2019-01-29 09:38:18 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
// LPC interface for ChromeOS Embedded Controller
|
|
|
|
//
|
|
|
|
// Copyright (C) 2012-2015 Google, Inc
|
|
|
|
//
|
|
|
|
// This driver uses the ChromeOS 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.
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
#include <linux/acpi.h>
|
2015-02-02 11:26:24 +00:00
|
|
|
#include <linux/dmi.h>
|
|
|
|
#include <linux/delay.h>
|
2015-02-27 05:37:48 +00:00
|
|
|
#include <linux/io.h>
|
2018-10-09 17:56:46 +00:00
|
|
|
#include <linux/interrupt.h>
|
2024-05-21 20:58:40 +00:00
|
|
|
#include <linux/kobject.h>
|
2015-02-02 11:26:24 +00:00
|
|
|
#include <linux/module.h>
|
2019-09-02 09:53:05 +00:00
|
|
|
#include <linux/platform_data/cros_ec_commands.h>
|
|
|
|
#include <linux/platform_data/cros_ec_proto.h>
|
2015-02-02 11:26:24 +00:00
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/printk.h>
|
2024-05-21 19:54:40 +00:00
|
|
|
#include <linux/reboot.h>
|
2018-02-22 21:21:17 +00:00
|
|
|
#include <linux/suspend.h>
|
2015-02-02 11:26:24 +00:00
|
|
|
|
platform/chrome: cros_ec: Match implementation with headers
The 'cros_ec' core driver is the common interface for the cros_ec
transport drivers to do the shared operations to register, unregister,
suspend, resume and handle_event. The interface is provided by including
the header 'include/linux/platform_data/cros_ec_proto.h', however, instead
of have the implementation of these functions in cros_ec_proto.c, it is in
'cros_ec.c', which is a different kernel module. Apart from being a bad
practice, this can induce confusions allowing the users of the cros_ec
protocol to call these functions.
The register, unregister, suspend, resume and handle_event functions
*should* only be called by the different transport drivers (i2c, spi, lpc,
etc.), so make this a bit less confusing by moving these functions from
the public in-kernel space to a private include in platform/chrome, and
then, the interface for cros_ec module and for the cros_ec_proto module is
clean.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Benson Leung <bleung@chromium.org>
2020-01-22 09:07:01 +00:00
|
|
|
#include "cros_ec.h"
|
2019-06-14 21:43:00 +00:00
|
|
|
#include "cros_ec_lpc_mec.h"
|
2018-07-18 16:09:55 +00:00
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
#define DRV_NAME "cros_ec_lpcs"
|
2017-05-16 15:46:48 +00:00
|
|
|
#define ACPI_DRV_NAME "GOOG0004"
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2017-12-01 13:42:21 +00:00
|
|
|
/* True if ACPI device is present */
|
|
|
|
static bool cros_ec_lpc_acpi_device_found;
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/**
|
|
|
|
* struct lpc_driver_ops - LPC driver operations
|
|
|
|
* @read: Copy length bytes from EC address offset into buffer dest. Returns
|
|
|
|
* the 8-bit checksum of all bytes read.
|
|
|
|
* @write: Copy length bytes from buffer msg into EC address offset. Returns
|
|
|
|
* the 8-bit checksum of all bytes written.
|
|
|
|
*/
|
|
|
|
struct lpc_driver_ops {
|
|
|
|
u8 (*read)(unsigned int offset, unsigned int length, u8 *dest);
|
|
|
|
u8 (*write)(unsigned int offset, unsigned int length, const u8 *msg);
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct lpc_driver_ops cros_ec_lpc_ops = { };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A generic instance of the read function of struct lpc_driver_ops, used for
|
|
|
|
* the LPC EC.
|
|
|
|
*/
|
|
|
|
static u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length,
|
|
|
|
u8 *dest)
|
2019-06-14 21:43:00 +00:00
|
|
|
{
|
|
|
|
int sum = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < length; ++i) {
|
|
|
|
dest[i] = inb(offset + i);
|
|
|
|
sum += dest[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return checksum of all bytes read */
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/*
|
|
|
|
* A generic instance of the write function of struct lpc_driver_ops, used for
|
|
|
|
* the LPC EC.
|
|
|
|
*/
|
|
|
|
static u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length,
|
|
|
|
const u8 *msg)
|
2019-06-14 21:43:00 +00:00
|
|
|
{
|
|
|
|
int sum = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < length; ++i) {
|
|
|
|
outb(msg[i], offset + i);
|
|
|
|
sum += msg[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return checksum of all bytes written */
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/*
|
|
|
|
* An instance of the read function of struct lpc_driver_ops, used for the
|
|
|
|
* MEC variant of LPC EC.
|
|
|
|
*/
|
|
|
|
static u8 cros_ec_lpc_mec_read_bytes(unsigned int offset, unsigned int length,
|
|
|
|
u8 *dest)
|
2019-06-14 21:43:00 +00:00
|
|
|
{
|
|
|
|
int in_range = cros_ec_lpc_mec_in_range(offset, length);
|
|
|
|
|
|
|
|
if (in_range < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return in_range ?
|
|
|
|
cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
|
|
|
|
offset - EC_HOST_CMD_REGION0,
|
|
|
|
length, dest) :
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_read_bytes(offset, length, dest);
|
2019-06-14 21:43:00 +00:00
|
|
|
}
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/*
|
|
|
|
* An instance of the write function of struct lpc_driver_ops, used for the
|
|
|
|
* MEC variant of LPC EC.
|
|
|
|
*/
|
|
|
|
static u8 cros_ec_lpc_mec_write_bytes(unsigned int offset, unsigned int length,
|
|
|
|
const u8 *msg)
|
2019-06-14 21:43:00 +00:00
|
|
|
{
|
|
|
|
int in_range = cros_ec_lpc_mec_in_range(offset, length);
|
|
|
|
|
|
|
|
if (in_range < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return in_range ?
|
|
|
|
cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
|
|
|
|
offset - EC_HOST_CMD_REGION0,
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
length, (u8 *)msg) :
|
|
|
|
cros_ec_lpc_write_bytes(offset, length, msg);
|
2019-06-14 21:43:00 +00:00
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
static int ec_response_timed_out(void)
|
|
|
|
{
|
|
|
|
unsigned long one_second = jiffies + HZ;
|
2017-05-16 15:46:48 +00:00
|
|
|
u8 data;
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
usleep_range(200, 300);
|
|
|
|
do {
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
if (!(cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_CMD, 1, &data) &
|
2017-05-16 15:46:48 +00:00
|
|
|
EC_LPC_STATUS_BUSY_MASK))
|
2015-02-02 11:26:24 +00:00
|
|
|
return 0;
|
|
|
|
usleep_range(100, 200);
|
|
|
|
} while (time_before(jiffies, one_second));
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-06-09 11:04:46 +00:00
|
|
|
static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
|
|
|
|
struct cros_ec_command *msg)
|
|
|
|
{
|
|
|
|
struct ec_host_response response;
|
2017-05-16 15:46:48 +00:00
|
|
|
u8 sum;
|
2015-06-09 11:04:46 +00:00
|
|
|
int ret = 0;
|
|
|
|
u8 *dout;
|
|
|
|
|
|
|
|
ret = cros_ec_prepare_tx(ec, msg);
|
2022-11-07 21:59:16 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto done;
|
2015-06-09 11:04:46 +00:00
|
|
|
|
|
|
|
/* Write buffer */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
|
2015-06-09 11:04:46 +00:00
|
|
|
|
|
|
|
/* Here we go */
|
2017-05-16 15:46:48 +00:00
|
|
|
sum = EC_COMMAND_PROTOCOL_3;
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
|
2015-06-09 11:04:46 +00:00
|
|
|
|
|
|
|
if (ec_response_timed_out()) {
|
2022-06-13 16:43:22 +00:00
|
|
|
dev_warn(ec->dev, "EC response timed out\n");
|
2015-06-09 11:04:46 +00:00
|
|
|
ret = -EIO;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check result */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
|
2015-06-09 11:04:46 +00:00
|
|
|
ret = cros_ec_check_result(ec, msg);
|
|
|
|
if (ret)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Read back response */
|
|
|
|
dout = (u8 *)&response;
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
sum = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
|
|
|
|
dout);
|
2015-06-09 11:04:46 +00:00
|
|
|
|
|
|
|
msg->result = response.result;
|
|
|
|
|
|
|
|
if (response.data_len > msg->insize) {
|
|
|
|
dev_err(ec->dev,
|
|
|
|
"packet too long (%d bytes, expected %d)",
|
|
|
|
response.data_len, msg->insize);
|
|
|
|
ret = -EMSGSIZE;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read response and process checksum */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET +
|
|
|
|
sizeof(response), response.data_len,
|
|
|
|
msg->data);
|
2015-06-09 11:04:46 +00:00
|
|
|
|
|
|
|
if (sum) {
|
|
|
|
dev_err(ec->dev,
|
|
|
|
"bad packet checksum %02x\n",
|
|
|
|
response.checksum);
|
|
|
|
ret = -EBADMSG;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return actual amount of data received */
|
|
|
|
ret = response.data_len;
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
|
|
|
|
struct cros_ec_command *msg)
|
|
|
|
{
|
|
|
|
struct ec_lpc_host_args args;
|
2017-05-16 15:46:48 +00:00
|
|
|
u8 sum;
|
2015-02-02 11:26:24 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE ||
|
|
|
|
msg->insize > EC_PROTO2_MAX_PARAM_SIZE) {
|
|
|
|
dev_err(ec->dev,
|
|
|
|
"invalid buffer sizes (out %d, in %d)\n",
|
|
|
|
msg->outsize, msg->insize);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now actually send the command to the EC and get the result */
|
|
|
|
args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
|
|
|
|
args.command_version = msg->version;
|
|
|
|
args.data_size = msg->outsize;
|
|
|
|
|
|
|
|
/* Initialize checksum */
|
2017-05-16 15:46:48 +00:00
|
|
|
sum = msg->command + args.flags + args.command_version + args.data_size;
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
/* Copy data and update checksum */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
sum += cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
|
|
|
|
msg->data);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
/* Finalize checksum and write args */
|
2017-05-16 15:46:48 +00:00
|
|
|
args.checksum = sum;
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
|
|
|
|
(u8 *)&args);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
/* Here we go */
|
2017-05-16 15:46:48 +00:00
|
|
|
sum = msg->command;
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
if (ec_response_timed_out()) {
|
2022-06-13 16:43:22 +00:00
|
|
|
dev_warn(ec->dev, "EC response timed out\n");
|
2015-02-02 11:26:24 +00:00
|
|
|
ret = -EIO;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check result */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
|
2015-06-22 06:27:18 +00:00
|
|
|
ret = cros_ec_check_result(ec, msg);
|
|
|
|
if (ret)
|
2015-02-02 11:26:24 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Read back args */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_ARGS, sizeof(args), (u8 *)&args);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
if (args.data_size > msg->insize) {
|
|
|
|
dev_err(ec->dev,
|
|
|
|
"packet too long (%d bytes, expected %d)",
|
|
|
|
args.data_size, msg->insize);
|
|
|
|
ret = -ENOSPC;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start calculating response checksum */
|
2017-05-16 15:46:48 +00:00
|
|
|
sum = msg->command + args.flags + args.command_version + args.data_size;
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
/* Read response and update checksum */
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PARAM, args.data_size,
|
|
|
|
msg->data);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
|
|
|
/* Verify checksum */
|
2017-05-16 15:46:48 +00:00
|
|
|
if (args.checksum != sum) {
|
2015-02-02 11:26:24 +00:00
|
|
|
dev_err(ec->dev,
|
|
|
|
"bad packet checksum, expected %02x, got %02x\n",
|
2017-05-16 15:46:48 +00:00
|
|
|
args.checksum, sum);
|
2015-02-02 11:26:24 +00:00
|
|
|
ret = -EBADMSG;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return actual amount of data received */
|
|
|
|
ret = args.data_size;
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns num bytes read, or negative on error. Doesn't need locking. */
|
|
|
|
static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
|
|
|
|
unsigned int bytes, void *dest)
|
|
|
|
{
|
|
|
|
int i = offset;
|
|
|
|
char *s = dest;
|
|
|
|
int cnt = 0;
|
|
|
|
|
|
|
|
if (offset >= EC_MEMMAP_SIZE - bytes)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* fixed length */
|
|
|
|
if (bytes) {
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
|
2017-05-16 15:46:48 +00:00
|
|
|
return bytes;
|
2015-02-02 11:26:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* string */
|
|
|
|
for (; i < EC_MEMMAP_SIZE; i++, s++) {
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + i, 1, s);
|
2015-02-02 11:26:24 +00:00
|
|
|
cnt++;
|
|
|
|
if (!*s)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
|
|
|
|
{
|
2024-05-21 20:58:40 +00:00
|
|
|
static const char *env[] = { "ERROR=PANIC", NULL };
|
2017-05-16 15:46:48 +00:00
|
|
|
struct cros_ec_device *ec_dev = data;
|
2019-11-19 12:45:46 +00:00
|
|
|
bool ec_has_more_events;
|
|
|
|
int ret;
|
2017-05-16 15:46:48 +00:00
|
|
|
|
2019-11-19 12:45:46 +00:00
|
|
|
ec_dev->last_event_time = cros_ec_get_time_ns();
|
|
|
|
|
2024-05-21 19:54:39 +00:00
|
|
|
if (value == ACPI_NOTIFY_CROS_EC_PANIC) {
|
|
|
|
dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!");
|
|
|
|
blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev);
|
2024-05-21 20:58:40 +00:00
|
|
|
kobject_uevent_env(&ec_dev->dev->kobj, KOBJ_CHANGE, (char **)env);
|
2024-05-21 20:58:42 +00:00
|
|
|
/* Begin orderly shutdown. EC will force reset after a short period. */
|
|
|
|
hw_protection_shutdown("CrOS EC Panic", -1);
|
2024-05-21 19:54:39 +00:00
|
|
|
/* Do not query for other events after a panic is reported */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-19 12:45:46 +00:00
|
|
|
if (ec_dev->mkbp_event_supported)
|
|
|
|
do {
|
|
|
|
ret = cros_ec_get_next_event(ec_dev, NULL,
|
|
|
|
&ec_has_more_events);
|
|
|
|
if (ret > 0)
|
|
|
|
blocking_notifier_call_chain(
|
|
|
|
&ec_dev->event_notifier, 0,
|
|
|
|
ec_dev);
|
|
|
|
} while (ec_has_more_events);
|
2018-02-22 21:21:17 +00:00
|
|
|
|
|
|
|
if (value == ACPI_NOTIFY_DEVICE_WAKE)
|
|
|
|
pm_system_wakeup();
|
2017-05-16 15:46:48 +00:00
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
static int cros_ec_lpc_probe(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct device *dev = &pdev->dev;
|
2017-05-16 15:46:48 +00:00
|
|
|
struct acpi_device *adev;
|
|
|
|
acpi_status status;
|
2015-02-02 11:26:24 +00:00
|
|
|
struct cros_ec_device *ec_dev;
|
2024-05-21 20:38:20 +00:00
|
|
|
u8 buf[2] = {};
|
2018-10-09 17:56:46 +00:00
|
|
|
int irq, ret;
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2022-11-07 21:56:46 +00:00
|
|
|
/*
|
|
|
|
* 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");
|
2015-02-02 11:26:24 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2024-04-19 17:24:55 +00:00
|
|
|
cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
|
|
|
|
EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/*
|
|
|
|
* Read the mapped ID twice, the first one is assuming the
|
|
|
|
* EC is a Microchip Embedded Controller (MEC) variant, if the
|
|
|
|
* protocol fails, fallback to the non MEC variant and try to
|
|
|
|
* read again the ID.
|
|
|
|
*/
|
|
|
|
cros_ec_lpc_ops.read = cros_ec_lpc_mec_read_bytes;
|
|
|
|
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);
|
2017-05-16 15:46:48 +00:00
|
|
|
if (buf[0] != 'E' || buf[1] != 'C') {
|
2022-11-07 21:56:46 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
platform/chrome: cros_ec_lpc: Choose Microchip EC at runtime
On many boards, communication between the kernel and the Embedded
Controller happens over an LPC bus. In these cases, the kernel config
CONFIG_CROS_EC_LPC is enabled. Some of these LPC boards contain a
Microchip Embedded Controller (MEC) that is different from the regular
EC. On these devices, the same LPC bus is used, but the protocol is
a little different. In these cases, the CONFIG_CROS_EC_LPC_MEC kernel
config is enabled. Currently, the kernel decides at compile-time whether
or not to use the MEC variant, and, when that kernel option is selected
it breaks the other boards. We would like a kind of runtime detection to
avoid this.
This patch adds that detection mechanism by probing the protocol at
runtime, first we assume that a MEC variant is connected, and if the
protocol fails it fallbacks to the regular EC. This adds a bit of
overload because we try to read twice on those LPC boards that doesn't
contain a MEC variant, but is a better solution than having to select the
EC variant at compile-time.
While here also fix the alignment in Kconfig file for this config option
replacing the spaces by tabs.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
Tested-by: Nick Crews <ncrews@chromium.org>
Reviewed-by: Nick Crews <ncrews@chromium.org>
2019-06-14 21:43:01 +00:00
|
|
|
/* 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;
|
|
|
|
cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2,
|
|
|
|
buf);
|
|
|
|
if (buf[0] != 'E' || buf[1] != 'C') {
|
|
|
|
dev_err(dev, "EC ID not detected\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2022-11-07 21:56:46 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2015-02-02 11:26:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
|
|
|
|
if (!ec_dev)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
platform_set_drvdata(pdev, ec_dev);
|
|
|
|
ec_dev->dev = dev;
|
|
|
|
ec_dev->phys_name = dev_name(dev);
|
|
|
|
ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc;
|
2015-06-09 11:04:46 +00:00
|
|
|
ec_dev->pkt_xfer = cros_ec_pkt_xfer_lpc;
|
2015-02-02 11:26:24 +00:00
|
|
|
ec_dev->cmd_readmem = cros_ec_lpc_readmem;
|
2015-06-09 11:04:45 +00:00
|
|
|
ec_dev->din_size = sizeof(struct ec_host_response) +
|
|
|
|
sizeof(struct ec_response_get_protocol_info);
|
|
|
|
ec_dev->dout_size = sizeof(struct ec_host_request);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2018-10-09 17:56:46 +00:00
|
|
|
/*
|
|
|
|
* Some boards do not have an IRQ allotted for cros_ec_lpc,
|
|
|
|
* which makes ENXIO an expected (and safe) scenario.
|
|
|
|
*/
|
2019-11-29 10:22:54 +00:00
|
|
|
irq = platform_get_irq_optional(pdev, 0);
|
2018-10-09 17:56:46 +00:00
|
|
|
if (irq > 0)
|
|
|
|
ec_dev->irq = irq;
|
|
|
|
else if (irq != -ENXIO) {
|
|
|
|
dev_err(dev, "couldn't retrieve IRQ number (%d)\n", irq);
|
|
|
|
return irq;
|
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
ret = cros_ec_register(ec_dev);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dev, "couldn't register ec_dev (%d)\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
/*
|
|
|
|
* Connect a notify handler to process MKBP messages if we have a
|
|
|
|
* companion ACPI device.
|
|
|
|
*/
|
|
|
|
adev = ACPI_COMPANION(dev);
|
|
|
|
if (adev) {
|
|
|
|
status = acpi_install_notify_handler(adev->handle,
|
|
|
|
ACPI_ALL_NOTIFY,
|
|
|
|
cros_ec_lpc_acpi_notify,
|
|
|
|
ec_dev);
|
|
|
|
if (ACPI_FAILURE(status))
|
|
|
|
dev_warn(dev, "Failed to register notifier %08x\n",
|
|
|
|
status);
|
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-04-19 17:24:55 +00:00
|
|
|
static void cros_ec_lpc_remove(struct platform_device *pdev)
|
2015-02-02 11:26:24 +00:00
|
|
|
{
|
2019-09-02 09:53:00 +00:00
|
|
|
struct cros_ec_device *ec_dev = platform_get_drvdata(pdev);
|
2017-05-16 15:46:48 +00:00
|
|
|
struct acpi_device *adev;
|
|
|
|
|
|
|
|
adev = ACPI_COMPANION(&pdev->dev);
|
|
|
|
if (adev)
|
|
|
|
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
|
|
|
|
cros_ec_lpc_acpi_notify);
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2022-06-13 17:05:12 +00:00
|
|
|
cros_ec_unregister(ec_dev);
|
2015-02-02 11:26:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = {
|
|
|
|
{ ACPI_DRV_NAME, 0 },
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(acpi, cros_ec_lpc_acpi_device_ids);
|
|
|
|
|
2017-09-14 09:59:30 +00:00
|
|
|
static const struct dmi_system_id cros_ec_lpc_dmi_table[] __initconst = {
|
2015-02-02 11:26:24 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Today all Chromebooks/boxes ship with Google_* as version and
|
|
|
|
* coreboot as bios vendor. No other systems with this
|
|
|
|
* combination are known to date.
|
|
|
|
*/
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
|
|
|
|
DMI_MATCH(DMI_BIOS_VERSION, "Google_"),
|
|
|
|
},
|
|
|
|
},
|
2018-03-07 13:56:43 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the box is running custom coreboot firmware then the
|
|
|
|
* DMI BIOS version string will not be matched by "Google_",
|
|
|
|
* but the system vendor string will still be matched by
|
|
|
|
* "GOOGLE".
|
|
|
|
*/
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
|
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
|
|
|
},
|
|
|
|
},
|
2015-02-02 11:26:24 +00:00
|
|
|
{
|
|
|
|
/* x86-link, the Chromebook Pixel. */
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
|
|
|
|
},
|
|
|
|
},
|
2015-06-22 06:27:19 +00:00
|
|
|
{
|
|
|
|
/* x86-samus, the Chromebook Pixel 2. */
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
|
|
|
|
},
|
|
|
|
},
|
2015-02-02 11:26:24 +00:00
|
|
|
{
|
|
|
|
/* x86-peppy, the Acer C720 Chromebook. */
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
|
|
|
|
},
|
|
|
|
},
|
2017-12-01 13:42:22 +00:00
|
|
|
{
|
|
|
|
/* x86-glimmer, the Lenovo Thinkpad Yoga 11e. */
|
|
|
|
.matches = {
|
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),
|
|
|
|
},
|
|
|
|
},
|
2022-11-07 21:56:40 +00:00
|
|
|
/* 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"),
|
|
|
|
},
|
|
|
|
},
|
2015-02-02 11:26:24 +00:00
|
|
|
{ /* sentinel */ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table);
|
|
|
|
|
2017-05-16 15:46:48 +00:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2024-05-21 20:58:40 +00:00
|
|
|
static int cros_ec_lpc_prepare(struct device *dev)
|
2017-05-16 15:46:48 +00:00
|
|
|
{
|
|
|
|
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
|
|
|
|
|
|
|
|
return cros_ec_suspend(ec_dev);
|
|
|
|
}
|
|
|
|
|
2024-05-21 20:58:40 +00:00
|
|
|
static void cros_ec_lpc_complete(struct device *dev)
|
2017-05-16 15:46:48 +00:00
|
|
|
{
|
|
|
|
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
|
2024-05-21 20:58:40 +00:00
|
|
|
cros_ec_resume(ec_dev);
|
2017-05-16 15:46:48 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-05-30 08:49:32 +00:00
|
|
|
static const struct dev_pm_ops cros_ec_lpc_pm_ops = {
|
2024-05-21 20:58:40 +00:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
.prepare = cros_ec_lpc_prepare,
|
|
|
|
.complete = cros_ec_lpc_complete
|
|
|
|
#endif
|
2017-05-16 15:46:48 +00:00
|
|
|
};
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
static struct platform_driver cros_ec_lpc_driver = {
|
|
|
|
.driver = {
|
|
|
|
.name = DRV_NAME,
|
2017-05-16 15:46:48 +00:00
|
|
|
.acpi_match_table = cros_ec_lpc_acpi_device_ids,
|
2017-05-16 15:46:48 +00:00
|
|
|
.pm = &cros_ec_lpc_pm_ops,
|
platform/chrome: cros_ec_lpc: Force synchronous probe
JIRA: https://issues.redhat.com/browse/RHEL-33550
commit ca821c1f4ec11d6181da58118d158a015160106d
Author: Brian Norris <briannorris@chromium.org>
Date: Mon, 14 Nov 2022 10:26:46 +0000
This reverts commit bd88b965ae8c ("platform/chrome: cros_ec_lpc: Mark
PROBE_PREFER_ASYNCHRONOUS"), and then some.
It has been reported that there are issues with 'cros-ec-keyb' devices
that are children of this. As noted in the initial patch for its ACPI
support (commit ba0f32141bc5 ("Input: cros_ec_keyb - handle x86
detachable/convertible Chromebooks")), it's possible to probe an ACPI
child device before its parent is probed -- hence the need for
EPROBE_DEFER. Unfortunately, poking your parent's dev_get_drvdata()
isn't safe with asynchronous probe, as there's no locking, and the
ordering is all wrong anyway (drvdata is set before the device is
*really* ready).
Because this parent/child relationship has known issues, let's go the
other direction and force synchronous probe, until we resolve the
issues.
Possible solutions involve adding device links, so we ensure the child
doesn't probe before the parent is done; or perhaps some other larger
refactoring (auxiliary bus?). But that might take a little more effort
and review, as there are many other potential sub-devices of
cros_ec_lpc that could need patching.
Note that we don't have the same problem for non-ACPI cros-ec hosts,
like cros-ec-spi (commit 015e4b05c377 ("platform/chrome: cros_ec_spi:
Set PROBE_PREFER_ASYNCHRONOUS")), because its sub-devices aren't created
until cros_ec_register(), or they don't exist at all (e.g., FPMCU uses).
Fixes: bd88b965ae8c ("platform/chrome: cros_ec_lpc: Mark PROBE_PREFER_ASYNCHRONOUS")
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Link: https://lore.kernel.org/r/20221111231302.3458191-1-briannorris@chromium.org
Signed-off-by: Mark Langsdorf <mlangsdo@redhat.com>
2024-05-21 19:46:11 +00:00
|
|
|
/*
|
|
|
|
* ACPI child devices may probe before us, and they racily
|
|
|
|
* check our drvdata pointer. Force synchronous probe until
|
|
|
|
* those races are resolved.
|
|
|
|
*/
|
|
|
|
.probe_type = PROBE_FORCE_SYNCHRONOUS,
|
2015-02-02 11:26:24 +00:00
|
|
|
},
|
|
|
|
.probe = cros_ec_lpc_probe,
|
2024-04-19 17:24:55 +00:00
|
|
|
.remove_new = cros_ec_lpc_remove,
|
2015-02-02 11:26:24 +00:00
|
|
|
};
|
|
|
|
|
2017-12-01 13:42:21 +00:00
|
|
|
static struct platform_device cros_ec_lpc_device = {
|
|
|
|
.name = DRV_NAME
|
|
|
|
};
|
|
|
|
|
|
|
|
static acpi_status cros_ec_lpc_parse_device(acpi_handle handle, u32 level,
|
|
|
|
void *context, void **retval)
|
|
|
|
{
|
|
|
|
*(bool *)context = true;
|
|
|
|
return AE_CTRL_TERMINATE;
|
|
|
|
}
|
|
|
|
|
2015-02-02 11:26:24 +00:00
|
|
|
static int __init cros_ec_lpc_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
2017-12-01 13:42:21 +00:00
|
|
|
acpi_status status;
|
2015-02-02 11:26:24 +00:00
|
|
|
|
2018-05-22 23:08:41 +00:00
|
|
|
status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device,
|
|
|
|
&cros_ec_lpc_acpi_device_found, NULL);
|
|
|
|
if (ACPI_FAILURE(status))
|
|
|
|
pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME);
|
|
|
|
|
|
|
|
if (!cros_ec_lpc_acpi_device_found &&
|
|
|
|
!dmi_check_system(cros_ec_lpc_dmi_table)) {
|
2015-02-02 11:26:24 +00:00
|
|
|
pr_err(DRV_NAME ": unsupported system.\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Register the driver */
|
|
|
|
ret = platform_driver_register(&cros_ec_lpc_driver);
|
|
|
|
if (ret) {
|
|
|
|
pr_err(DRV_NAME ": can't register driver: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-12-01 13:42:21 +00:00
|
|
|
if (!cros_ec_lpc_acpi_device_found) {
|
|
|
|
/* Register the device, and it'll get hooked up automatically */
|
|
|
|
ret = platform_device_register(&cros_ec_lpc_device);
|
|
|
|
if (ret) {
|
|
|
|
pr_err(DRV_NAME ": can't register device: %d\n", ret);
|
|
|
|
platform_driver_unregister(&cros_ec_lpc_driver);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2015-02-02 11:26:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit cros_ec_lpc_exit(void)
|
|
|
|
{
|
2017-12-01 13:42:21 +00:00
|
|
|
if (!cros_ec_lpc_acpi_device_found)
|
|
|
|
platform_device_unregister(&cros_ec_lpc_device);
|
2015-02-02 11:26:24 +00:00
|
|
|
platform_driver_unregister(&cros_ec_lpc_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(cros_ec_lpc_init);
|
|
|
|
module_exit(cros_ec_lpc_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("ChromeOS EC LPC driver");
|