Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1603334 > unrolled thread
| Started by | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| First post | 2017-03-17 15:00 +0100 |
| Last post | 2017-03-17 15:10 +0100 |
| Articles | 8 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH 00/13] platform/chrome: Add console debugfs, lpc and lightbar programming support Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:00 +0100
[PATCH 13/13] platform/chrome: cros_ec_lightbar - Avoid I2C xfer to EC during suspend Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:00 +0100
[PATCH 02/13] mfd: cros_ec: Add EC console read structures definitions Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:10 +0100
[PATCH 06/13] platform/chrome: cros_ec_lpc: Add support for mec1322 EC Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:10 +0100
Re: [PATCH 06/13] platform/chrome: cros_ec_lpc: Add support for mec1322 EC Lee Jones <lee.jones@linaro.org> - 2017-03-23 13:00 +0100
[PATCH 11/13] platform/chrome: cros_ec_lightbar - Control of suspend/resume lightbar sequence Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:10 +0100
[PATCH 03/13] mfd: cros_ec: add debugfs, console log file Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:10 +0100
[PATCH 04/13] mfd: cros_ec: Add support for dumping panic information Enric Balletbo i Serra <enric.balletbo@collabora.com> - 2017-03-17 15:10 +0100
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:00 +0100 |
| Subject | [PATCH 00/13] platform/chrome: Add console debugfs, lpc and lightbar programming support |
| Message-ID | <tm0A9-7ex-5@gated-at.bofh.it> |
Dear Olof, Benson,
We have some patches that stayed in the mailing list for long time, now that we
are in rc2 we're wondering if you can review the following patches and if it's ok include for the next 4.12 merge window.
As some patches depends on the other to apply cleanly I created a patch series with all includes to make easier the merge, so this series include the following patches
- https://lkml.org/lkml/2016/8/23/10
- https://lkml.org/lkml/2016/12/2/360
- https://lkml.org/lkml/2016/12/16/438
- https://lkml.org/lkml/2017/1/11/579
Basically what I did in this series is rebase on top of linux-next and add the acks received (basically the ones received by Lee Jones for the mfd parts) and also fix a small issue reported by Doug Anderson.
If you prefer to pick the patches from a git repository, the following
changes since commit a88dcd6742a2eedfc047b5513cda6b7351215bf0:
mfd: cros_ec: Add helper for event notifier.
are available in the git repository at:
https://git.collabora.com/cgit/linux.git upstream/chromeos/for-4.12
for you to fetch changes up to 02397bc8b49ba3fdaf2e6ee389a231590059c81c:
platform/chrome: cros_ec_lightbar - Avoid I2C xfer to EC during suspend
Many thanks for your help,
Enric
Archana Patni (1):
platform/chrome: cros_ec_lpc: Add power management ops
Eric Caruso (4):
mfd: cros_ec: add debugfs, console log file
platform/chrome: cros_ec_lightbar - Add lightbar program feature to
sysfs
platform/chrome: cros_ec_lightbar - Control of suspend/resume lightbar
sequence
platform/chrome: cros_ec_lightbar - Add userspace lightbar control bit
to EC
Gwendal Grignou (3):
mfd: cros_ec: Add helper for event notifier.
platform/chrome: cros_ec_lpc: Add support for GOOG004 ACPI device
platform/chrome: cros_ec_lpc: Add MKBP events support over ACPI
Jeffery Yu (1):
platform/chrome: cros_ec_lightbar - Avoid I2C xfer to EC during
suspend
Nicolas Boichat (2):
mfd: cros_ec: Add EC console read structures definitions
mfd: cros_ec: Add support for dumping panic information
Shawn Nematbakhsh (2):
platform/chrome: cros_ec_lpc: Add R/W helpers to LPC protocol variants
platform/chrome: cros_ec_lpc: Add support for mec1322 EC
drivers/platform/chrome/Kconfig | 14 +-
drivers/platform/chrome/Makefile | 7 +-
drivers/platform/chrome/cros_ec_debugfs.c | 401 +++++++++++++++++++++++++++++
drivers/platform/chrome/cros_ec_debugfs.h | 27 ++
drivers/platform/chrome/cros_ec_dev.c | 40 +++
drivers/platform/chrome/cros_ec_dev.h | 6 +
drivers/platform/chrome/cros_ec_lightbar.c | 197 +++++++++++++-
drivers/platform/chrome/cros_ec_lpc.c | 167 +++++++-----
drivers/platform/chrome/cros_ec_lpc_mec.c | 140 ++++++++++
drivers/platform/chrome/cros_ec_lpc_reg.c | 133 ++++++++++
drivers/platform/chrome/cros_ec_proto.c | 20 ++
include/linux/mfd/cros_ec.h | 14 +
include/linux/mfd/cros_ec_commands.h | 42 ++-
include/linux/mfd/cros_ec_lpc_mec.h | 90 +++++++
include/linux/mfd/cros_ec_lpc_reg.h | 61 +++++
15 files changed, 1286 insertions(+), 73 deletions(-)
create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
create mode 100644 drivers/platform/chrome/cros_ec_lpc_mec.c
create mode 100644 drivers/platform/chrome/cros_ec_lpc_reg.c
create mode 100644 include/linux/mfd/cros_ec_lpc_mec.h
create mode 100644 include/linux/mfd/cros_ec_lpc_reg.h
--
2.9.3
[toc] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:00 +0100 |
| Subject | [PATCH 13/13] platform/chrome: cros_ec_lightbar - Avoid I2C xfer to EC during suspend |
| Message-ID | <tm0Aa-7ex-25@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Jeffery Yu <jefferyy@nvidia.com>
A Mutex lock in cros_ec_cmd_xfer which may be held by frozen
Userspace thread during system suspending. So should not
call this routine in suspend thread.
Signed-off-by: Jeffery Yu <jefferyy@nvidia.com>
Signed-off-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
drivers/platform/chrome/cros_ec_dev.c | 12 ++++--------
drivers/platform/chrome/cros_ec_lightbar.c | 13 +++++++++----
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index abcbfea..ea2cbf4 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -450,8 +450,7 @@ static int ec_device_probe(struct platform_device *pdev)
cros_ec_sensors_register(ec);
/* Take control of the lightbar from the EC. */
- if (ec_has_lightbar(ec))
- lb_manual_suspend_ctrl(ec, 1);
+ lb_manual_suspend_ctrl(ec, 1);
return 0;
@@ -469,8 +468,7 @@ static int ec_device_remove(struct platform_device *pdev)
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
/* Let the EC take over the lightbar again. */
- if (ec_has_lightbar(ec))
- lb_manual_suspend_ctrl(ec, 0);
+ lb_manual_suspend_ctrl(ec, 0);
cros_ec_debugfs_remove(ec);
@@ -489,8 +487,7 @@ static int ec_device_suspend(struct device *dev)
{
struct cros_ec_dev *ec = dev_get_drvdata(dev);
- if (ec_has_lightbar(ec))
- lb_suspend(ec);
+ lb_suspend(ec);
return 0;
}
@@ -499,8 +496,7 @@ static int ec_device_resume(struct device *dev)
{
struct cros_ec_dev *ec = dev_get_drvdata(dev);
- if (ec_has_lightbar(ec))
- lb_resume(ec);
+ lb_resume(ec);
return 0;
}
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index e570c1e..fd2b047 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -43,6 +43,7 @@ static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
* If this is true, we won't do anything during suspend/resume.
*/
static bool userspace_control;
+static struct cros_ec_dev *ec_with_lightbar;
static ssize_t interval_msec_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -384,6 +385,9 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
struct cros_ec_command *msg;
int ret;
+ if (ec != ec_with_lightbar)
+ return 0;
+
msg = alloc_lightbar_cmd_msg(ec);
if (!msg)
return -ENOMEM;
@@ -413,7 +417,7 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
int lb_suspend(struct cros_ec_dev *ec)
{
- if (userspace_control)
+ if (userspace_control || ec != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
@@ -421,7 +425,7 @@ int lb_suspend(struct cros_ec_dev *ec)
int lb_resume(struct cros_ec_dev *ec)
{
- if (userspace_control)
+ if (userspace_control || ec != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
@@ -606,9 +610,10 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
return 0;
/* Only instantiate this stuff if the EC has a lightbar */
- if (ec_has_lightbar(ec))
+ if (ec_has_lightbar(ec)) {
+ ec_with_lightbar = ec;
return a->mode;
-
+ }
return 0;
}
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:10 +0100 |
| Subject | [PATCH 02/13] mfd: cros_ec: Add EC console read structures definitions |
| Message-ID | <tm0JQ-7zo-3@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Nicolas Boichat <drinkcat@chromium.org>
ec_params_console_read_v1 is used to capture EC logs from kernel,
and ec_params_get_cmd_versions_v1 is used to probe whether EC
supports that command.
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index f1ef638..3497e1a 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
uint8_t cmd; /* Command to check */
} __packed;
+struct ec_params_get_cmd_versions_v1 {
+ uint16_t cmd; /* Command to check */
+} __packed;
+
struct ec_response_get_cmd_versions {
/*
* Mask of supported versions; use EC_VER_MASK() to compare with a
@@ -2281,13 +2285,28 @@ struct ec_params_charge_control {
#define EC_CMD_CONSOLE_SNAPSHOT 0x97
/*
- * Read next chunk of data from saved snapshot.
+ * Read data from the saved snapshot. If the subcmd parameter is
+ * CONSOLE_READ_NEXT, this will return data starting from the beginning of
+ * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
+ * end of the previous snapshot.
+ *
+ * The params are only looked at in version >= 1 of this command. Prior
+ * versions will just default to CONSOLE_READ_NEXT behavior.
*
* Response is null-terminated string. Empty string, if there is no more
* remaining output.
*/
#define EC_CMD_CONSOLE_READ 0x98
+enum ec_console_read_subcmd {
+ CONSOLE_READ_NEXT = 0,
+ CONSOLE_READ_RECENT
+};
+
+struct ec_params_console_read_v1 {
+ uint8_t subcmd; /* enum ec_console_read_subcmd */
+} __packed;
+
/*****************************************************************************/
/*
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:10 +0100 |
| Subject | [PATCH 06/13] platform/chrome: cros_ec_lpc: Add support for mec1322 EC |
| Message-ID | <tm0JQ-7zo-7@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Shawn Nematbakhsh <shawnn@chromium.org>
This adds support for the ChromeOS LPC Microchip Embedded Controller
(mec1322) variant.
mec1322 accesses I/O region [800h, 9ffh] through embedded memory
interface (EMI) rather than LPC.
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
---
Changelog:
- v2:
-Add a few lines in Kconfig description
-Fixed coding style issues
-Updated copyright to year 2016
drivers/platform/chrome/Kconfig | 12 +++
drivers/platform/chrome/Makefile | 1 +
drivers/platform/chrome/cros_ec_lpc.c | 5 ++
drivers/platform/chrome/cros_ec_lpc_mec.c | 140 ++++++++++++++++++++++++++++++
drivers/platform/chrome/cros_ec_lpc_reg.c | 69 +++++++++++++++
include/linux/mfd/cros_ec_lpc_mec.h | 90 +++++++++++++++++++
include/linux/mfd/cros_ec_lpc_reg.h | 14 +++
7 files changed, 331 insertions(+)
create mode 100644 drivers/platform/chrome/cros_ec_lpc_mec.c
create mode 100644 include/linux/mfd/cros_ec_lpc_mec.h
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 76bdae1..6d80fb5 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -59,6 +59,18 @@ config CROS_EC_LPC
To compile this driver as a module, choose M here: the
module will be called cros_ec_lpc.
+config CROS_EC_LPC_MEC
+ bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant"
+ depends on CROS_EC_LPC
+ default n
+ help
+ If you say Y here, a variant LPC protocol for the Microchip EC
+ will be used. Note that this variant is not backward compatible
+ with non-Microchip ECs.
+
+ If you have a ChromeOS Embedded Controller Microchip EC variant
+ choose Y here.
+
config CROS_EC_PROTO
bool
help
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 61182fd..66c345c 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -6,6 +6,7 @@ cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \
cros_ec_debugfs.o
obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o
+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
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 6a782a6..bc2dc62 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -346,10 +346,13 @@ static int __init cros_ec_lpc_init(void)
return -ENODEV;
}
+ cros_ec_lpc_reg_init();
+
/* Register the driver */
ret = platform_driver_register(&cros_ec_lpc_driver);
if (ret) {
pr_err(DRV_NAME ": can't register driver: %d\n", ret);
+ cros_ec_lpc_reg_destroy();
return ret;
}
@@ -358,6 +361,7 @@ static int __init cros_ec_lpc_init(void)
if (ret) {
pr_err(DRV_NAME ": can't register device: %d\n", ret);
platform_driver_unregister(&cros_ec_lpc_driver);
+ cros_ec_lpc_reg_destroy();
return ret;
}
@@ -368,6 +372,7 @@ static void __exit cros_ec_lpc_exit(void)
{
platform_device_unregister(&cros_ec_lpc_device);
platform_driver_unregister(&cros_ec_lpc_driver);
+ cros_ec_lpc_reg_destroy();
}
module_init(cros_ec_lpc_init);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
new file mode 100644
index 0000000..2eda2c2
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
@@ -0,0 +1,140 @@
+/*
+ * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
+ *
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * This driver uses the Chrome OS EC byte-level message-based protocol for
+ * communicating the keyboard state (which keys are pressed) from a keyboard EC
+ * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
+ * but everything else (including deghosting) is done here. The main
+ * motivation for this is to keep the EC firmware as simple as possible, since
+ * it cannot be easily upgraded and EC flash/IRAM space is relatively
+ * expensive.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/mfd/cros_ec_lpc_mec.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/*
+ * This mutex must be held while accessing the EMI unit. We can't rely on the
+ * EC mutex because memmap data may be accessed without it being held.
+ */
+static struct mutex io_mutex;
+
+/*
+ * cros_ec_lpc_mec_emi_write_address
+ *
+ * Initialize EMI read / write at a given address.
+ *
+ * @addr: Starting read / write address
+ * @access_type: Type of access, typically 32-bit auto-increment
+ */
+static void cros_ec_lpc_mec_emi_write_address(u16 addr,
+ enum cros_ec_lpc_mec_emi_access_mode access_type)
+{
+ /* Address relative to start of EMI range */
+ addr -= MEC_EMI_RANGE_START;
+ outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0);
+ outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1);
+}
+
+/*
+ * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
+ *
+ * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
+ * @offset: Base read / write address
+ * @length: Number of bytes to read / write
+ * @buf: Destination / source buffer
+ *
+ * @return 8-bit checksum of all bytes read / written
+ */
+u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
+ unsigned int offset, unsigned int length,
+ u8 *buf)
+{
+ int i = 0;
+ int io_addr;
+ u8 sum = 0;
+ enum cros_ec_lpc_mec_emi_access_mode access, new_access;
+
+ /*
+ * Long access cannot be used on misaligned data since reading B0 loads
+ * the data register and writing B3 flushes.
+ */
+ if (offset & 0x3 || length < 4)
+ access = ACCESS_TYPE_BYTE;
+ else
+ access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
+
+ mutex_lock(&io_mutex);
+
+ /* Initialize I/O at desired address */
+ cros_ec_lpc_mec_emi_write_address(offset, access);
+
+ /* Skip bytes in case of misaligned offset */
+ io_addr = MEC_EMI_EC_DATA_B0 + (offset & 0x3);
+ while (i < length) {
+ while (io_addr <= MEC_EMI_EC_DATA_B3) {
+ if (io_type == MEC_IO_READ)
+ buf[i] = inb(io_addr++);
+ else
+ outb(buf[i], io_addr++);
+
+ sum += buf[i++];
+ offset++;
+
+ /* Extra bounds check in case of misaligned length */
+ if (i == length)
+ goto done;
+ }
+
+ /*
+ * Use long auto-increment access except for misaligned write,
+ * since writing B3 triggers the flush.
+ */
+ if (length - i < 4 && io_type == MEC_IO_WRITE)
+ new_access = ACCESS_TYPE_BYTE;
+ else
+ new_access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
+
+ if (new_access != access ||
+ access != ACCESS_TYPE_LONG_AUTO_INCREMENT) {
+ access = new_access;
+ cros_ec_lpc_mec_emi_write_address(offset, access);
+ }
+
+ /* Access [B0, B3] on each loop pass */
+ io_addr = MEC_EMI_EC_DATA_B0;
+ }
+
+done:
+ mutex_unlock(&io_mutex);
+
+ return sum;
+}
+EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec);
+
+void cros_ec_lpc_mec_init(void)
+{
+ mutex_init(&io_mutex);
+}
+EXPORT_SYMBOL(cros_ec_lpc_mec_init);
+
+void cros_ec_lpc_mec_destroy(void)
+{
+ mutex_destroy(&io_mutex);
+}
+EXPORT_SYMBOL(cros_ec_lpc_mec_destroy);
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
index 03c9781..dcc7a3e 100644
--- a/drivers/platform/chrome/cros_ec_lpc_reg.c
+++ b/drivers/platform/chrome/cros_ec_lpc_reg.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
+#include <linux/mfd/cros_ec_lpc_mec.h>
static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
{
@@ -53,12 +54,80 @@ static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
return sum;
}
+#ifdef CONFIG_CROS_EC_LPC_MEC
+
u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
{
+ if (length == 0)
+ return 0;
+
+ /* Access desired range through EMI interface */
+ if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
+ /* Ensure we don't straddle EMI region */
+ if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
+ return 0;
+
+ return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length,
+ dest);
+ }
+
+ if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
+ offset < MEC_EMI_RANGE_START))
+ return 0;
+
return lpc_read_bytes(offset, length, dest);
}
u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
{
+ if (length == 0)
+ return 0;
+
+ /* Access desired range through EMI interface */
+ if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
+ /* Ensure we don't straddle EMI region */
+ if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
+ return 0;
+
+ return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length,
+ msg);
+ }
+
+ if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
+ offset < MEC_EMI_RANGE_START))
+ return 0;
+
return lpc_write_bytes(offset, length, msg);
}
+
+void cros_ec_lpc_reg_init(void)
+{
+ cros_ec_lpc_mec_init();
+}
+
+void cros_ec_lpc_reg_destroy(void)
+{
+ cros_ec_lpc_mec_destroy();
+}
+
+#else /* CONFIG_CROS_EC_LPC_MEC */
+
+u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
+{
+ return lpc_read_bytes(offset, length, dest);
+}
+
+u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
+{
+ return lpc_write_bytes(offset, length, msg);
+}
+
+void cros_ec_lpc_reg_init(void)
+{
+}
+
+void cros_ec_lpc_reg_destroy(void)
+{
+}
+
+#endif /* CONFIG_CROS_EC_LPC_MEC */
diff --git a/include/linux/mfd/cros_ec_lpc_mec.h b/include/linux/mfd/cros_ec_lpc_mec.h
new file mode 100644
index 0000000..176496d
--- /dev/null
+++ b/include/linux/mfd/cros_ec_lpc_mec.h
@@ -0,0 +1,90 @@
+/*
+ * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
+ *
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * This driver uses the Chrome OS EC byte-level message-based protocol for
+ * communicating the keyboard state (which keys are pressed) from a keyboard EC
+ * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
+ * but everything else (including deghosting) is done here. The main
+ * motivation for this is to keep the EC firmware as simple as possible, since
+ * it cannot be easily upgraded and EC flash/IRAM space is relatively
+ * expensive.
+ */
+
+#ifndef __LINUX_MFD_CROS_EC_MEC_H
+#define __LINUX_MFD_CROS_EC_MEC_H
+
+#include <linux/mfd/cros_ec_commands.h>
+
+enum cros_ec_lpc_mec_emi_access_mode {
+ /* 8-bit access */
+ ACCESS_TYPE_BYTE = 0x0,
+ /* 16-bit access */
+ ACCESS_TYPE_WORD = 0x1,
+ /* 32-bit access */
+ ACCESS_TYPE_LONG = 0x2,
+ /*
+ * 32-bit access, read or write of MEC_EMI_EC_DATA_B3 causes the
+ * EC data register to be incremented.
+ */
+ ACCESS_TYPE_LONG_AUTO_INCREMENT = 0x3,
+};
+
+enum cros_ec_lpc_mec_io_type {
+ MEC_IO_READ,
+ MEC_IO_WRITE,
+};
+
+/* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
+#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
+#define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
+
+/* EMI registers are relative to base */
+#define MEC_EMI_BASE 0x800
+#define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0)
+#define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1)
+#define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2)
+#define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3)
+#define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4)
+#define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5)
+#define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6)
+#define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7)
+
+/*
+ * cros_ec_lpc_mec_init
+ *
+ * Initialize MEC I/O.
+ */
+void cros_ec_lpc_mec_init(void);
+
+/*
+ * cros_ec_lpc_mec_destroy
+ *
+ * Cleanup MEC I/O.
+ */
+void cros_ec_lpc_mec_destroy(void);
+
+/**
+ * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
+ *
+ * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
+ * @offset: Base read / write address
+ * @length: Number of bytes to read / write
+ * @buf: Destination / source buffer
+ *
+ * @return 8-bit checksum of all bytes read / written
+ */
+u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
+ unsigned int offset, unsigned int length, u8 *buf);
+
+#endif /* __LINUX_MFD_CROS_EC_MEC_H */
diff --git a/include/linux/mfd/cros_ec_lpc_reg.h b/include/linux/mfd/cros_ec_lpc_reg.h
index 4089bd5..5560bef 100644
--- a/include/linux/mfd/cros_ec_lpc_reg.h
+++ b/include/linux/mfd/cros_ec_lpc_reg.h
@@ -44,4 +44,18 @@ u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest);
*/
u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg);
+/**
+ * cros_ec_lpc_reg_init
+ *
+ * Initialize register I/O.
+ */
+void cros_ec_lpc_reg_init(void);
+
+/**
+ * cros_ec_lpc_reg_destroy
+ *
+ * Cleanup reg I/O.
+ */
+void cros_ec_lpc_reg_destroy(void);
+
#endif /* __LINUX_MFD_CROS_EC_REG_H */
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Lee Jones <lee.jones@linaro.org> |
|---|---|
| Date | 2017-03-23 13:00 +0100 |
| Subject | Re: [PATCH 06/13] platform/chrome: cros_ec_lpc: Add support for mec1322 EC |
| Message-ID | <to9zj-1HJ-3@gated-at.bofh.it> |
| In reply to | #1603340 |
On Fri, 17 Mar 2017, Enric Balletbo i Serra wrote:
> From: Shawn Nematbakhsh <shawnn@chromium.org>
>
> This adds support for the ChromeOS LPC Microchip Embedded Controller
> (mec1322) variant.
>
> mec1322 accesses I/O region [800h, 9ffh] through embedded memory
> interface (EMI) rather than LPC.
>
> Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> ---
> Changelog:
> - v2:
> -Add a few lines in Kconfig description
> -Fixed coding style issues
> -Updated copyright to year 2016
>
> drivers/platform/chrome/Kconfig | 12 +++
> drivers/platform/chrome/Makefile | 1 +
> drivers/platform/chrome/cros_ec_lpc.c | 5 ++
> drivers/platform/chrome/cros_ec_lpc_mec.c | 140 ++++++++++++++++++++++++++++++
> drivers/platform/chrome/cros_ec_lpc_reg.c | 69 +++++++++++++++
> include/linux/mfd/cros_ec_lpc_mec.h | 90 +++++++++++++++++++
> include/linux/mfd/cros_ec_lpc_reg.h | 14 +++
Acked-by: Lee Jones <lee.jones@linaro.org>
> 7 files changed, 331 insertions(+)
> create mode 100644 drivers/platform/chrome/cros_ec_lpc_mec.c
> create mode 100644 include/linux/mfd/cros_ec_lpc_mec.h
>
> diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
> index 76bdae1..6d80fb5 100644
> --- a/drivers/platform/chrome/Kconfig
> +++ b/drivers/platform/chrome/Kconfig
> @@ -59,6 +59,18 @@ config CROS_EC_LPC
> To compile this driver as a module, choose M here: the
> module will be called cros_ec_lpc.
>
> +config CROS_EC_LPC_MEC
> + bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant"
> + depends on CROS_EC_LPC
> + default n
> + help
> + If you say Y here, a variant LPC protocol for the Microchip EC
> + will be used. Note that this variant is not backward compatible
> + with non-Microchip ECs.
> +
> + If you have a ChromeOS Embedded Controller Microchip EC variant
> + choose Y here.
> +
> config CROS_EC_PROTO
> bool
> help
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index 61182fd..66c345c 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -6,6 +6,7 @@ cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \
> cros_ec_debugfs.o
> obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
> cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o
> +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
> diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
> index 6a782a6..bc2dc62 100644
> --- a/drivers/platform/chrome/cros_ec_lpc.c
> +++ b/drivers/platform/chrome/cros_ec_lpc.c
> @@ -346,10 +346,13 @@ static int __init cros_ec_lpc_init(void)
> return -ENODEV;
> }
>
> + cros_ec_lpc_reg_init();
> +
> /* Register the driver */
> ret = platform_driver_register(&cros_ec_lpc_driver);
> if (ret) {
> pr_err(DRV_NAME ": can't register driver: %d\n", ret);
> + cros_ec_lpc_reg_destroy();
> return ret;
> }
>
> @@ -358,6 +361,7 @@ static int __init cros_ec_lpc_init(void)
> if (ret) {
> pr_err(DRV_NAME ": can't register device: %d\n", ret);
> platform_driver_unregister(&cros_ec_lpc_driver);
> + cros_ec_lpc_reg_destroy();
> return ret;
> }
>
> @@ -368,6 +372,7 @@ static void __exit cros_ec_lpc_exit(void)
> {
> platform_device_unregister(&cros_ec_lpc_device);
> platform_driver_unregister(&cros_ec_lpc_driver);
> + cros_ec_lpc_reg_destroy();
> }
>
> module_init(cros_ec_lpc_init);
> diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
> new file mode 100644
> index 0000000..2eda2c2
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
> @@ -0,0 +1,140 @@
> +/*
> + * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
> + *
> + * Copyright (C) 2016 Google, Inc
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * This driver uses the Chrome OS EC byte-level message-based protocol for
> + * communicating the keyboard state (which keys are pressed) from a keyboard EC
> + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
> + * but everything else (including deghosting) is done here. The main
> + * motivation for this is to keep the EC firmware as simple as possible, since
> + * it cannot be easily upgraded and EC flash/IRAM space is relatively
> + * expensive.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/mfd/cros_ec_commands.h>
> +#include <linux/mfd/cros_ec_lpc_mec.h>
> +#include <linux/mutex.h>
> +#include <linux/types.h>
> +
> +/*
> + * This mutex must be held while accessing the EMI unit. We can't rely on the
> + * EC mutex because memmap data may be accessed without it being held.
> + */
> +static struct mutex io_mutex;
> +
> +/*
> + * cros_ec_lpc_mec_emi_write_address
> + *
> + * Initialize EMI read / write at a given address.
> + *
> + * @addr: Starting read / write address
> + * @access_type: Type of access, typically 32-bit auto-increment
> + */
> +static void cros_ec_lpc_mec_emi_write_address(u16 addr,
> + enum cros_ec_lpc_mec_emi_access_mode access_type)
> +{
> + /* Address relative to start of EMI range */
> + addr -= MEC_EMI_RANGE_START;
> + outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0);
> + outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1);
> +}
> +
> +/*
> + * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
> + *
> + * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
> + * @offset: Base read / write address
> + * @length: Number of bytes to read / write
> + * @buf: Destination / source buffer
> + *
> + * @return 8-bit checksum of all bytes read / written
> + */
> +u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
> + unsigned int offset, unsigned int length,
> + u8 *buf)
> +{
> + int i = 0;
> + int io_addr;
> + u8 sum = 0;
> + enum cros_ec_lpc_mec_emi_access_mode access, new_access;
> +
> + /*
> + * Long access cannot be used on misaligned data since reading B0 loads
> + * the data register and writing B3 flushes.
> + */
> + if (offset & 0x3 || length < 4)
> + access = ACCESS_TYPE_BYTE;
> + else
> + access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
> +
> + mutex_lock(&io_mutex);
> +
> + /* Initialize I/O at desired address */
> + cros_ec_lpc_mec_emi_write_address(offset, access);
> +
> + /* Skip bytes in case of misaligned offset */
> + io_addr = MEC_EMI_EC_DATA_B0 + (offset & 0x3);
> + while (i < length) {
> + while (io_addr <= MEC_EMI_EC_DATA_B3) {
> + if (io_type == MEC_IO_READ)
> + buf[i] = inb(io_addr++);
> + else
> + outb(buf[i], io_addr++);
> +
> + sum += buf[i++];
> + offset++;
> +
> + /* Extra bounds check in case of misaligned length */
> + if (i == length)
> + goto done;
> + }
> +
> + /*
> + * Use long auto-increment access except for misaligned write,
> + * since writing B3 triggers the flush.
> + */
> + if (length - i < 4 && io_type == MEC_IO_WRITE)
> + new_access = ACCESS_TYPE_BYTE;
> + else
> + new_access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
> +
> + if (new_access != access ||
> + access != ACCESS_TYPE_LONG_AUTO_INCREMENT) {
> + access = new_access;
> + cros_ec_lpc_mec_emi_write_address(offset, access);
> + }
> +
> + /* Access [B0, B3] on each loop pass */
> + io_addr = MEC_EMI_EC_DATA_B0;
> + }
> +
> +done:
> + mutex_unlock(&io_mutex);
> +
> + return sum;
> +}
> +EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec);
> +
> +void cros_ec_lpc_mec_init(void)
> +{
> + mutex_init(&io_mutex);
> +}
> +EXPORT_SYMBOL(cros_ec_lpc_mec_init);
> +
> +void cros_ec_lpc_mec_destroy(void)
> +{
> + mutex_destroy(&io_mutex);
> +}
> +EXPORT_SYMBOL(cros_ec_lpc_mec_destroy);
> diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
> index 03c9781..dcc7a3e 100644
> --- a/drivers/platform/chrome/cros_ec_lpc_reg.c
> +++ b/drivers/platform/chrome/cros_ec_lpc_reg.c
> @@ -24,6 +24,7 @@
> #include <linux/io.h>
> #include <linux/mfd/cros_ec.h>
> #include <linux/mfd/cros_ec_commands.h>
> +#include <linux/mfd/cros_ec_lpc_mec.h>
>
> static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
> {
> @@ -53,12 +54,80 @@ static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
> return sum;
> }
>
> +#ifdef CONFIG_CROS_EC_LPC_MEC
> +
> u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
> {
> + if (length == 0)
> + return 0;
> +
> + /* Access desired range through EMI interface */
> + if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
> + /* Ensure we don't straddle EMI region */
> + if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
> + return 0;
> +
> + return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length,
> + dest);
> + }
> +
> + if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
> + offset < MEC_EMI_RANGE_START))
> + return 0;
> +
> return lpc_read_bytes(offset, length, dest);
> }
>
> u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
> {
> + if (length == 0)
> + return 0;
> +
> + /* Access desired range through EMI interface */
> + if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
> + /* Ensure we don't straddle EMI region */
> + if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
> + return 0;
> +
> + return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length,
> + msg);
> + }
> +
> + if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
> + offset < MEC_EMI_RANGE_START))
> + return 0;
> +
> return lpc_write_bytes(offset, length, msg);
> }
> +
> +void cros_ec_lpc_reg_init(void)
> +{
> + cros_ec_lpc_mec_init();
> +}
> +
> +void cros_ec_lpc_reg_destroy(void)
> +{
> + cros_ec_lpc_mec_destroy();
> +}
> +
> +#else /* CONFIG_CROS_EC_LPC_MEC */
> +
> +u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
> +{
> + return lpc_read_bytes(offset, length, dest);
> +}
> +
> +u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
> +{
> + return lpc_write_bytes(offset, length, msg);
> +}
> +
> +void cros_ec_lpc_reg_init(void)
> +{
> +}
> +
> +void cros_ec_lpc_reg_destroy(void)
> +{
> +}
> +
> +#endif /* CONFIG_CROS_EC_LPC_MEC */
> diff --git a/include/linux/mfd/cros_ec_lpc_mec.h b/include/linux/mfd/cros_ec_lpc_mec.h
> new file mode 100644
> index 0000000..176496d
> --- /dev/null
> +++ b/include/linux/mfd/cros_ec_lpc_mec.h
> @@ -0,0 +1,90 @@
> +/*
> + * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
> + *
> + * Copyright (C) 2016 Google, Inc
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * This driver uses the Chrome OS EC byte-level message-based protocol for
> + * communicating the keyboard state (which keys are pressed) from a keyboard EC
> + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
> + * but everything else (including deghosting) is done here. The main
> + * motivation for this is to keep the EC firmware as simple as possible, since
> + * it cannot be easily upgraded and EC flash/IRAM space is relatively
> + * expensive.
> + */
> +
> +#ifndef __LINUX_MFD_CROS_EC_MEC_H
> +#define __LINUX_MFD_CROS_EC_MEC_H
> +
> +#include <linux/mfd/cros_ec_commands.h>
> +
> +enum cros_ec_lpc_mec_emi_access_mode {
> + /* 8-bit access */
> + ACCESS_TYPE_BYTE = 0x0,
> + /* 16-bit access */
> + ACCESS_TYPE_WORD = 0x1,
> + /* 32-bit access */
> + ACCESS_TYPE_LONG = 0x2,
> + /*
> + * 32-bit access, read or write of MEC_EMI_EC_DATA_B3 causes the
> + * EC data register to be incremented.
> + */
> + ACCESS_TYPE_LONG_AUTO_INCREMENT = 0x3,
> +};
> +
> +enum cros_ec_lpc_mec_io_type {
> + MEC_IO_READ,
> + MEC_IO_WRITE,
> +};
> +
> +/* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
> +#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
> +#define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
> +
> +/* EMI registers are relative to base */
> +#define MEC_EMI_BASE 0x800
> +#define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0)
> +#define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1)
> +#define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2)
> +#define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3)
> +#define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4)
> +#define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5)
> +#define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6)
> +#define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7)
> +
> +/*
> + * cros_ec_lpc_mec_init
> + *
> + * Initialize MEC I/O.
> + */
> +void cros_ec_lpc_mec_init(void);
> +
> +/*
> + * cros_ec_lpc_mec_destroy
> + *
> + * Cleanup MEC I/O.
> + */
> +void cros_ec_lpc_mec_destroy(void);
> +
> +/**
> + * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
> + *
> + * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
> + * @offset: Base read / write address
> + * @length: Number of bytes to read / write
> + * @buf: Destination / source buffer
> + *
> + * @return 8-bit checksum of all bytes read / written
> + */
> +u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
> + unsigned int offset, unsigned int length, u8 *buf);
> +
> +#endif /* __LINUX_MFD_CROS_EC_MEC_H */
> diff --git a/include/linux/mfd/cros_ec_lpc_reg.h b/include/linux/mfd/cros_ec_lpc_reg.h
> index 4089bd5..5560bef 100644
> --- a/include/linux/mfd/cros_ec_lpc_reg.h
> +++ b/include/linux/mfd/cros_ec_lpc_reg.h
> @@ -44,4 +44,18 @@ u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest);
> */
> u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg);
>
> +/**
> + * cros_ec_lpc_reg_init
> + *
> + * Initialize register I/O.
> + */
> +void cros_ec_lpc_reg_init(void);
> +
> +/**
> + * cros_ec_lpc_reg_destroy
> + *
> + * Cleanup reg I/O.
> + */
> +void cros_ec_lpc_reg_destroy(void);
> +
> #endif /* __LINUX_MFD_CROS_EC_REG_H */
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
[toc] | [prev] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:10 +0100 |
| Subject | [PATCH 11/13] platform/chrome: cros_ec_lightbar - Control of suspend/resume lightbar sequence |
| Message-ID | <tm0JQ-7zo-17@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Eric Caruso <ejcaruso@chromium.org>
Don't let EC control suspend/resume sequence. If the EC controls the
lightbar and sets the sequence when it notices the chipset transitioning
between states, we can't make exceptions for cases where we don't want
to activate the lightbar. Instead, let's move the suspend/resume
notifications into the kernel so we can selectively play the sequences.
Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
Signed-off-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
drivers/platform/chrome/cros_ec_dev.c | 37 +++++++++++++
drivers/platform/chrome/cros_ec_dev.h | 6 +++
drivers/platform/chrome/cros_ec_lightbar.c | 85 ++++++++++++++++++++++++++++--
include/linux/mfd/cros_ec_commands.h | 11 +++-
4 files changed, 134 insertions(+), 5 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index 518210b..abcbfea 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -21,6 +21,7 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -448,6 +449,10 @@ static int ec_device_probe(struct platform_device *pdev)
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
cros_ec_sensors_register(ec);
+ /* Take control of the lightbar from the EC. */
+ if (ec_has_lightbar(ec))
+ lb_manual_suspend_ctrl(ec, 1);
+
return 0;
dev_reg_failed:
@@ -463,6 +468,10 @@ static int ec_device_remove(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
+ /* Let the EC take over the lightbar again. */
+ if (ec_has_lightbar(ec))
+ lb_manual_suspend_ctrl(ec, 0);
+
cros_ec_debugfs_remove(ec);
cdev_del(&ec->cdev);
@@ -476,9 +485,37 @@ static const struct platform_device_id cros_ec_id[] = {
};
MODULE_DEVICE_TABLE(platform, cros_ec_id);
+static int ec_device_suspend(struct device *dev)
+{
+ struct cros_ec_dev *ec = dev_get_drvdata(dev);
+
+ if (ec_has_lightbar(ec))
+ lb_suspend(ec);
+
+ return 0;
+}
+
+static int ec_device_resume(struct device *dev)
+{
+ struct cros_ec_dev *ec = dev_get_drvdata(dev);
+
+ if (ec_has_lightbar(ec))
+ lb_resume(ec);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cros_ec_dev_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ec_device_suspend,
+ .resume = ec_device_resume,
+#endif
+};
+
static struct platform_driver cros_ec_dev_driver = {
.driver = {
.name = "cros-ec-ctl",
+ .pm = &cros_ec_dev_pm_ops,
},
.probe = ec_device_probe,
.remove = ec_device_remove,
diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h
index bfd2c84..45e9453 100644
--- a/drivers/platform/chrome/cros_ec_dev.h
+++ b/drivers/platform/chrome/cros_ec_dev.h
@@ -43,4 +43,10 @@ struct cros_ec_readmem {
#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command)
#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem)
+/* Lightbar utilities */
+extern bool ec_has_lightbar(struct cros_ec_dev *ec);
+extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable);
+extern int lb_suspend(struct cros_ec_dev *ec);
+extern int lb_resume(struct cros_ec_dev *ec);
+
#endif /* _CROS_EC_DEV_H_ */
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 2667505..4df379d 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -341,6 +341,80 @@ static ssize_t sequence_show(struct device *dev,
return ret;
}
+static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
+{
+ struct ec_params_lightbar *param;
+ struct cros_ec_command *msg;
+ int ret;
+
+ msg = alloc_lightbar_cmd_msg(ec);
+ if (!msg)
+ return -ENOMEM;
+
+ param = (struct ec_params_lightbar *)msg->data;
+ param->cmd = cmd;
+
+ ret = lb_throttle();
+ if (ret)
+ goto error;
+
+ ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+ if (ret < 0)
+ goto error;
+ if (msg->result != EC_RES_SUCCESS) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = 0;
+error:
+ kfree(msg);
+
+ return ret;
+}
+
+int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
+{
+ struct ec_params_lightbar *param;
+ struct cros_ec_command *msg;
+ int ret;
+
+ msg = alloc_lightbar_cmd_msg(ec);
+ if (!msg)
+ return -ENOMEM;
+
+ param = (struct ec_params_lightbar *)msg->data;
+
+ param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL;
+ param->manual_suspend_ctrl.enable = enable;
+
+ ret = lb_throttle();
+ if (ret)
+ goto error;
+
+ ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+ if (ret < 0)
+ goto error;
+ if (msg->result != EC_RES_SUCCESS) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = 0;
+error:
+ kfree(msg);
+
+ return ret;
+}
+
+int lb_suspend(struct cros_ec_dev *ec)
+{
+ return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
+}
+
+int lb_resume(struct cros_ec_dev *ec)
+{
+ return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
+}
+
static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -473,6 +547,11 @@ static struct attribute *__lb_cmds_attrs[] = {
NULL,
};
+bool ec_has_lightbar(struct cros_ec_dev *ec)
+{
+ return !!get_lightbar_version(ec, NULL, NULL);
+}
+
static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
struct attribute *a, int n)
{
@@ -489,10 +568,10 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
return 0;
/* Only instantiate this stuff if the EC has a lightbar */
- if (get_lightbar_version(ec, NULL, NULL))
+ if (ec_has_lightbar(ec))
return a->mode;
- else
- return 0;
+
+ return 0;
}
struct attribute_group cros_ec_lightbar_attr_group = {
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index bae2bcc..84e1abb 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -1175,7 +1175,7 @@ struct ec_params_lightbar {
struct {
/* no args */
} dump, off, on, init, get_seq, get_params_v0, get_params_v1,
- version, get_brightness, get_demo;
+ version, get_brightness, get_demo, suspend, resume;
struct {
uint8_t num;
@@ -1193,6 +1193,10 @@ struct ec_params_lightbar {
uint8_t led;
} get_rgb;
+ struct {
+ uint8_t enable;
+ } manual_suspend_ctrl;
+
struct lightbar_params_v0 set_params_v0;
struct lightbar_params_v1 set_params_v1;
struct lightbar_program set_program;
@@ -1229,7 +1233,7 @@ struct ec_response_lightbar {
/* no return params */
} off, on, init, set_brightness, seq, reg, set_rgb,
demo, set_params_v0, set_params_v1,
- set_program;
+ set_program, manual_suspend_ctrl, suspend, resume;
};
} __packed;
@@ -1254,6 +1258,9 @@ enum lightbar_command {
LIGHTBAR_CMD_GET_PARAMS_V1 = 16,
LIGHTBAR_CMD_SET_PARAMS_V1 = 17,
LIGHTBAR_CMD_SET_PROGRAM = 18,
+ LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL = 19,
+ LIGHTBAR_CMD_SUSPEND = 20,
+ LIGHTBAR_CMD_RESUME = 21,
LIGHTBAR_NUM_CMDS
};
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:10 +0100 |
| Subject | [PATCH 03/13] mfd: cros_ec: add debugfs, console log file |
| Message-ID | <tm0JQ-7zo-15@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Eric Caruso <ejcaruso@chromium.org>
If the EC supports the new CONSOLE_READ command type, then we
place a console_log file in debugfs for that EC device which allows
us to grab EC logs. The kernel will poll every 10 seconds for the
log and keep its own buffer, but userspace should grab this and
write it out to some logs which actually get rotated.
Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
Changes since last version:
- Fix some sizeof() calls that are wrong. They need "*" (reported by Doug Anderson)
drivers/platform/chrome/Makefile | 3 +-
drivers/platform/chrome/cros_ec_debugfs.c | 347 ++++++++++++++++++++++++++++++
drivers/platform/chrome/cros_ec_debugfs.h | 27 +++
drivers/platform/chrome/cros_ec_dev.c | 7 +
include/linux/mfd/cros_ec.h | 4 +
5 files changed, 387 insertions(+), 1 deletion(-)
create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 4f34627..3870afe 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -2,7 +2,8 @@
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \
- cros_ec_lightbar.o cros_ec_vbc.o
+ cros_ec_lightbar.o cros_ec_vbc.o \
+ cros_ec_debugfs.o
obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
new file mode 100644
index 0000000..f8195bb
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -0,0 +1,347 @@
+/*
+ * cros_ec_debugfs - debug logs for Chrome OS EC
+ *
+ * Copyright 2015 Google, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include "cros_ec_dev.h"
+#include "cros_ec_debugfs.h"
+
+#define LOG_SHIFT 14
+#define LOG_SIZE (1 << LOG_SHIFT)
+#define LOG_POLL_SEC 10
+
+#define CIRC_ADD(idx, size, value) (((idx) + (value)) & ((size) - 1))
+
+/* struct cros_ec_debugfs - ChromeOS EC debugging information
+ *
+ * @ec: EC device this debugfs information belongs to
+ * @dir: dentry for debugfs files
+ * @log_buffer: circular buffer for console log information
+ * @read_msg: preallocated EC command and buffer to read console log
+ * @log_mutex: mutex to protect circular buffer
+ * @log_wq: waitqueue for log readers
+ * @log_poll_work: recurring task to poll EC for new console log data
+ */
+struct cros_ec_debugfs {
+ struct cros_ec_dev *ec;
+ struct dentry *dir;
+ struct circ_buf log_buffer;
+ struct cros_ec_command *read_msg;
+ struct mutex log_mutex;
+ wait_queue_head_t log_wq;
+ struct delayed_work log_poll_work;
+};
+
+/*
+ * We need to make sure that the EC log buffer on the UART is large enough,
+ * so that it is unlikely enough to overlow within LOG_POLL_SEC.
+ */
+static void cros_ec_console_log_work(struct work_struct *__work)
+{
+ struct cros_ec_debugfs *debug_info =
+ container_of(to_delayed_work(__work),
+ struct cros_ec_debugfs,
+ log_poll_work);
+ struct cros_ec_dev *ec = debug_info->ec;
+ struct circ_buf *cb = &debug_info->log_buffer;
+ struct cros_ec_command snapshot_msg = {
+ .command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset,
+ };
+
+ struct ec_params_console_read_v1 *read_params =
+ (struct ec_params_console_read_v1 *)debug_info->read_msg->data;
+ uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data;
+ int idx;
+ int buf_space;
+ int ret;
+
+ ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
+ if (ret < 0) {
+ dev_err(ec->dev, "EC communication failed\n");
+ goto resched;
+ }
+ if (snapshot_msg.result != EC_RES_SUCCESS) {
+ dev_err(ec->dev, "EC failed to snapshot the console log\n");
+ goto resched;
+ }
+
+ /* Loop until we have read everything, or there's an error. */
+ mutex_lock(&debug_info->log_mutex);
+ buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE);
+
+ while (1) {
+ if (!buf_space) {
+ dev_info_once(ec->dev,
+ "Some logs may have been dropped...\n");
+ break;
+ }
+
+ memset(read_params, '\0', sizeof(*read_params));
+ read_params->subcmd = CONSOLE_READ_RECENT;
+ ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
+ if (ret < 0) {
+ dev_err(ec->dev, "EC communication failed\n");
+ break;
+ }
+ if (debug_info->read_msg->result != EC_RES_SUCCESS) {
+ dev_err(ec->dev,
+ "EC failed to read the console log\n");
+ break;
+ }
+
+ /* If the buffer is empty, we're done here. */
+ if (ret == 0 || ec_buffer[0] == '\0')
+ break;
+
+ idx = 0;
+ while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) {
+ cb->buf[cb->head] = ec_buffer[idx];
+ cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1);
+ idx++;
+ buf_space--;
+ }
+
+ wake_up(&debug_info->log_wq);
+ }
+
+ mutex_unlock(&debug_info->log_mutex);
+
+resched:
+ schedule_delayed_work(&debug_info->log_poll_work,
+ msecs_to_jiffies(LOG_POLL_SEC * 1000));
+}
+
+static int cros_ec_console_log_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct cros_ec_debugfs *debug_info = file->private_data;
+ struct circ_buf *cb = &debug_info->log_buffer;
+ ssize_t ret;
+
+ mutex_lock(&debug_info->log_mutex);
+
+ while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ goto error;
+ }
+
+ mutex_unlock(&debug_info->log_mutex);
+
+ ret = wait_event_interruptible(debug_info->log_wq,
+ CIRC_CNT(cb->head, cb->tail, LOG_SIZE));
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&debug_info->log_mutex);
+ }
+
+ /* Only copy until the end of the circular buffer, and let userspace
+ * retry to get the rest of the data.
+ */
+ ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE),
+ count);
+
+ if (copy_to_user(buf, cb->buf + cb->tail, ret)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret);
+
+error:
+ mutex_unlock(&debug_info->log_mutex);
+ return ret;
+}
+
+static unsigned int cros_ec_console_log_poll(struct file *file,
+ poll_table *wait)
+{
+ struct cros_ec_debugfs *debug_info = file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &debug_info->log_wq, wait);
+
+ mutex_lock(&debug_info->log_mutex);
+ if (CIRC_CNT(debug_info->log_buffer.head,
+ debug_info->log_buffer.tail,
+ LOG_SIZE))
+ mask |= POLLIN | POLLRDNORM;
+ mutex_unlock(&debug_info->log_mutex);
+
+ return mask;
+}
+
+static int cros_ec_console_log_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+const struct file_operations cros_ec_console_log_fops = {
+ .owner = THIS_MODULE,
+ .open = cros_ec_console_log_open,
+ .read = cros_ec_console_log_read,
+ .llseek = no_llseek,
+ .poll = cros_ec_console_log_poll,
+ .release = cros_ec_console_log_release,
+};
+
+static int ec_read_version_supported(struct cros_ec_dev *ec)
+{
+ struct ec_params_get_cmd_versions_v1 *params;
+ struct ec_response_get_cmd_versions *response;
+ int ret;
+
+ struct cros_ec_command *msg;
+
+ msg = kzalloc(sizeof(*msg) + max(sizeof(params), sizeof(response)),
+ GFP_KERNEL);
+ if (!msg)
+ return 0;
+
+ msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
+ msg->outsize = sizeof(*params);
+ msg->insize = sizeof(*response);
+
+ params = (struct ec_params_get_cmd_versions_v1 *)msg->data;
+ params->cmd = EC_CMD_CONSOLE_READ;
+ response = (struct ec_response_get_cmd_versions *)msg->data;
+
+ ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
+ msg->result == EC_RES_SUCCESS &&
+ (response->version_mask & EC_VER_MASK(1));
+
+ kfree(msg);
+
+ return ret;
+}
+
+static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
+{
+ struct cros_ec_dev *ec = debug_info->ec;
+ char *buf;
+ int read_params_size;
+ int read_response_size;
+
+ if (!ec_read_version_supported(ec)) {
+ dev_warn(ec->dev,
+ "device does not support reading the console log\n");
+ return 0;
+ }
+
+ buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ read_params_size = sizeof(struct ec_params_console_read_v1);
+ read_response_size = ec->ec_dev->max_response;
+ debug_info->read_msg = devm_kzalloc(ec->dev,
+ sizeof(*debug_info->read_msg) +
+ max(read_params_size, read_response_size), GFP_KERNEL);
+ if (!debug_info->read_msg)
+ return -ENOMEM;
+
+ debug_info->read_msg->version = 1;
+ debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset;
+ debug_info->read_msg->outsize = read_params_size;
+ debug_info->read_msg->insize = read_response_size;
+
+ debug_info->log_buffer.buf = buf;
+ debug_info->log_buffer.head = 0;
+ debug_info->log_buffer.tail = 0;
+
+ mutex_init(&debug_info->log_mutex);
+ init_waitqueue_head(&debug_info->log_wq);
+
+ if (!debugfs_create_file("console_log",
+ S_IFREG | S_IRUGO,
+ debug_info->dir,
+ debug_info,
+ &cros_ec_console_log_fops))
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&debug_info->log_poll_work,
+ cros_ec_console_log_work);
+ schedule_delayed_work(&debug_info->log_poll_work, 0);
+
+ return 0;
+}
+
+static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
+{
+ if (debug_info->log_buffer.buf) {
+ cancel_delayed_work_sync(&debug_info->log_poll_work);
+ mutex_destroy(&debug_info->log_mutex);
+ }
+}
+
+int cros_ec_debugfs_init(struct cros_ec_dev *ec)
+{
+ struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
+ const char *name = ec_platform->ec_name;
+ struct cros_ec_debugfs *debug_info;
+ int ret;
+
+ debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL);
+ if (!debug_info)
+ return -ENOMEM;
+
+ debug_info->ec = ec;
+ debug_info->dir = debugfs_create_dir(name, NULL);
+ if (!debug_info->dir)
+ return -ENOMEM;
+
+ ret = cros_ec_create_console_log(debug_info);
+ if (ret)
+ goto remove_debugfs;
+
+ ec->debug_info = debug_info;
+
+ return 0;
+
+remove_debugfs:
+ debugfs_remove_recursive(debug_info->dir);
+ return ret;
+}
+
+void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
+{
+ if (!ec->debug_info)
+ return;
+
+ debugfs_remove_recursive(ec->debug_info->dir);
+ cros_ec_cleanup_console_log(ec->debug_info);
+}
diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
new file mode 100644
index 0000000..1ff3a50
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 Google, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DRV_CROS_EC_DEBUGFS_H_
+#define _DRV_CROS_EC_DEBUGFS_H_
+
+#include "cros_ec_dev.h"
+
+/* debugfs stuff */
+int cros_ec_debugfs_init(struct cros_ec_dev *ec);
+void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
+
+#endif /* _DRV_CROS_EC_DEBUGFS_H_ */
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index 6f09da4..518210b 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include "cros_ec_debugfs.h"
#include "cros_ec_dev.h"
/* Device variables */
@@ -440,6 +441,9 @@ static int ec_device_probe(struct platform_device *pdev)
goto dev_reg_failed;
}
+ if (cros_ec_debugfs_init(ec))
+ dev_warn(dev, "failed to create debugfs directory\n");
+
/* check whether this EC is a sensor hub. */
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
cros_ec_sensors_register(ec);
@@ -458,6 +462,9 @@ static int ec_device_probe(struct platform_device *pdev)
static int ec_device_remove(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
+
+ cros_ec_debugfs_remove(ec);
+
cdev_del(&ec->cdev);
device_unregister(&ec->class_dev);
return 0;
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index 2ceb245..2f462d5 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -171,6 +171,8 @@ struct cros_ec_platform {
u16 cmd_offset;
};
+struct cros_ec_debugfs;
+
/*
* struct cros_ec_dev - ChromeOS EC device entry point
*
@@ -178,6 +180,7 @@ struct cros_ec_platform {
* @cdev: Character device structure in /dev
* @ec_dev: cros_ec_device structure to talk to the physical device
* @dev: pointer to the platform device
+ * @debug_info: cros_ec_debugfs structure for debugging information
* @cmd_offset: offset to apply for each command.
*/
struct cros_ec_dev {
@@ -185,6 +188,7 @@ struct cros_ec_dev {
struct cdev cdev;
struct cros_ec_device *ec_dev;
struct device *dev;
+ struct cros_ec_debugfs *debug_info;
u16 cmd_offset;
u32 features[2];
};
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Enric Balletbo i Serra <enric.balletbo@collabora.com> |
|---|---|
| Date | 2017-03-17 15:10 +0100 |
| Subject | [PATCH 04/13] mfd: cros_ec: Add support for dumping panic information |
| Message-ID | <tm0JR-7zo-33@gated-at.bofh.it> |
| In reply to | #1603334 |
From: Nicolas Boichat <drinkcat@chromium.org>
This dumps the EC panic information from the previous reboot.
Similar to the information presented by ectool panicinfo, except
that we do not bother doing any parsing (we should write a small
offline tool for that).
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
drivers/platform/chrome/cros_ec_debugfs.c | 54 +++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index f8195bb..8133c33 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -47,15 +47,19 @@
* @log_mutex: mutex to protect circular buffer
* @log_wq: waitqueue for log readers
* @log_poll_work: recurring task to poll EC for new console log data
+ * @panicinfo_blob: panicinfo debugfs blob
*/
struct cros_ec_debugfs {
struct cros_ec_dev *ec;
struct dentry *dir;
+ /* EC log */
struct circ_buf log_buffer;
struct cros_ec_command *read_msg;
struct mutex log_mutex;
wait_queue_head_t log_wq;
struct delayed_work log_poll_work;
+ /* EC panicinfo */
+ struct debugfs_blob_wrapper panicinfo_blob;
};
/*
@@ -308,6 +312,52 @@ static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
}
}
+static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
+{
+ struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
+ int ret;
+ struct cros_ec_command *msg;
+ int insize;
+
+ insize = ec_dev->max_response;
+
+ msg = devm_kzalloc(debug_info->ec->dev,
+ sizeof(*msg) + insize, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->command = EC_CMD_GET_PANIC_INFO;
+ msg->insize = insize;
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ if (ret < 0) {
+ dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n");
+ ret = 0;
+ goto free;
+ }
+
+ /* No panic data */
+ if (ret == 0)
+ goto free;
+
+ debug_info->panicinfo_blob.data = msg->data;
+ debug_info->panicinfo_blob.size = ret;
+
+ if (!debugfs_create_blob("panicinfo",
+ S_IFREG | S_IRUGO,
+ debug_info->dir,
+ &debug_info->panicinfo_blob)) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ return 0;
+
+free:
+ devm_kfree(debug_info->ec->dev, msg);
+ return ret;
+}
+
int cros_ec_debugfs_init(struct cros_ec_dev *ec)
{
struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
@@ -324,6 +374,10 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
if (!debug_info->dir)
return -ENOMEM;
+ ret = cros_ec_create_panicinfo(debug_info);
+ if (ret)
+ goto remove_debugfs;
+
ret = cros_ec_create_console_log(debug_info);
if (ret)
goto remove_debugfs;
--
2.9.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web