| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // LPC interface for ChromeOS Embedded Controller |
| 3 | // |
| 4 | // Copyright (C) 2012-2015 Google, Inc |
| 5 | // |
| 6 | // This driver uses the ChromeOS EC byte-level message-based protocol for |
| 7 | // communicating the keyboard state (which keys are pressed) from a keyboard EC |
| 8 | // to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, |
| 9 | // but everything else (including deghosting) is done here. The main |
| 10 | // motivation for this is to keep the EC firmware as simple as possible, since |
| 11 | // it cannot be easily upgraded and EC flash/IRAM space is relatively |
| 12 | // expensive. |
| 13 | |
| 14 | #include <linux/acpi.h> |
| 15 | #include <linux/dmi.h> |
| 16 | #include <linux/delay.h> |
| 17 | #include <linux/io.h> |
| 18 | #include <linux/interrupt.h> |
| 19 | #include <linux/kobject.h> |
| 20 | #include <linux/module.h> |
| 21 | #include <linux/platform_data/cros_ec_commands.h> |
| 22 | #include <linux/platform_data/cros_ec_proto.h> |
| 23 | #include <linux/platform_device.h> |
| 24 | #include <linux/printk.h> |
| 25 | #include <linux/reboot.h> |
| 26 | #include <linux/suspend.h> |
| 27 | |
| 28 | #include "cros_ec.h" |
| 29 | #include "cros_ec_lpc_mec.h" |
| 30 | |
| 31 | #define DRV_NAME "cros_ec_lpcs" |
| 32 | #define ACPI_DRV_NAME "GOOG0004" |
| 33 | #define FRMW_ACPI_DRV_NAME "FRMWC004" |
| 34 | |
| 35 | /* True if ACPI device is present */ |
| 36 | static bool cros_ec_lpc_acpi_device_found; |
| 37 | |
| 38 | /* |
| 39 | * Indicates that lpc_driver_data.quirk_mmio_memory_base should |
| 40 | * be used as the base port for EC mapped memory. |
| 41 | */ |
| 42 | #define CROS_EC_LPC_QUIRK_REMAP_MEMORY BIT(0) |
| 43 | /* |
| 44 | * Indicates that lpc_driver_data.quirk_acpi_id should be used to find |
| 45 | * the ACPI device. |
| 46 | */ |
| 47 | #define CROS_EC_LPC_QUIRK_ACPI_ID BIT(1) |
| 48 | /* |
| 49 | * Indicates that lpc_driver_data.quirk_aml_mutex_name should be used |
| 50 | * to find an AML mutex to protect access to Microchip EC. |
| 51 | */ |
| 52 | #define CROS_EC_LPC_QUIRK_AML_MUTEX BIT(2) |
| 53 | |
| 54 | /** |
| 55 | * struct lpc_driver_data - driver data attached to a DMI device ID to indicate |
| 56 | * hardware quirks. |
| 57 | * @quirks: a bitfield composed of quirks from CROS_EC_LPC_QUIRK_* |
| 58 | * @quirk_mmio_memory_base: The first I/O port addressing EC mapped memory (used |
| 59 | * when quirk ...REMAP_MEMORY is set.) |
| 60 | * @quirk_acpi_id: An ACPI HID to be used to find the ACPI device. |
| 61 | * @quirk_aml_mutex_name: The name of an AML mutex to be used to protect access |
| 62 | * to Microchip EC. |
| 63 | */ |
| 64 | struct lpc_driver_data { |
| 65 | u32 quirks; |
| 66 | u16 quirk_mmio_memory_base; |
| 67 | const char *quirk_acpi_id; |
| 68 | const char *quirk_aml_mutex_name; |
| 69 | }; |
| 70 | |
| 71 | /** |
| 72 | * struct cros_ec_lpc - LPC device-specific data |
| 73 | * @mmio_memory_base: The first I/O port addressing EC mapped memory. |
| 74 | * @base: For EC supporting memory mapping, base address of the mapped region. |
| 75 | * @mem32: Information about the memory mapped register region, if present. |
| 76 | * @read: Copy length bytes from EC address offset into buffer dest. |
| 77 | * Returns a negative error code on error, or the 8-bit checksum |
| 78 | * of all bytes read. |
| 79 | * @write: Copy length bytes from buffer msg into EC address offset. |
| 80 | * Returns a negative error code on error, or the 8-bit checksum |
| 81 | * of all bytes written. |
| 82 | */ |
| 83 | struct cros_ec_lpc { |
| 84 | u16 mmio_memory_base; |
| 85 | void __iomem *base; |
| 86 | struct acpi_resource_fixed_memory32 mem32; |
| 87 | int (*read)(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 88 | unsigned int length, u8 *dest); |
| 89 | int (*write)(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 90 | unsigned int length, const u8 *msg); |
| 91 | }; |
| 92 | |
| 93 | /* |
| 94 | * A generic instance of the read function of struct lpc_driver_ops, used for |
| 95 | * the LPC EC. |
| 96 | */ |
| 97 | static int cros_ec_lpc_read_bytes(struct cros_ec_lpc *_, unsigned int offset, unsigned int length, |
| 98 | u8 *dest) |
| 99 | { |
| 100 | u8 sum = 0; |
| 101 | int i; |
| 102 | |
| 103 | for (i = 0; i < length; ++i) { |
| 104 | dest[i] = inb(port: offset + i); |
| 105 | sum += dest[i]; |
| 106 | } |
| 107 | |
| 108 | /* Return checksum of all bytes read */ |
| 109 | return sum; |
| 110 | } |
| 111 | |
| 112 | /* |
| 113 | * A generic instance of the write function of struct lpc_driver_ops, used for |
| 114 | * the LPC EC. |
| 115 | */ |
| 116 | static int cros_ec_lpc_write_bytes(struct cros_ec_lpc *_, unsigned int offset, unsigned int length, |
| 117 | const u8 *msg) |
| 118 | { |
| 119 | u8 sum = 0; |
| 120 | int i; |
| 121 | |
| 122 | for (i = 0; i < length; ++i) { |
| 123 | outb(value: msg[i], port: offset + i); |
| 124 | sum += msg[i]; |
| 125 | } |
| 126 | |
| 127 | /* Return checksum of all bytes written */ |
| 128 | return sum; |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | * An instance of the read function of struct lpc_driver_ops, used for the |
| 133 | * MEC variant of LPC EC. |
| 134 | */ |
| 135 | static int cros_ec_lpc_mec_read_bytes(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 136 | unsigned int length, u8 *dest) |
| 137 | { |
| 138 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
| 139 | |
| 140 | if (in_range < 0) |
| 141 | return in_range; |
| 142 | |
| 143 | return in_range ? |
| 144 | cros_ec_lpc_io_bytes_mec(io_type: MEC_IO_READ, |
| 145 | offset: offset - EC_HOST_CMD_REGION0, |
| 146 | length, buf: dest) : |
| 147 | cros_ec_lpc_read_bytes(: ec_lpc, offset, length, dest); |
| 148 | } |
| 149 | |
| 150 | /* |
| 151 | * An instance of the write function of struct lpc_driver_ops, used for the |
| 152 | * MEC variant of LPC EC. |
| 153 | */ |
| 154 | static int cros_ec_lpc_mec_write_bytes(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 155 | unsigned int length, const u8 *msg) |
| 156 | { |
| 157 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
| 158 | |
| 159 | if (in_range < 0) |
| 160 | return in_range; |
| 161 | |
| 162 | return in_range ? |
| 163 | cros_ec_lpc_io_bytes_mec(io_type: MEC_IO_WRITE, |
| 164 | offset: offset - EC_HOST_CMD_REGION0, |
| 165 | length, buf: (u8 *)msg) : |
| 166 | cros_ec_lpc_write_bytes(: ec_lpc, offset, length, msg); |
| 167 | } |
| 168 | |
| 169 | static int cros_ec_lpc_direct_read(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 170 | unsigned int length, u8 *dest) |
| 171 | { |
| 172 | int sum = 0; |
| 173 | int i; |
| 174 | |
| 175 | if (offset < EC_HOST_CMD_REGION0 || offset > EC_LPC_ADDR_MEMMAP + |
| 176 | EC_MEMMAP_SIZE) { |
| 177 | return cros_ec_lpc_read_bytes(: ec_lpc, offset, length, dest); |
| 178 | } |
| 179 | |
| 180 | for (i = 0; i < length; ++i) { |
| 181 | dest[i] = readb(addr: ec_lpc->base + offset - EC_HOST_CMD_REGION0 + i); |
| 182 | sum += dest[i]; |
| 183 | } |
| 184 | |
| 185 | /* Return checksum of all bytes read */ |
| 186 | return sum; |
| 187 | } |
| 188 | |
| 189 | static int cros_ec_lpc_direct_write(struct cros_ec_lpc *ec_lpc, unsigned int offset, |
| 190 | unsigned int length, const u8 *msg) |
| 191 | { |
| 192 | int sum = 0; |
| 193 | int i; |
| 194 | |
| 195 | if (offset < EC_HOST_CMD_REGION0 || offset > EC_LPC_ADDR_MEMMAP + |
| 196 | EC_MEMMAP_SIZE) { |
| 197 | return cros_ec_lpc_write_bytes(: ec_lpc, offset, length, msg); |
| 198 | } |
| 199 | |
| 200 | for (i = 0; i < length; ++i) { |
| 201 | writeb(val: msg[i], addr: ec_lpc->base + offset - EC_HOST_CMD_REGION0 + i); |
| 202 | sum += msg[i]; |
| 203 | } |
| 204 | |
| 205 | /* Return checksum of all bytes written */ |
| 206 | return sum; |
| 207 | } |
| 208 | |
| 209 | static int ec_response_timed_out(struct cros_ec_lpc *ec_lpc) |
| 210 | { |
| 211 | unsigned long one_second = jiffies + HZ; |
| 212 | u8 data; |
| 213 | int ret; |
| 214 | |
| 215 | usleep_range(min: 200, max: 300); |
| 216 | do { |
| 217 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_CMD, 1, &data); |
| 218 | if (ret < 0) |
| 219 | return ret; |
| 220 | if (!(data & EC_LPC_STATUS_BUSY_MASK)) |
| 221 | return 0; |
| 222 | usleep_range(min: 100, max: 200); |
| 223 | } while (time_before(jiffies, one_second)); |
| 224 | |
| 225 | return 1; |
| 226 | } |
| 227 | |
| 228 | static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, |
| 229 | struct cros_ec_command *msg) |
| 230 | { |
| 231 | struct cros_ec_lpc *ec_lpc = ec->priv; |
| 232 | struct ec_host_response response; |
| 233 | u8 sum; |
| 234 | int ret = 0; |
| 235 | u8 *dout; |
| 236 | |
| 237 | ret = cros_ec_prepare_tx(ec_dev: ec, msg); |
| 238 | if (ret < 0) |
| 239 | goto done; |
| 240 | |
| 241 | /* Write buffer */ |
| 242 | ret = ec_lpc->write(ec_lpc, EC_LPC_ADDR_HOST_PACKET, ret, ec->dout); |
| 243 | if (ret < 0) |
| 244 | goto done; |
| 245 | |
| 246 | /* Here we go */ |
| 247 | sum = EC_COMMAND_PROTOCOL_3; |
| 248 | ret = ec_lpc->write(ec_lpc, EC_LPC_ADDR_HOST_CMD, 1, &sum); |
| 249 | if (ret < 0) |
| 250 | goto done; |
| 251 | |
| 252 | ret = ec_response_timed_out(ec_lpc); |
| 253 | if (ret < 0) |
| 254 | goto done; |
| 255 | if (ret) { |
| 256 | dev_warn(ec->dev, "EC response timed out\n" ); |
| 257 | ret = -EIO; |
| 258 | goto done; |
| 259 | } |
| 260 | |
| 261 | /* Check result */ |
| 262 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_DATA, 1, &sum); |
| 263 | if (ret < 0) |
| 264 | goto done; |
| 265 | msg->result = ret; |
| 266 | ret = cros_ec_check_result(ec_dev: ec, msg); |
| 267 | if (ret) |
| 268 | goto done; |
| 269 | |
| 270 | /* Read back response */ |
| 271 | dout = (u8 *)&response; |
| 272 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_PACKET, sizeof(response), |
| 273 | dout); |
| 274 | if (ret < 0) |
| 275 | goto done; |
| 276 | sum = ret; |
| 277 | |
| 278 | msg->result = response.result; |
| 279 | |
| 280 | if (response.data_len > msg->insize) { |
| 281 | dev_err(ec->dev, |
| 282 | "packet too long (%d bytes, expected %d)" , |
| 283 | response.data_len, msg->insize); |
| 284 | ret = -EMSGSIZE; |
| 285 | goto done; |
| 286 | } |
| 287 | |
| 288 | /* Read response and process checksum */ |
| 289 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_PACKET + |
| 290 | sizeof(response), response.data_len, |
| 291 | msg->data); |
| 292 | if (ret < 0) |
| 293 | goto done; |
| 294 | sum += ret; |
| 295 | |
| 296 | if (sum) { |
| 297 | dev_err(ec->dev, |
| 298 | "bad packet checksum %02x\n" , |
| 299 | response.checksum); |
| 300 | ret = -EBADMSG; |
| 301 | goto done; |
| 302 | } |
| 303 | |
| 304 | /* Return actual amount of data received */ |
| 305 | ret = response.data_len; |
| 306 | done: |
| 307 | return ret; |
| 308 | } |
| 309 | |
| 310 | static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, |
| 311 | struct cros_ec_command *msg) |
| 312 | { |
| 313 | struct cros_ec_lpc *ec_lpc = ec->priv; |
| 314 | struct ec_lpc_host_args args; |
| 315 | u8 sum; |
| 316 | int ret = 0; |
| 317 | |
| 318 | if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE || |
| 319 | msg->insize > EC_PROTO2_MAX_PARAM_SIZE) { |
| 320 | dev_err(ec->dev, |
| 321 | "invalid buffer sizes (out %d, in %d)\n" , |
| 322 | msg->outsize, msg->insize); |
| 323 | return -EINVAL; |
| 324 | } |
| 325 | |
| 326 | /* Now actually send the command to the EC and get the result */ |
| 327 | args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; |
| 328 | args.command_version = msg->version; |
| 329 | args.data_size = msg->outsize; |
| 330 | |
| 331 | /* Initialize checksum */ |
| 332 | sum = msg->command + args.flags + args.command_version + args.data_size; |
| 333 | |
| 334 | /* Copy data and update checksum */ |
| 335 | ret = ec_lpc->write(ec_lpc, EC_LPC_ADDR_HOST_PARAM, msg->outsize, |
| 336 | msg->data); |
| 337 | if (ret < 0) |
| 338 | goto done; |
| 339 | sum += ret; |
| 340 | |
| 341 | /* Finalize checksum and write args */ |
| 342 | args.checksum = sum; |
| 343 | ret = ec_lpc->write(ec_lpc, EC_LPC_ADDR_HOST_ARGS, sizeof(args), |
| 344 | (u8 *)&args); |
| 345 | if (ret < 0) |
| 346 | goto done; |
| 347 | |
| 348 | /* Here we go */ |
| 349 | sum = msg->command; |
| 350 | ret = ec_lpc->write(ec_lpc, EC_LPC_ADDR_HOST_CMD, 1, &sum); |
| 351 | if (ret < 0) |
| 352 | goto done; |
| 353 | |
| 354 | ret = ec_response_timed_out(ec_lpc); |
| 355 | if (ret < 0) |
| 356 | goto done; |
| 357 | if (ret) { |
| 358 | dev_warn(ec->dev, "EC response timed out\n" ); |
| 359 | ret = -EIO; |
| 360 | goto done; |
| 361 | } |
| 362 | |
| 363 | /* Check result */ |
| 364 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_DATA, 1, &sum); |
| 365 | if (ret < 0) |
| 366 | goto done; |
| 367 | msg->result = ret; |
| 368 | ret = cros_ec_check_result(ec_dev: ec, msg); |
| 369 | if (ret) |
| 370 | goto done; |
| 371 | |
| 372 | /* Read back args */ |
| 373 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_ARGS, sizeof(args), (u8 *)&args); |
| 374 | if (ret < 0) |
| 375 | goto done; |
| 376 | |
| 377 | if (args.data_size > msg->insize) { |
| 378 | dev_err(ec->dev, |
| 379 | "packet too long (%d bytes, expected %d)" , |
| 380 | args.data_size, msg->insize); |
| 381 | ret = -ENOSPC; |
| 382 | goto done; |
| 383 | } |
| 384 | |
| 385 | /* Start calculating response checksum */ |
| 386 | sum = msg->command + args.flags + args.command_version + args.data_size; |
| 387 | |
| 388 | /* Read response and update checksum */ |
| 389 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_HOST_PARAM, args.data_size, |
| 390 | msg->data); |
| 391 | if (ret < 0) |
| 392 | goto done; |
| 393 | sum += ret; |
| 394 | |
| 395 | /* Verify checksum */ |
| 396 | if (args.checksum != sum) { |
| 397 | dev_err(ec->dev, |
| 398 | "bad packet checksum, expected %02x, got %02x\n" , |
| 399 | args.checksum, sum); |
| 400 | ret = -EBADMSG; |
| 401 | goto done; |
| 402 | } |
| 403 | |
| 404 | /* Return actual amount of data received */ |
| 405 | ret = args.data_size; |
| 406 | done: |
| 407 | return ret; |
| 408 | } |
| 409 | |
| 410 | /* Returns num bytes read, or negative on error. Doesn't need locking. */ |
| 411 | static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset, |
| 412 | unsigned int bytes, void *dest) |
| 413 | { |
| 414 | struct cros_ec_lpc *ec_lpc = ec->priv; |
| 415 | int i = offset; |
| 416 | char *s = dest; |
| 417 | int cnt = 0; |
| 418 | int ret; |
| 419 | |
| 420 | if (offset >= EC_MEMMAP_SIZE - bytes) |
| 421 | return -EINVAL; |
| 422 | |
| 423 | /* fixed length */ |
| 424 | if (bytes) { |
| 425 | ret = ec_lpc->read(ec_lpc, ec_lpc->mmio_memory_base + offset, bytes, s); |
| 426 | if (ret < 0) |
| 427 | return ret; |
| 428 | return bytes; |
| 429 | } |
| 430 | |
| 431 | /* string */ |
| 432 | for (; i < EC_MEMMAP_SIZE; i++, s++) { |
| 433 | ret = ec_lpc->read(ec_lpc, ec_lpc->mmio_memory_base + i, 1, s); |
| 434 | if (ret < 0) |
| 435 | return ret; |
| 436 | cnt++; |
| 437 | if (!*s) |
| 438 | break; |
| 439 | } |
| 440 | |
| 441 | return cnt; |
| 442 | } |
| 443 | |
| 444 | static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data) |
| 445 | { |
| 446 | static const char *env[] = { "ERROR=PANIC" , NULL }; |
| 447 | struct cros_ec_device *ec_dev = data; |
| 448 | bool ec_has_more_events; |
| 449 | int ret; |
| 450 | |
| 451 | ec_dev->last_event_time = cros_ec_get_time_ns(); |
| 452 | |
| 453 | if (value == ACPI_NOTIFY_CROS_EC_PANIC) { |
| 454 | dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!" ); |
| 455 | blocking_notifier_call_chain(nh: &ec_dev->panic_notifier, val: 0, v: ec_dev); |
| 456 | kobject_uevent_env(kobj: &ec_dev->dev->kobj, action: KOBJ_CHANGE, envp: (char **)env); |
| 457 | /* Begin orderly shutdown. EC will force reset after a short period. */ |
| 458 | __hw_protection_trigger(reason: "CrOS EC Panic" , ms_until_forced: -1, action: HWPROT_ACT_SHUTDOWN); |
| 459 | /* Do not query for other events after a panic is reported */ |
| 460 | return; |
| 461 | } |
| 462 | |
| 463 | if (value == ACPI_NOTIFY_CROS_EC_MKBP && ec_dev->mkbp_event_supported) |
| 464 | do { |
| 465 | ret = cros_ec_get_next_event(ec_dev, NULL, |
| 466 | has_more_events: &ec_has_more_events); |
| 467 | if (ret > 0) |
| 468 | blocking_notifier_call_chain( |
| 469 | nh: &ec_dev->event_notifier, val: 0, |
| 470 | v: ec_dev); |
| 471 | } while (ec_has_more_events); |
| 472 | |
| 473 | if (value == ACPI_NOTIFY_DEVICE_WAKE) |
| 474 | pm_system_wakeup(); |
| 475 | } |
| 476 | |
| 477 | static acpi_status cros_ec_lpc_parse_device(acpi_handle handle, u32 level, |
| 478 | void *context, void **retval) |
| 479 | { |
| 480 | *(struct acpi_device **)context = acpi_fetch_acpi_dev(handle); |
| 481 | return AE_CTRL_TERMINATE; |
| 482 | } |
| 483 | |
| 484 | static struct acpi_device *cros_ec_lpc_get_device(const char *id) |
| 485 | { |
| 486 | struct acpi_device *adev = NULL; |
| 487 | acpi_status status = acpi_get_devices(HID: id, user_function: cros_ec_lpc_parse_device, |
| 488 | context: &adev, NULL); |
| 489 | if (ACPI_FAILURE(status)) { |
| 490 | pr_warn(DRV_NAME ": Looking for %s failed\n" , id); |
| 491 | return NULL; |
| 492 | } |
| 493 | |
| 494 | return adev; |
| 495 | } |
| 496 | |
| 497 | static acpi_status cros_ec_lpc_resources(struct acpi_resource *res, void *data) |
| 498 | { |
| 499 | struct cros_ec_lpc *ec_lpc = data; |
| 500 | |
| 501 | switch (res->type) { |
| 502 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
| 503 | ec_lpc->mem32 = res->data.fixed_memory32; |
| 504 | break; |
| 505 | default: |
| 506 | break; |
| 507 | } |
| 508 | return AE_OK; |
| 509 | } |
| 510 | |
| 511 | static int cros_ec_lpc_probe(struct platform_device *pdev) |
| 512 | { |
| 513 | struct device *dev = &pdev->dev; |
| 514 | struct acpi_device *adev; |
| 515 | acpi_status status; |
| 516 | struct cros_ec_device *ec_dev; |
| 517 | struct cros_ec_lpc *ec_lpc; |
| 518 | const struct lpc_driver_data *driver_data; |
| 519 | u8 buf[2] = {}; |
| 520 | int irq, ret; |
| 521 | u32 quirks; |
| 522 | |
| 523 | ec_lpc = devm_kzalloc(dev, size: sizeof(*ec_lpc), GFP_KERNEL); |
| 524 | if (!ec_lpc) |
| 525 | return -ENOMEM; |
| 526 | |
| 527 | ec_lpc->mmio_memory_base = EC_LPC_ADDR_MEMMAP; |
| 528 | |
| 529 | driver_data = platform_get_drvdata(pdev); |
| 530 | if (!driver_data) |
| 531 | driver_data = acpi_device_get_match_data(dev); |
| 532 | |
| 533 | if (driver_data) { |
| 534 | quirks = driver_data->quirks; |
| 535 | |
| 536 | if (quirks) |
| 537 | dev_info(dev, "loaded with quirks %8.08x\n" , quirks); |
| 538 | |
| 539 | if (quirks & CROS_EC_LPC_QUIRK_REMAP_MEMORY) |
| 540 | ec_lpc->mmio_memory_base = driver_data->quirk_mmio_memory_base; |
| 541 | |
| 542 | if (quirks & CROS_EC_LPC_QUIRK_ACPI_ID) { |
| 543 | adev = cros_ec_lpc_get_device(id: driver_data->quirk_acpi_id); |
| 544 | if (!adev) { |
| 545 | dev_err(dev, "failed to get ACPI device '%s'" , |
| 546 | driver_data->quirk_acpi_id); |
| 547 | return -ENODEV; |
| 548 | } |
| 549 | ACPI_COMPANION_SET(dev, adev); |
| 550 | } |
| 551 | |
| 552 | if (quirks & CROS_EC_LPC_QUIRK_AML_MUTEX) { |
| 553 | const char *name = driver_data->quirk_aml_mutex_name; |
| 554 | ret = cros_ec_lpc_mec_acpi_mutex(ACPI_COMPANION(dev), pathname: name); |
| 555 | if (ret) { |
| 556 | dev_err(dev, "failed to get AML mutex '%s'" , name); |
| 557 | return ret; |
| 558 | } |
| 559 | dev_info(dev, "got AML mutex '%s'" , name); |
| 560 | } |
| 561 | } |
| 562 | adev = ACPI_COMPANION(dev); |
| 563 | if (adev) { |
| 564 | /* |
| 565 | * Retrieve the resource information in the CRS register, if available. |
| 566 | */ |
| 567 | status = acpi_walk_resources(device: adev->handle, METHOD_NAME__CRS, |
| 568 | user_function: cros_ec_lpc_resources, context: ec_lpc); |
| 569 | if (ACPI_SUCCESS(status) && ec_lpc->mem32.address_length) { |
| 570 | ec_lpc->base = devm_ioremap(dev, |
| 571 | offset: ec_lpc->mem32.address, |
| 572 | size: ec_lpc->mem32.address_length); |
| 573 | if (!ec_lpc->base) |
| 574 | return -EINVAL; |
| 575 | |
| 576 | ec_lpc->read = cros_ec_lpc_direct_read; |
| 577 | ec_lpc->write = cros_ec_lpc_direct_write; |
| 578 | } |
| 579 | } |
| 580 | if (!ec_lpc->read) { |
| 581 | /* |
| 582 | * The Framework Laptop (and possibly other non-ChromeOS devices) |
| 583 | * only exposes the eight I/O ports that are required for the Microchip EC. |
| 584 | * Requesting a larger reservation will fail. |
| 585 | */ |
| 586 | if (!devm_request_region(dev, EC_HOST_CMD_REGION0, |
| 587 | EC_HOST_CMD_MEC_REGION_SIZE, dev_name(dev))) { |
| 588 | dev_err(dev, "couldn't reserve MEC region\n" ); |
| 589 | return -EBUSY; |
| 590 | } |
| 591 | |
| 592 | cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0, |
| 593 | EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE); |
| 594 | |
| 595 | /* |
| 596 | * Read the mapped ID twice, the first one is assuming the |
| 597 | * EC is a Microchip Embedded Controller (MEC) variant, if the |
| 598 | * protocol fails, fallback to the non MEC variant and try to |
| 599 | * read again the ID. |
| 600 | */ |
| 601 | ec_lpc->read = cros_ec_lpc_mec_read_bytes; |
| 602 | ec_lpc->write = cros_ec_lpc_mec_write_bytes; |
| 603 | } |
| 604 | ret = ec_lpc->read(ec_lpc, EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf); |
| 605 | if (ret < 0) |
| 606 | return ret; |
| 607 | if (buf[0] != 'E' || buf[1] != 'C') { |
| 608 | if (!devm_request_region(dev, ec_lpc->mmio_memory_base, EC_MEMMAP_SIZE, |
| 609 | dev_name(dev))) { |
| 610 | dev_err(dev, "couldn't reserve memmap region\n" ); |
| 611 | return -EBUSY; |
| 612 | } |
| 613 | |
| 614 | /* Re-assign read/write operations for the non MEC variant */ |
| 615 | ec_lpc->read = cros_ec_lpc_read_bytes; |
| 616 | ec_lpc->write = cros_ec_lpc_write_bytes; |
| 617 | ret = ec_lpc->read(ec_lpc, ec_lpc->mmio_memory_base + EC_MEMMAP_ID, 2, |
| 618 | buf); |
| 619 | if (ret < 0) |
| 620 | return ret; |
| 621 | if (buf[0] != 'E' || buf[1] != 'C') { |
| 622 | dev_err(dev, "EC ID not detected\n" ); |
| 623 | return -ENODEV; |
| 624 | } |
| 625 | |
| 626 | /* Reserve the remaining I/O ports required by the non-MEC protocol. */ |
| 627 | if (!devm_request_region(dev, EC_HOST_CMD_REGION0 + EC_HOST_CMD_MEC_REGION_SIZE, |
| 628 | EC_HOST_CMD_REGION_SIZE - EC_HOST_CMD_MEC_REGION_SIZE, |
| 629 | dev_name(dev))) { |
| 630 | dev_err(dev, "couldn't reserve remainder of region0\n" ); |
| 631 | return -EBUSY; |
| 632 | } |
| 633 | if (!devm_request_region(dev, EC_HOST_CMD_REGION1, |
| 634 | EC_HOST_CMD_REGION_SIZE, dev_name(dev))) { |
| 635 | dev_err(dev, "couldn't reserve region1\n" ); |
| 636 | return -EBUSY; |
| 637 | } |
| 638 | } |
| 639 | |
| 640 | ec_dev = cros_ec_device_alloc(dev); |
| 641 | if (!ec_dev) |
| 642 | return -ENOMEM; |
| 643 | |
| 644 | platform_set_drvdata(pdev, data: ec_dev); |
| 645 | ec_dev->phys_name = dev_name(dev); |
| 646 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc; |
| 647 | ec_dev->pkt_xfer = cros_ec_pkt_xfer_lpc; |
| 648 | ec_dev->cmd_readmem = cros_ec_lpc_readmem; |
| 649 | ec_dev->priv = ec_lpc; |
| 650 | |
| 651 | /* |
| 652 | * Some boards do not have an IRQ allotted for cros_ec_lpc, |
| 653 | * which makes ENXIO an expected (and safe) scenario. |
| 654 | */ |
| 655 | irq = platform_get_irq_optional(pdev, 0); |
| 656 | if (irq > 0) |
| 657 | ec_dev->irq = irq; |
| 658 | else if (irq != -ENXIO) { |
| 659 | dev_err(dev, "couldn't retrieve IRQ number (%d)\n" , irq); |
| 660 | return irq; |
| 661 | } |
| 662 | |
| 663 | ret = cros_ec_register(ec_dev); |
| 664 | if (ret) { |
| 665 | dev_err(dev, "couldn't register ec_dev (%d)\n" , ret); |
| 666 | return ret; |
| 667 | } |
| 668 | |
| 669 | /* |
| 670 | * Connect a notify handler to process MKBP messages if we have a |
| 671 | * companion ACPI device. |
| 672 | */ |
| 673 | if (adev) { |
| 674 | status = acpi_install_notify_handler(device: adev->handle, |
| 675 | ACPI_ALL_NOTIFY, |
| 676 | handler: cros_ec_lpc_acpi_notify, |
| 677 | context: ec_dev); |
| 678 | if (ACPI_FAILURE(status)) |
| 679 | dev_warn(dev, "Failed to register notifier %08x\n" , |
| 680 | status); |
| 681 | } |
| 682 | |
| 683 | return 0; |
| 684 | } |
| 685 | |
| 686 | static void cros_ec_lpc_remove(struct platform_device *pdev) |
| 687 | { |
| 688 | struct cros_ec_device *ec_dev = platform_get_drvdata(pdev); |
| 689 | struct acpi_device *adev; |
| 690 | |
| 691 | adev = ACPI_COMPANION(&pdev->dev); |
| 692 | if (adev) |
| 693 | acpi_remove_notify_handler(device: adev->handle, ACPI_ALL_NOTIFY, |
| 694 | handler: cros_ec_lpc_acpi_notify); |
| 695 | |
| 696 | cros_ec_unregister(ec_dev); |
| 697 | } |
| 698 | |
| 699 | static const struct lpc_driver_data framework_laptop_npcx_lpc_driver_data __initconst = { |
| 700 | .quirks = CROS_EC_LPC_QUIRK_REMAP_MEMORY, |
| 701 | .quirk_mmio_memory_base = 0xE00, |
| 702 | }; |
| 703 | |
| 704 | static const struct lpc_driver_data framework_laptop_mec_lpc_driver_data __initconst = { |
| 705 | .quirks = CROS_EC_LPC_QUIRK_ACPI_ID|CROS_EC_LPC_QUIRK_AML_MUTEX, |
| 706 | .quirk_acpi_id = "PNP0C09" , |
| 707 | .quirk_aml_mutex_name = "ECMT" , |
| 708 | }; |
| 709 | |
| 710 | static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { |
| 711 | { ACPI_DRV_NAME, 0 }, |
| 712 | { FRMW_ACPI_DRV_NAME, (kernel_ulong_t)&framework_laptop_npcx_lpc_driver_data }, |
| 713 | { } |
| 714 | }; |
| 715 | MODULE_DEVICE_TABLE(acpi, cros_ec_lpc_acpi_device_ids); |
| 716 | |
| 717 | static const struct dmi_system_id cros_ec_lpc_dmi_table[] __initconst = { |
| 718 | { |
| 719 | /* |
| 720 | * Today all Chromebooks/boxes ship with Google_* as version and |
| 721 | * coreboot as bios vendor. No other systems with this |
| 722 | * combination are known to date. |
| 723 | */ |
| 724 | .matches = { |
| 725 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot" ), |
| 726 | DMI_MATCH(DMI_BIOS_VERSION, "Google_" ), |
| 727 | }, |
| 728 | }, |
| 729 | { |
| 730 | /* |
| 731 | * If the box is running custom coreboot firmware then the |
| 732 | * DMI BIOS version string will not be matched by "Google_", |
| 733 | * but the system vendor string will still be matched by |
| 734 | * "GOOGLE". |
| 735 | */ |
| 736 | .matches = { |
| 737 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot" ), |
| 738 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
| 739 | }, |
| 740 | }, |
| 741 | { |
| 742 | /* x86-link, the Chromebook Pixel. */ |
| 743 | .matches = { |
| 744 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
| 745 | DMI_MATCH(DMI_PRODUCT_NAME, "Link" ), |
| 746 | }, |
| 747 | }, |
| 748 | { |
| 749 | /* x86-samus, the Chromebook Pixel 2. */ |
| 750 | .matches = { |
| 751 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
| 752 | DMI_MATCH(DMI_PRODUCT_NAME, "Samus" ), |
| 753 | }, |
| 754 | }, |
| 755 | { |
| 756 | /* x86-peppy, the Acer C720 Chromebook. */ |
| 757 | .matches = { |
| 758 | DMI_MATCH(DMI_SYS_VENDOR, "Acer" ), |
| 759 | DMI_MATCH(DMI_PRODUCT_NAME, "Peppy" ), |
| 760 | }, |
| 761 | }, |
| 762 | { |
| 763 | /* x86-glimmer, the Lenovo Thinkpad Yoga 11e. */ |
| 764 | .matches = { |
| 765 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
| 766 | DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer" ), |
| 767 | }, |
| 768 | }, |
| 769 | /* A small number of non-Chromebook/box machines also use the ChromeOS EC */ |
| 770 | { |
| 771 | /* Framework Laptop (11th Gen Intel Core) */ |
| 772 | .matches = { |
| 773 | DMI_MATCH(DMI_SYS_VENDOR, "Framework" ), |
| 774 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Laptop" ), |
| 775 | }, |
| 776 | .driver_data = (void *)&framework_laptop_mec_lpc_driver_data, |
| 777 | }, |
| 778 | { |
| 779 | /* Framework Laptop (12th Gen Intel Core) */ |
| 780 | .matches = { |
| 781 | DMI_MATCH(DMI_SYS_VENDOR, "Framework" ), |
| 782 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Laptop (12th Gen Intel Core)" ), |
| 783 | }, |
| 784 | .driver_data = (void *)&framework_laptop_mec_lpc_driver_data, |
| 785 | }, |
| 786 | { |
| 787 | /* Framework Laptop (13th Gen Intel Core) */ |
| 788 | .matches = { |
| 789 | DMI_MATCH(DMI_SYS_VENDOR, "Framework" ), |
| 790 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Laptop (13th Gen Intel Core)" ), |
| 791 | }, |
| 792 | .driver_data = (void *)&framework_laptop_mec_lpc_driver_data, |
| 793 | }, |
| 794 | { |
| 795 | /* |
| 796 | * All remaining Framework Laptop models (13 AMD Ryzen, 16 AMD |
| 797 | * Ryzen, Intel Core Ultra) |
| 798 | */ |
| 799 | .matches = { |
| 800 | DMI_MATCH(DMI_SYS_VENDOR, "Framework" ), |
| 801 | DMI_MATCH(DMI_PRODUCT_FAMILY, "Laptop" ), |
| 802 | }, |
| 803 | .driver_data = (void *)&framework_laptop_npcx_lpc_driver_data, |
| 804 | }, |
| 805 | { /* sentinel */ } |
| 806 | }; |
| 807 | MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table); |
| 808 | |
| 809 | #ifdef CONFIG_PM_SLEEP |
| 810 | static int cros_ec_lpc_prepare(struct device *dev) |
| 811 | { |
| 812 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
| 813 | return cros_ec_suspend_prepare(ec_dev); |
| 814 | } |
| 815 | |
| 816 | static void cros_ec_lpc_complete(struct device *dev) |
| 817 | { |
| 818 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
| 819 | cros_ec_resume_complete(ec_dev); |
| 820 | } |
| 821 | |
| 822 | static int cros_ec_lpc_suspend_late(struct device *dev) |
| 823 | { |
| 824 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
| 825 | |
| 826 | return cros_ec_suspend_late(ec_dev); |
| 827 | } |
| 828 | |
| 829 | static int cros_ec_lpc_resume_early(struct device *dev) |
| 830 | { |
| 831 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
| 832 | |
| 833 | return cros_ec_resume_early(ec_dev); |
| 834 | } |
| 835 | #endif |
| 836 | |
| 837 | static const struct dev_pm_ops cros_ec_lpc_pm_ops = { |
| 838 | #ifdef CONFIG_PM_SLEEP |
| 839 | .prepare = cros_ec_lpc_prepare, |
| 840 | .complete = cros_ec_lpc_complete, |
| 841 | #endif |
| 842 | SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend_late, cros_ec_lpc_resume_early) |
| 843 | }; |
| 844 | |
| 845 | static struct platform_driver cros_ec_lpc_driver = { |
| 846 | .driver = { |
| 847 | .name = DRV_NAME, |
| 848 | .acpi_match_table = cros_ec_lpc_acpi_device_ids, |
| 849 | .pm = &cros_ec_lpc_pm_ops, |
| 850 | /* |
| 851 | * ACPI child devices may probe before us, and they racily |
| 852 | * check our drvdata pointer. Force synchronous probe until |
| 853 | * those races are resolved. |
| 854 | */ |
| 855 | .probe_type = PROBE_FORCE_SYNCHRONOUS, |
| 856 | }, |
| 857 | .probe = cros_ec_lpc_probe, |
| 858 | .remove = cros_ec_lpc_remove, |
| 859 | }; |
| 860 | |
| 861 | static struct platform_device cros_ec_lpc_device = { |
| 862 | .name = DRV_NAME |
| 863 | }; |
| 864 | |
| 865 | static int __init cros_ec_lpc_init(void) |
| 866 | { |
| 867 | int ret; |
| 868 | const struct dmi_system_id *dmi_match; |
| 869 | |
| 870 | cros_ec_lpc_acpi_device_found = !!cros_ec_lpc_get_device(ACPI_DRV_NAME) || |
| 871 | !!cros_ec_lpc_get_device(FRMW_ACPI_DRV_NAME); |
| 872 | |
| 873 | dmi_match = dmi_first_match(list: cros_ec_lpc_dmi_table); |
| 874 | |
| 875 | if (!cros_ec_lpc_acpi_device_found && !dmi_match) { |
| 876 | pr_err(DRV_NAME ": unsupported system.\n" ); |
| 877 | return -ENODEV; |
| 878 | } |
| 879 | |
| 880 | /* Register the driver */ |
| 881 | ret = platform_driver_register(&cros_ec_lpc_driver); |
| 882 | if (ret) { |
| 883 | pr_err(DRV_NAME ": can't register driver: %d\n" , ret); |
| 884 | return ret; |
| 885 | } |
| 886 | |
| 887 | if (!cros_ec_lpc_acpi_device_found) { |
| 888 | /* Pass the DMI match's driver data down to the platform device */ |
| 889 | platform_set_drvdata(pdev: &cros_ec_lpc_device, data: dmi_match->driver_data); |
| 890 | |
| 891 | /* Register the device, and it'll get hooked up automatically */ |
| 892 | ret = platform_device_register(&cros_ec_lpc_device); |
| 893 | if (ret) { |
| 894 | pr_err(DRV_NAME ": can't register device: %d\n" , ret); |
| 895 | platform_driver_unregister(&cros_ec_lpc_driver); |
| 896 | } |
| 897 | } |
| 898 | |
| 899 | return ret; |
| 900 | } |
| 901 | |
| 902 | static void __exit cros_ec_lpc_exit(void) |
| 903 | { |
| 904 | if (!cros_ec_lpc_acpi_device_found) |
| 905 | platform_device_unregister(&cros_ec_lpc_device); |
| 906 | platform_driver_unregister(&cros_ec_lpc_driver); |
| 907 | } |
| 908 | |
| 909 | module_init(cros_ec_lpc_init); |
| 910 | module_exit(cros_ec_lpc_exit); |
| 911 | |
| 912 | MODULE_LICENSE("GPL" ); |
| 913 | MODULE_DESCRIPTION("ChromeOS EC LPC driver" ); |
| 914 | |