summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-26 14:46:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-26 14:46:01 -0700
commitf1f88bb51f1ae9d7eec9ef871355dea033bac02d (patch)
tree73f1a185af6f772e4c84971cde124c7d1e9f555d
parentb1c8312c6bd70e2c41f96183936fdb6f4f07cc0e (diff)
parentabd4fd43f2af03e2e852e6b1b98faeee9e3eae55 (diff)
downloadlinux-f1f88bb51f1ae9d7eec9ef871355dea033bac02d.tar.bz2
Merge tag 'tag-chrome-platform-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux
Pull chrome platform updates from Tzung-Bi Shih: "cros_ec: - Fix wrong error handling path - Clean-up patches cros_ec_chardev: - Re-introduce cros_ec_cmd_xfer to fix ABI broken cros_ec_lpcs: - Support the Framework Laptop cros_ec_typec: - Fix NULL dereference chromeos_acpi: - Add ChromeOS ACPI device driver - Fix Sphinx errors when `make htmldocs` misc: - Drop BUG_ON()s" * tag 'tag-chrome-platform-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: platform/chrome: Use imperative mood for ChromeOS ACPI sysfs ABI descriptions platform/chrome: Use tables for values lists of ChromeOS ACPI sysfs ABI platform/chrome: cros_ec_spi: drop BUG_ON() if `din` isn't large enough platform/chrome: cros_ec_spi: drop unneeded BUG_ON() platform/chrome: cros_ec_i2c: drop BUG_ON() in cros_ec_pkt_xfer_i2c() platform/chrome: cros_ec_proto: drop BUG_ON() in cros_ec_get_host_event() platform/chrome: cros_ec_proto: drop BUG_ON() in cros_ec_prepare_tx() platform/chrome: correct cros_ec_prepare_tx() usage platform/chrome: cros_ec_proto: drop unneeded BUG_ON() in prepare_packet() platform/chrome: Add ChromeOS ACPI device driver platform/chrome: cros_ec_typec: Check for EC driver platform/chrome: cros_ec_lpcs: reserve the MEC LPC I/O ports first platform/chrome: cros_ec_lpcs: detect the Framework Laptop platform/chrome: Re-introduce cros_ec_cmd_xfer and use it for ioctls platform/chrome: cros_ec: append newline to all logs platform/chrome: cros_ec: sort header inclusion alphabetically platform/chrome: cros_ec: determine `wake_enabled` in cros_ec_suspend() platform/chrome: cros_ec: remove unused variable `was_wake_device` platform/chrome: cros_ec: fix error handling in cros_ec_register()
-rw-r--r--Documentation/ABI/testing/sysfs-driver-chromeos-acpi137
-rw-r--r--Documentation/firmware-guide/acpi/chromeos-acpi-device.rst363
-rw-r--r--Documentation/firmware-guide/acpi/index.rst1
-rw-r--r--drivers/platform/chrome/Kconfig11
-rw-r--r--drivers/platform/chrome/Makefile1
-rw-r--r--drivers/platform/chrome/chromeos_acpi.c257
-rw-r--r--drivers/platform/chrome/cros_ec.c36
-rw-r--r--drivers/platform/chrome/cros_ec_chardev.c2
-rw-r--r--drivers/platform/chrome/cros_ec_i2c.c12
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c4
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c49
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c63
-rw-r--r--drivers/platform/chrome/cros_ec_rpmsg.c2
-rw-r--r--drivers/platform/chrome/cros_ec_spi.c15
-rw-r--r--drivers/platform/chrome/cros_ec_typec.c3
-rw-r--r--include/linux/platform_data/cros_ec_commands.h10
-rw-r--r--include/linux/platform_data/cros_ec_proto.h6
17 files changed, 914 insertions, 58 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-chromeos-acpi b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi
new file mode 100644
index 000000000000..c308926e1568
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi
@@ -0,0 +1,137 @@
+What: /sys/bus/platform/devices/GGL0001:*/BINF.2
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns active EC firmware of current boot (boolean).
+
+ == ===============================
+ 0 Read only (recovery) firmware.
+ 1 Rewritable firmware.
+ == ===============================
+
+What: /sys/bus/platform/devices/GGL0001:*/BINF.3
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns main firmware type for current boot (integer).
+
+ == =====================================
+ 0 Recovery.
+ 1 Normal.
+ 2 Developer.
+ 3 Netboot (factory installation only).
+ == =====================================
+
+What: /sys/bus/platform/devices/GGL0001:*/CHSW
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns switch position for Chrome OS specific hardware
+ switches when the firmware is booted (integer).
+
+ ==== ===========================================
+ 0 No changes.
+ 2 Recovery button was pressed.
+ 4 Recovery button was pressed (EC firmware).
+ 32 Developer switch was enabled.
+ 512 Firmware write protection was disabled.
+ ==== ===========================================
+
+What: /sys/bus/platform/devices/GGL0001:*/FMAP
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns physical memory address of the start of the main
+ processor firmware flashmap.
+
+What: /sys/bus/platform/devices/GGL0001:*/FRID
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns firmware version for the read-only portion of the
+ main processor firmware.
+
+What: /sys/bus/platform/devices/GGL0001:*/FWID
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns firmware version for the rewritable portion of the
+ main processor firmware.
+
+What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.0
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns type of the GPIO signal for the Chrome OS specific
+ GPIO assignments (integer).
+
+ =========== ==================================
+ 1 Recovery button.
+ 2 Developer mode switch.
+ 3 Firmware write protection switch.
+ 256 to 511 Debug header GPIO 0 to GPIO 255.
+ =========== ==================================
+
+What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.1
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns signal attributes of the GPIO signal (integer bitfield).
+
+ == =======================
+ 0 Signal is active low.
+ 1 Signal is active high.
+ == =======================
+
+What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.2
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns the GPIO number on the specified GPIO
+ controller.
+
+What: /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.3
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns name of the GPIO controller.
+
+What: /sys/bus/platform/devices/GGL0001:*/HWID
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns hardware ID for the Chromebook.
+
+What: /sys/bus/platform/devices/GGL0001:*/MECK
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns the SHA-1 or SHA-256 hash that is read out of the
+ Management Engine extended registers during boot. The hash
+ is exported via ACPI so the OS can verify that the Management
+ Engine firmware has not changed. If Management Engine is not
+ present, or if the firmware was unable to read the extended registers, this buffer size can be zero.
+
+What: /sys/bus/platform/devices/GGL0001:*/VBNV.0
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns offset in CMOS bank 0 of the verified boot non-volatile
+ storage block, counting from the first writable CMOS byte
+ (that is, 'offset = 0' is the byte following the 14 bytes of
+ clock data).
+
+What: /sys/bus/platform/devices/GGL0001:*/VBNV.1
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Return the size in bytes of the verified boot non-volatile
+ storage block.
+
+What: /sys/bus/platform/devices/GGL0001:*/VDAT
+Date: May 2022
+KernelVersion: 5.19
+Description:
+ Returns the verified boot data block shared between the
+ firmware verification step and the kernel verification step
+ (binary).
diff --git a/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst b/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
new file mode 100644
index 000000000000..f37fc90ce340
--- /dev/null
+++ b/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
@@ -0,0 +1,363 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+Chrome OS ACPI Device
+=====================
+
+Hardware functionality specific to Chrome OS is exposed through a Chrome OS ACPI device.
+The plug and play ID of a Chrome OS ACPI device is GGL0001. GGL is a valid PNP ID of Google.
+PNP ID can be used with the ACPI devices according to the guidelines. The following ACPI
+objects are supported:
+
+.. flat-table:: Supported ACPI Objects
+ :widths: 1 2
+ :header-rows: 1
+
+ * - Object
+ - Description
+
+ * - CHSW
+ - Chrome OS switch positions
+
+ * - HWID
+ - Chrome OS hardware ID
+
+ * - FWID
+ - Chrome OS firmware version
+
+ * - FRID
+ - Chrome OS read-only firmware version
+
+ * - BINF
+ - Chrome OS boot information
+
+ * - GPIO
+ - Chrome OS GPIO assignments
+
+ * - VBNV
+ - Chrome OS NVRAM locations
+
+ * - VDTA
+ - Chrome OS verified boot data
+
+ * - FMAP
+ - Chrome OS flashmap base address
+
+ * - MLST
+ - Chrome OS method list
+
+CHSW (Chrome OS switch positions)
+=================================
+This control method returns the switch positions for Chrome OS specific hardware switches.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+An integer containing the switch positions as bitfields:
+
+.. flat-table::
+ :widths: 1 2
+
+ * - 0x00000002
+ - Recovery button was pressed when x86 firmware booted.
+
+ * - 0x00000004
+ - Recovery button was pressed when EC firmware booted. (required if EC EEPROM is
+ rewritable; otherwise optional)
+
+ * - 0x00000020
+ - Developer switch was enabled when x86 firmware booted.
+
+ * - 0x00000200
+ - Firmware write protection was disabled when x86 firmware booted. (required if
+ firmware write protection is controlled through x86 BIOS; otherwise optional)
+
+All other bits are reserved and should be set to 0.
+
+HWID (Chrome OS hardware ID)
+============================
+This control method returns the hardware ID for the Chromebook.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A null-terminated ASCII string containing the hardware ID from the Model-Specific Data area of
+EEPROM.
+
+Note that the hardware ID can be up to 256 characters long, including the terminating null.
+
+FWID (Chrome OS firmware version)
+=================================
+This control method returns the firmware version for the rewritable portion of the main
+processor firmware.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A null-terminated ASCII string containing the complete firmware version for the rewritable
+portion of the main processor firmware.
+
+FRID (Chrome OS read-only firmware version)
+===========================================
+This control method returns the firmware version for the read-only portion of the main
+processor firmware.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A null-terminated ASCII string containing the complete firmware version for the read-only
+(bootstrap + recovery ) portion of the main processor firmware.
+
+BINF (Chrome OS boot information)
+=================================
+This control method returns information about the current boot.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+
+.. code-block::
+
+ Package {
+ Reserved1
+ Reserved2
+ Active EC Firmware
+ Active Main Firmware Type
+ Reserved5
+ }
+
+.. flat-table::
+ :widths: 1 1 2
+ :header-rows: 1
+
+ * - Field
+ - Format
+ - Description
+
+ * - Reserved1
+ - DWORD
+ - Set to 256 (0x100). This indicates this field is no longer used.
+
+ * - Reserved2
+ - DWORD
+ - Set to 256 (0x100). This indicates this field is no longer used.
+
+ * - Active EC firmware
+ - DWORD
+ - The EC firmware which was used during boot.
+
+ - 0 - Read-only (recovery) firmware
+ - 1 - Rewritable firmware.
+
+ Set to 0 if EC firmware is always read-only.
+
+ * - Active Main Firmware Type
+ - DWORD
+ - The main firmware type which was used during boot.
+
+ - 0 - Recovery
+ - 1 - Normal
+ - 2 - Developer
+ - 3 - netboot (factory installation only)
+
+ Other values are reserved.
+
+ * - Reserved5
+ - DWORD
+ - Set to 256 (0x100). This indicates this field is no longer used.
+
+GPIO (Chrome OS GPIO assignments)
+=================================
+This control method returns information about Chrome OS specific GPIO assignments for
+Chrome OS hardware, so the kernel can directly control that hardware.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+.. code-block::
+
+ Package {
+ Package {
+ // First GPIO assignment
+ Signal Type //DWORD
+ Attributes //DWORD
+ Controller Offset //DWORD
+ Controller Name //ASCIIZ
+ },
+ ...
+ Package {
+ // Last GPIO assignment
+ Signal Type //DWORD
+ Attributes //DWORD
+ Controller Offset //DWORD
+ Controller Name //ASCIIZ
+ }
+ }
+
+Where ASCIIZ means a null-terminated ASCII string.
+
+.. flat-table::
+ :widths: 1 1 2
+ :header-rows: 1
+
+ * - Field
+ - Format
+ - Description
+
+ * - Signal Type
+ - DWORD
+ - Type of GPIO signal
+
+ - 0x00000001 - Recovery button
+ - 0x00000002 - Developer mode switch
+ - 0x00000003 - Firmware write protection switch
+ - 0x00000100 - Debug header GPIO 0
+ - ...
+ - 0x000001FF - Debug header GPIO 255
+
+ Other values are reserved.
+
+ * - Attributes
+ - DWORD
+ - Signal attributes as bitfields:
+
+ - 0x00000001 - Signal is active-high (for button, a GPIO value
+ of 1 means the button is pressed; for switches, a GPIO value
+ of 1 means the switch is enabled). If this bit is 0, the signal
+ is active low. Set to 0 for debug header GPIOs.
+
+ * - Controller Offset
+ - DWORD
+ - GPIO number on the specified controller.
+
+ * - Controller Name
+ - ASCIIZ
+ - Name of the controller for the GPIO.
+ Currently supported names:
+ "NM10" - Intel NM10 chip
+
+VBNV (Chrome OS NVRAM locations)
+================================
+This control method returns information about the NVRAM (CMOS) locations used to
+communicate with the BIOS.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+.. code-block::
+
+ Package {
+ NV Storage Block Offset //DWORD
+ NV Storage Block Size //DWORD
+ }
+
+.. flat-table::
+ :widths: 1 1 2
+ :header-rows: 1
+
+ * - Field
+ - Format
+ - Description
+
+ * - NV Storage Block Offset
+ - DWORD
+ - Offset in CMOS bank 0 of the verified boot non-volatile storage block, counting from
+ the first writable CMOS byte (that is, offset=0 is the byte following the 14 bytes of
+ clock data).
+
+ * - NV Storage Block Size
+ - DWORD
+ - Size in bytes of the verified boot non-volatile storage block.
+
+FMAP (Chrome OS flashmap address)
+=================================
+This control method returns the physical memory address of the start of the main processor
+firmware flashmap.
+
+Arguments:
+----------
+None
+
+NoneResult code:
+----------------
+A DWORD containing the physical memory address of the start of the main processor firmware
+flashmap.
+
+VDTA (Chrome OS verified boot data)
+===================================
+This control method returns the verified boot data block shared between the firmware
+verification step and the kernel verification step.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A buffer containing the verified boot data block.
+
+MECK (Management Engine Checksum)
+=================================
+This control method returns the SHA-1 or SHA-256 hash that is read out of the Management
+Engine extended registers during boot. The hash is exported via ACPI so the OS can verify that
+the ME firmware has not changed. If Management Engine is not present, or if the firmware was
+unable to read the extended registers, this buffer can be zero.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A buffer containing the ME hash.
+
+MLST (Chrome OS method list)
+============================
+This control method returns a list of the other control methods supported by the Chrome OS
+hardware device.
+
+Arguments:
+----------
+None
+
+Result code:
+------------
+A package containing a list of null-terminated ASCII strings, one for each control method
+supported by the Chrome OS hardware device, not including the MLST method itself.
+For this version of the specification, the result is:
+
+.. code-block::
+
+ Package {
+ "CHSW",
+ "FWID",
+ "HWID",
+ "FRID",
+ "BINF",
+ "GPIO",
+ "VBNV",
+ "FMAP",
+ "VDTA",
+ "MECK"
+ }
diff --git a/Documentation/firmware-guide/acpi/index.rst b/Documentation/firmware-guide/acpi/index.rst
index b053b0c3d696..b6a42f4ffe03 100644
--- a/Documentation/firmware-guide/acpi/index.rst
+++ b/Documentation/firmware-guide/acpi/index.rst
@@ -29,3 +29,4 @@ ACPI Support
non-d0-probe
extcon-intel-int3496
intel-pmc-mux
+ chromeos-acpi-device
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 75e93efd669f..717299cbccac 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -15,6 +15,17 @@ menuconfig CHROME_PLATFORMS
if CHROME_PLATFORMS
+config CHROMEOS_ACPI
+ tristate "ChromeOS specific ACPI extensions"
+ depends on ACPI
+ help
+ This driver provides the firmware interface for the services
+ exported through the ChromeOS interfaces when using ChromeOS
+ ACPI firmware.
+
+ If you have an ACPI-compatible Chromebook, say Y or M here.
+ The module will be called chromeos_acpi.
+
config CHROMEOS_LAPTOP
tristate "Chrome OS Laptop"
depends on I2C && DMI && X86
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 6420ca129548..52f5a2dde8b8 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -4,6 +4,7 @@
CFLAGS_cros_ec_trace.o:= -I$(src)
CFLAGS_cros_ec_sensorhub_ring.o:= -I$(src)
+obj-$(CONFIG_CHROMEOS_ACPI) += chromeos_acpi.o
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN) += chromeos_privacy_screen.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
diff --git a/drivers/platform/chrome/chromeos_acpi.c b/drivers/platform/chrome/chromeos_acpi.c
new file mode 100644
index 000000000000..50d8a4d4352d
--- /dev/null
+++ b/drivers/platform/chrome/chromeos_acpi.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ChromeOS specific ACPI extensions
+ *
+ * Copyright 2022 Google LLC
+ *
+ * This driver attaches to the ChromeOS ACPI device and then exports the
+ * values reported by the ACPI in a sysfs directory. All values are
+ * presented in the string form (numbers as decimal values) and can be
+ * accessed as the contents of the appropriate read only files in the
+ * sysfs directory tree.
+ */
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+#define ACPI_ATTR_NAME_LEN 4
+
+#define DEV_ATTR(_var, _name) \
+ static struct device_attribute dev_attr_##_var = \
+ __ATTR(_name, 0444, chromeos_first_level_attr_show, NULL);
+
+#define GPIO_ATTR_GROUP(_group, _name, _num) \
+ static umode_t attr_is_visible_gpio_##_num(struct kobject *kobj, \
+ struct attribute *attr, int n) \
+ { \
+ if (_num < chromeos_acpi_gpio_groups) \
+ return attr->mode; \
+ return 0; \
+ } \
+ static ssize_t chromeos_attr_show_gpio_##_num(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ char name[ACPI_ATTR_NAME_LEN + 1]; \
+ int ret, num; \
+ \
+ ret = parse_attr_name(attr->attr.name, name, &num); \
+ if (ret) \
+ return ret; \
+ return chromeos_acpi_evaluate_method(dev, _num, num, name, buf); \
+ } \
+ static struct device_attribute dev_attr_0_##_group = \
+ __ATTR(GPIO.0, 0444, chromeos_attr_show_gpio_##_num, NULL); \
+ static struct device_attribute dev_attr_1_##_group = \
+ __ATTR(GPIO.1, 0444, chromeos_attr_show_gpio_##_num, NULL); \
+ static struct device_attribute dev_attr_2_##_group = \
+ __ATTR(GPIO.2, 0444, chromeos_attr_show_gpio_##_num, NULL); \
+ static struct device_attribute dev_attr_3_##_group = \
+ __ATTR(GPIO.3, 0444, chromeos_attr_show_gpio_##_num, NULL); \
+ \
+ static struct attribute *attrs_##_group[] = { \
+ &dev_attr_0_##_group.attr, \
+ &dev_attr_1_##_group.attr, \
+ &dev_attr_2_##_group.attr, \
+ &dev_attr_3_##_group.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group attr_group_##_group = { \
+ .name = _name, \
+ .is_visible = attr_is_visible_gpio_##_num, \
+ .attrs = attrs_##_group, \
+ };
+
+static unsigned int chromeos_acpi_gpio_groups;
+
+/* Parse the ACPI package and return the data related to that attribute */
+static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *obj,
+ int pkg_num, int sub_pkg_num, char *name, char *buf)
+{
+ union acpi_object *element = obj->package.elements;
+
+ if (pkg_num >= obj->package.count)
+ return -EINVAL;
+ element += pkg_num;
+
+ if (element->type == ACPI_TYPE_PACKAGE) {
+ if (sub_pkg_num >= element->package.count)
+ return -EINVAL;
+ /* select sub element inside this package */
+ element = element->package.elements;
+ element += sub_pkg_num;
+ }
+
+ switch (element->type) {
+ case ACPI_TYPE_INTEGER:
+ return sysfs_emit(buf, "%d\n", (int)element->integer.value);
+ case ACPI_TYPE_STRING:
+ return sysfs_emit(buf, "%s\n", element->string.pointer);
+ case ACPI_TYPE_BUFFER:
+ return sysfs_emit(buf, "%s\n", element->buffer.pointer);
+ default:
+ dev_err(dev, "element type %d not supported\n", element->type);
+ return -EINVAL;
+ }
+}
+
+static int chromeos_acpi_evaluate_method(struct device *dev, int pkg_num, int sub_pkg_num,
+ char *name, char *buf)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+ int ret = -EINVAL;
+
+ status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
+ return ret;
+ }
+
+ if (((union acpi_object *)output.pointer)->type == ACPI_TYPE_PACKAGE)
+ ret = chromeos_acpi_handle_package(dev, output.pointer, pkg_num, sub_pkg_num,
+ name, buf);
+
+ kfree(output.pointer);
+ return ret;
+}
+
+static int parse_attr_name(const char *name, char *attr_name, int *attr_num)
+{
+ int ret;
+
+ ret = strscpy(attr_name, name, ACPI_ATTR_NAME_LEN + 1);
+ if (ret == -E2BIG)
+ return kstrtoint(&name[ACPI_ATTR_NAME_LEN + 1], 0, attr_num);
+ return 0;
+}
+
+static ssize_t chromeos_first_level_attr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ char attr_name[ACPI_ATTR_NAME_LEN + 1];
+ int ret, attr_num = 0;
+
+ ret = parse_attr_name(attr->attr.name, attr_name, &attr_num);
+ if (ret)
+ return ret;
+ return chromeos_acpi_evaluate_method(dev, attr_num, 0, attr_name, buf);
+}
+
+static unsigned int get_gpio_pkg_num(struct device *dev)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ unsigned int count = 0;
+ char *name = "GPIO";
+
+ status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
+ return count;
+ }
+
+ obj = output.pointer;
+
+ if (obj->type == ACPI_TYPE_PACKAGE)
+ count = obj->package.count;
+
+ kfree(output.pointer);
+ return count;
+}
+
+DEV_ATTR(binf2, BINF.2)
+DEV_ATTR(binf3, BINF.3)
+DEV_ATTR(chsw, CHSW)
+DEV_ATTR(fmap, FMAP)
+DEV_ATTR(frid, FRID)
+DEV_ATTR(fwid, FWID)
+DEV_ATTR(hwid, HWID)
+DEV_ATTR(meck, MECK)
+DEV_ATTR(vbnv0, VBNV.0)
+DEV_ATTR(vbnv1, VBNV.1)
+DEV_ATTR(vdat, VDAT)
+
+static struct attribute *first_level_attrs[] = {
+ &dev_attr_binf2.attr,
+ &dev_attr_binf3.attr,
+ &dev_attr_chsw.attr,
+ &dev_attr_fmap.attr,
+ &dev_attr_frid.attr,
+ &dev_attr_fwid.attr,
+ &dev_attr_hwid.attr,
+ &dev_attr_meck.attr,
+ &dev_attr_vbnv0.attr,
+ &dev_attr_vbnv1.attr,
+ &dev_attr_vdat.attr,
+ NULL
+};
+
+static const struct attribute_group first_level_attr_group = {
+ .attrs = first_level_attrs,
+};
+
+/*
+ * Every platform can have a different number of GPIO attribute groups.
+ * Define upper limit groups. At run time, the platform decides to show
+ * the present number of groups only, others are hidden.
+ */
+GPIO_ATTR_GROUP(gpio0, "GPIO.0", 0)
+GPIO_ATTR_GROUP(gpio1, "GPIO.1", 1)
+GPIO_ATTR_GROUP(gpio2, "GPIO.2", 2)
+GPIO_ATTR_GROUP(gpio3, "GPIO.3", 3)
+GPIO_ATTR_GROUP(gpio4, "GPIO.4", 4)
+GPIO_ATTR_GROUP(gpio5, "GPIO.5", 5)
+GPIO_ATTR_GROUP(gpio6, "GPIO.6", 6)
+GPIO_ATTR_GROUP(gpio7, "GPIO.7", 7)
+
+static const struct attribute_group *chromeos_acpi_all_groups[] = {
+ &first_level_attr_group,
+ &attr_group_gpio0,
+ &attr_group_gpio1,
+ &attr_group_gpio2,
+ &attr_group_gpio3,
+ &attr_group_gpio4,
+ &attr_group_gpio5,
+ &attr_group_gpio6,
+ &attr_group_gpio7,
+ NULL
+};
+
+static int chromeos_acpi_device_probe(struct platform_device *pdev)
+{
+ chromeos_acpi_gpio_groups = get_gpio_pkg_num(&pdev->dev);
+
+ /*
+ * If the platform has more GPIO attribute groups than the number of
+ * groups this driver supports, give out a warning message.
+ */
+ if (chromeos_acpi_gpio_groups > ARRAY_SIZE(chromeos_acpi_all_groups) - 2)
+ dev_warn(&pdev->dev, "Only %zu GPIO attr groups supported by the driver out of total %u.\n",
+ ARRAY_SIZE(chromeos_acpi_all_groups) - 2, chromeos_acpi_gpio_groups);
+ return 0;
+}
+
+/* GGL is valid PNP ID of Google. PNP ID can be used with the ACPI devices. */
+static const struct acpi_device_id chromeos_device_ids[] = {
+ { "GGL0001", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);
+
+static struct platform_driver chromeos_acpi_device_driver = {
+ .probe = chromeos_acpi_device_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .dev_groups = chromeos_acpi_all_groups,
+ .acpi_match_table = chromeos_device_ids,
+ }
+};
+module_platform_driver(chromeos_acpi_device_driver);
+
+MODULE_AUTHOR("Muhammad Usama Anjum <usama.anjum@collabora.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ChromeOS specific ACPI extensions");
diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c
index d49a4efe46c8..b3e94cdf7d1a 100644
--- a/drivers/platform/chrome/cros_ec.c
+++ b/drivers/platform/chrome/cros_ec.c
@@ -9,12 +9,12 @@
* battery charging and regulator control, firmware update.
*/
-#include <linux/of_platform.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of_platform.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/slab.h>
#include <linux/suspend.h>
#include "cros_ec.h"
@@ -189,6 +189,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
ec_dev->max_request = sizeof(struct ec_params_hello);
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
ec_dev->max_passthru = 0;
+ ec_dev->ec = NULL;
+ ec_dev->pd = NULL;
ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
if (!ec_dev->din)
@@ -213,7 +215,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"chromeos-ec", ec_dev);
if (err) {
- dev_err(dev, "Failed to request IRQ %d: %d",
+ dev_err(dev, "Failed to request IRQ %d: %d\n",
ec_dev->irq, err);
return err;
}
@@ -245,18 +247,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (IS_ERR(ec_dev->pd)) {
dev_err(ec_dev->dev,
"Failed to create CrOS PD platform device\n");
- platform_device_unregister(ec_dev->ec);
- return PTR_ERR(ec_dev->pd);
+ err = PTR_ERR(ec_dev->pd);
+ goto exit;
}
}
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
err = devm_of_platform_populate(dev);
if (err) {
- platform_device_unregister(ec_dev->pd);
- platform_device_unregister(ec_dev->ec);
dev_err(dev, "Failed to register sub-devices\n");
- return err;
+ goto exit;
}
}
@@ -266,7 +266,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
*/
err = cros_ec_sleep_event(ec_dev, 0);
if (err < 0)
- dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
+ dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec\n",
err);
if (ec_dev->mkbp_event_supported) {
@@ -278,7 +278,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
err = blocking_notifier_chain_register(&ec_dev->event_notifier,
&ec_dev->notifier_ready);
if (err)
- return err;
+ goto exit;
}
dev_info(dev, "Chrome EC device registered\n");
@@ -291,6 +291,10 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
cros_ec_irq_thread(0, ec_dev);
return 0;
+exit:
+ platform_device_unregister(ec_dev->ec);
+ platform_device_unregister(ec_dev->pd);
+ return err;
}
EXPORT_SYMBOL(cros_ec_register);
@@ -331,14 +335,15 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
ret = cros_ec_sleep_event(ec_dev, sleep_event);
if (ret < 0)
- dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec",
+ dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec\n",
ret);
if (device_may_wakeup(dev))
ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
+ else
+ ec_dev->wake_enabled = false;
disable_irq(ec_dev->irq);
- ec_dev->was_wake_device = ec_dev->wake_enabled;
ec_dev->suspended = true;
return 0;
@@ -375,13 +380,12 @@ int cros_ec_resume(struct cros_ec_device *ec_dev)
ret = cros_ec_sleep_event(ec_dev, sleep_event);
if (ret < 0)
- dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
+ dev_dbg(ec_dev->dev, "Error %d sending resume event to ec\n",
ret);
- if (ec_dev->wake_enabled) {
+ if (ec_dev->wake_enabled)
disable_irq_wake(ec_dev->irq);
- ec_dev->wake_enabled = 0;
- }
+
/*
* Let the mfd devices know about events that occur during
* suspend. This way the clients know what to do with them.
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index e0bce869c49a..fd33de546aee 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -301,7 +301,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
}
s_cmd->command += ec->cmd_offset;
- ret = cros_ec_cmd_xfer_status(ec->ec_dev, s_cmd);
+ ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
/* Only copy data to userland if data was received. */
if (ret < 0)
goto exit;
diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c
index 22feb0fd4ce7..9f5b95763173 100644
--- a/drivers/platform/chrome/cros_ec_i2c.c
+++ b/drivers/platform/chrome/cros_ec_i2c.c
@@ -72,13 +72,19 @@ static int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev,
i2c_msg[1].flags = I2C_M_RD;
packet_len = msg->insize + response_header_size;
- BUG_ON(packet_len > ec_dev->din_size);
+ if (packet_len > ec_dev->din_size) {
+ ret = -EINVAL;
+ goto done;
+ }
in_buf = ec_dev->din;
i2c_msg[1].len = packet_len;
i2c_msg[1].buf = (char *) in_buf;
packet_len = msg->outsize + request_header_size;
- BUG_ON(packet_len > ec_dev->dout_size);
+ if (packet_len > ec_dev->dout_size) {
+ ret = -EINVAL;
+ goto done;
+ }
out_buf = ec_dev->dout;
i2c_msg[0].len = packet_len;
i2c_msg[0].buf = (char *) out_buf;
@@ -89,6 +95,8 @@ static int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev,
ec_dev->dout++;
ret = cros_ec_prepare_tx(ec_dev, msg);
+ if (ret < 0)
+ goto done;
ec_dev->dout--;
/* send command to EC and read answer */
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
index 4020b8354bae..cb2031cf7106 100644
--- a/drivers/platform/chrome/cros_ec_ishtp.c
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -521,7 +521,9 @@ static int cros_ec_pkt_xfer_ish(struct cros_ec_device *ec_dev,
out_msg->hdr.status = 0;
ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE;
- cros_ec_prepare_tx(ec_dev, msg);
+ rv = cros_ec_prepare_tx(ec_dev, msg);
+ if (rv < 0)
+ goto end_error;
ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE;
dev_dbg(dev,
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 7651417b4a25..7677ab3c0ead 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -147,6 +147,8 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
u8 *dout;
ret = cros_ec_prepare_tx(ec, msg);
+ if (ret < 0)
+ goto done;
/* Write buffer */
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
@@ -341,9 +343,14 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
u8 buf[2];
int irq, ret;
- if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
- dev_name(dev))) {
- dev_err(dev, "couldn't reserve memmap region\n");
+ /*
+ * The Framework Laptop (and possibly other non-ChromeOS devices)
+ * only exposes the eight I/O ports that are required for the Microchip EC.
+ * Requesting a larger reservation will fail.
+ */
+ if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
+ EC_HOST_CMD_MEC_REGION_SIZE, dev_name(dev))) {
+ dev_err(dev, "couldn't reserve MEC region\n");
return -EBUSY;
}
@@ -357,6 +364,12 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
cros_ec_lpc_ops.write = cros_ec_lpc_mec_write_bytes;
cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
if (buf[0] != 'E' || buf[1] != 'C') {
+ if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
+ dev_name(dev))) {
+ dev_err(dev, "couldn't reserve memmap region\n");
+ return -EBUSY;
+ }
+
/* Re-assign read/write operations for the non MEC variant */
cros_ec_lpc_ops.read = cros_ec_lpc_read_bytes;
cros_ec_lpc_ops.write = cros_ec_lpc_write_bytes;
@@ -366,17 +379,19 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
dev_err(dev, "EC ID not detected\n");
return -ENODEV;
}
- }
- if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
- EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
- dev_err(dev, "couldn't reserve region0\n");
- return -EBUSY;
- }
- if (!devm_request_region(dev, EC_HOST_CMD_REGION1,
- EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
- dev_err(dev, "couldn't reserve region1\n");
- return -EBUSY;
+ /* Reserve the remaining I/O ports required by the non-MEC protocol. */
+ if (!devm_request_region(dev, EC_HOST_CMD_REGION0 + EC_HOST_CMD_MEC_REGION_SIZE,
+ EC_HOST_CMD_REGION_SIZE - EC_HOST_CMD_MEC_REGION_SIZE,
+ dev_name(dev))) {
+ dev_err(dev, "couldn't reserve remainder of region0\n");
+ return -EBUSY;
+ }
+ if (!devm_request_region(dev, EC_HOST_CMD_REGION1,
+ EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
+ dev_err(dev, "couldn't reserve region1\n");
+ return -EBUSY;
+ }
}
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
@@ -502,6 +517,14 @@ static const struct dmi_system_id cros_ec_lpc_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),
},
},
+ /* A small number of non-Chromebook/box machines also use the ChromeOS EC */
+ {
+ /* the Framework Laptop */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Laptop"),
+ },
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table);
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index c4caf2e2de82..ff767dccdf0f 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -60,8 +60,8 @@ static int prepare_packet(struct cros_ec_device *ec_dev,
int i;
u8 csum = 0;
- BUG_ON(ec_dev->proto_version != EC_HOST_REQUEST_VERSION);
- BUG_ON(msg->outsize + sizeof(*request) > ec_dev->dout_size);
+ if (msg->outsize + sizeof(*request) > ec_dev->dout_size)
+ return -EINVAL;
out = ec_dev->dout;
request = (struct ec_host_request *)out;
@@ -165,7 +165,7 @@ static int send_command(struct cros_ec_device *ec_dev,
* only SPI uses it. Once LPC uses the same protocol it can start using it.
* I2C could use it now, with a refactor of the existing code.
*
- * Return: 0 on success or negative error code.
+ * Return: number of prepared bytes on success or negative error code.
*/
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
@@ -177,7 +177,9 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
if (ec_dev->proto_version > 2)
return prepare_packet(ec_dev, msg);
- BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
+ if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)
+ return -EINVAL;
+
out = ec_dev->dout;
out[0] = EC_CMD_VERSION0 + msg->version;
out[1] = msg->command;
@@ -560,22 +562,28 @@ exit:
EXPORT_SYMBOL(cros_ec_query_all);
/**
- * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
+ * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
* @ec_dev: EC device.
* @msg: Message to write.
*
- * Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
- * cmd_xfer() callback directly. It returns success status only if both the command was transmitted
- * successfully and the EC replied with success status.
+ * Call this to send a command to the ChromeOS EC. This should be used instead
+ * of calling the EC's cmd_xfer() callback directly. This function does not
+ * convert EC command execution error codes to Linux error codes. Most
+ * in-kernel users will want to use cros_ec_cmd_xfer_status() instead since
+ * that function implements the conversion.
*
* Return:
- * >=0 - The number of bytes transferred
- * <0 - Linux error code
+ * >0 - EC command was executed successfully. The return value is the number
+ * of bytes returned by the EC (excluding the header).
+ * =0 - EC communication was successful. EC command execution results are
+ * reported in msg->result. The result will be EC_RES_SUCCESS if the
+ * command was executed successfully or report an EC command execution
+ * error.
+ * <0 - EC communication error. Return value is the Linux error code.
*/
-int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
- struct cros_ec_command *msg)
+int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
- int ret, mapped;
+ int ret;
mutex_lock(&ec_dev->lock);
if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {
@@ -616,6 +624,32 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
ret = send_command(ec_dev, msg);
mutex_unlock(&ec_dev->lock);
+ return ret;
+}
+EXPORT_SYMBOL(cros_ec_cmd_xfer);
+
+/**
+ * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
+ * @ec_dev: EC device.
+ * @msg: Message to write.
+ *
+ * Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
+ * cmd_xfer() callback directly. It returns success status only if both the command was transmitted
+ * successfully and the EC replied with success status.
+ *
+ * Return:
+ * >=0 - The number of bytes transferred.
+ * <0 - Linux error code
+ */
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+ struct cros_ec_command *msg)
+{
+ int ret, mapped;
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ if (ret < 0)
+ return ret;
+
mapped = cros_ec_map_error(msg->result);
if (mapped) {
dev_dbg(ec_dev->dev, "Command result (err: %d [%d])\n",
@@ -783,7 +817,8 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
{
u32 host_event;
- BUG_ON(!ec_dev->mkbp_event_supported);
+ if (!ec_dev->mkbp_event_supported)
+ return 0;
if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)
return 0;
diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c
index d96d15b8ca94..39d3b50a7c09 100644
--- a/drivers/platform/chrome/cros_ec_rpmsg.c
+++ b/drivers/platform/chrome/cros_ec_rpmsg.c
@@ -89,6 +89,8 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
ec_msg->result = 0;
len = cros_ec_prepare_tx(ec_dev, ec_msg);
+ if (len < 0)
+ return len;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
reinit_completion(&ec_rpmsg->xfer_ack);
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c
index 8493af0f680e..7360b3ff6e4f 100644
--- a/drivers/platform/chrome/cros_ec_spi.c
+++ b/drivers/platform/chrome/cros_ec_spi.c
@@ -160,7 +160,8 @@ static int receive_n_bytes(struct cros_ec_device *ec_dev, u8 *buf, int n)
struct spi_message msg;
int ret;
- BUG_ON(buf - ec_dev->din + n > ec_dev->din_size);
+ if (buf - ec_dev->din + n > ec_dev->din_size)
+ return -EINVAL;
memset(&trans, 0, sizeof(trans));
trans.cs_change = 1;
@@ -197,7 +198,8 @@ static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev,
unsigned long deadline;
int todo;
- BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
+ if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT)
+ return -EINVAL;
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
@@ -237,7 +239,6 @@ static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev,
* start of our buffer
*/
todo = end - ++ptr;
- BUG_ON(todo < 0 || todo > ec_dev->din_size);
todo = min(todo, need_len);
memmove(ec_dev->din, ptr, todo);
ptr = ec_dev->din + todo;
@@ -305,7 +306,8 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
unsigned long deadline;
int todo;
- BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
+ if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT)
+ return -EINVAL;
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
@@ -345,7 +347,6 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
* start of our buffer
*/
todo = end - ++ptr;
- BUG_ON(todo < 0 || todo > ec_dev->din_size);
todo = min(todo, need_len);
memmove(ec_dev->din, ptr, todo);
ptr = ec_dev->din + todo;
@@ -401,6 +402,8 @@ static int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
unsigned long delay;
len = cros_ec_prepare_tx(ec_dev, ec_msg);
+ if (len < 0)
+ return len;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
@@ -544,6 +547,8 @@ static int do_cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
unsigned long delay;
len = cros_ec_prepare_tx(ec_dev, ec_msg);
+ if (len < 0)
+ return len;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 4bd2752c0823..7cb2e35c4ded 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -1084,6 +1084,9 @@ static int cros_typec_probe(struct platform_device *pdev)
}
ec_dev = dev_get_drvdata(&typec->ec->ec->dev);
+ if (!ec_dev)
+ return -EPROBE_DEFER;
+
typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index c23554531961..8cfa8cfca77e 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -51,10 +51,14 @@
/*
* The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff
* and they tell the kernel that so we have to think of it as two parts.
+ *
+ * Other BIOSes report only the I/O port region spanned by the Microchip
+ * MEC series EC; an attempt to address a larger region may fail.
*/
-#define EC_HOST_CMD_REGION0 0x800
-#define EC_HOST_CMD_REGION1 0x880
-#define EC_HOST_CMD_REGION_SIZE 0x80
+#define EC_HOST_CMD_REGION0 0x800
+#define EC_HOST_CMD_REGION1 0x880
+#define EC_HOST_CMD_REGION_SIZE 0x80
+#define EC_HOST_CMD_MEC_REGION_SIZE 0x8
/* EC command register bit functions */
#define EC_LPC_CMDR_DATA BIT(0) /* Data ready for host to read */
diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h
index df3c78c92ca2..138fd912c808 100644
--- a/include/linux/platform_data/cros_ec_proto.h
+++ b/include/linux/platform_data/cros_ec_proto.h
@@ -76,8 +76,6 @@ struct cros_ec_command {
* struct cros_ec_device - Information about a ChromeOS EC device.
* @phys_name: Name of physical comms layer (e.g. 'i2c-4').
* @dev: Device pointer for physical comms device
- * @was_wake_device: True if this device was set to wake the system from
- * sleep at the last suspend.
* @cros_class: The class structure for this device.
* @cmd_readmem: Direct read of the EC memory-mapped region, if supported.
* @offset: Is within EC_LPC_ADDR_MEMMAP region.
@@ -137,7 +135,6 @@ struct cros_ec_device {
/* These are used by other drivers that want to talk to the EC */
const char *phys_name;
struct device *dev;
- bool was_wake_device;
struct class *cros_class;
int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset,
unsigned int bytes, void *dest);
@@ -216,6 +213,9 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
int cros_ec_check_result(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg);
+int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
+ struct cros_ec_command *msg);
+
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg);