diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 17:23:39 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 17:23:39 -0800 |
| commit | 5f5ce6bcfcc3abbaf690fca30a22d0dcf6f36d32 (patch) | |
| tree | 1597ad6d459e09646e8d5c2022a36958ee7fc580 | |
| parent | 239451e90355be68130410ef8fadef8cd130a35d (diff) | |
| parent | b0d8a67715dae445c065c83a40a581d6563a341f (diff) | |
Merge tag 'tag-chrome-platform-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux
Pull chrome platform updates from Tzung-Bi Shih:
"New drivers:
- cros_ec_uart for ChromeOS EC protocol over UART
- cros_typec_vdm for USB PD Vendor Defined Message
Improvements:
- Preserve logs as much as possible when EC panics
- Shutdown to refrain from potential HW damages when EC panics
Fixes:
- Fix DP_PORT_VDO to include DP_CAP_RECEPTACLE
- Fix a lockdep false positive
Cleanups:
- Use sysfs_emit*() instead of scnprintf()
- Use asm instead of asm-generic for unaligned.h
Misc:
- Rename module name from cros_ec_typec to cros-ec-typec
- Minor fixes"
* tag 'tag-chrome-platform-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (34 commits)
platform/chrome: cros_ec_typec: Fix spelling mistake
platform/chrome: cros_typec_vdm: Add Attention support
platform/chrome: cros_ec: Add VDM attention headers
platform/chrome: cros_typec_vdm: Fix VDO copy
platform/chrome: cros_ec_typec: allow deferred probe of switch handles
platform/chrome: cros_ec_proto: remove big stub objects from stack
platform/chrome: cros_ec_uart: fix negative type promoted to high
platform/chrome: cros_ec: Use per-device lockdep key
platform/chrome: fix kernel-doc warnings for cros_ec_command
platform/chrome: fix kernel-doc warning for last_resume_result
platform/chrome: fix kernel-doc warning for suspend_timeout_ms
platform/chrome: fix kernel-doc warnings for panic notifier
platform/chrome: cros_ec_lpc: initialize the buf variable
platform/chrome: cros_ec: Fix panic notifier registration
platform/chrome: cros_typec_switch: Check for retimer flag
platform/chrome: cros_typec_switch: Use fwnode* prop check
platform/chrome: cros_typec_vdm: Add VDM send support
platform/chrome: cros_typec_vdm: Add VDM reply support
platform/chrome: cros_ec_typec: Add initial VDM support
platform/chrome: cros_ec_typec: Alter module name with hyphens
...
| -rw-r--r-- | MAINTAINERS | 10 | ||||
| -rw-r--r-- | drivers/mfd/cros_ec_dev.c | 5 | ||||
| -rw-r--r-- | drivers/platform/chrome/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/platform/chrome/Makefile | 4 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec.c | 15 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_debugfs.c | 25 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_lightbar.c | 14 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_lpc.c | 12 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_proto_test.c | 13 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_sysfs.c | 40 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_typec.c | 123 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_typec.h | 85 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_ec_uart.c | 362 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_typec_switch.c | 16 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_typec_vdm.c | 148 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_typec_vdm.h | 13 | ||||
| -rw-r--r-- | drivers/platform/chrome/wilco_ec/sysfs.c | 3 | ||||
| -rw-r--r-- | include/linux/platform_data/cros_ec_commands.h | 69 | ||||
| -rw-r--r-- | include/linux/platform_data/cros_ec_proto.h | 24 |
19 files changed, 846 insertions, 147 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 27f3a8619afc..49609a55577d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4823,6 +4823,13 @@ S: Maintained F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml F: sound/soc/codecs/cros_ec_codec.* +CHROMEOS EC UART DRIVER +M: Bhanu Prakash Maiya <bhanumaiya@chromium.org> +R: Benson Leung <bleung@chromium.org> +R: Tzung-Bi Shih <tzungbi@kernel.org> +S: Maintained +F: drivers/platform/chrome/cros_ec_uart.c + CHROMEOS EC SUBDRIVERS M: Benson Leung <bleung@chromium.org> R: Guenter Roeck <groeck@chromium.org> @@ -4836,8 +4843,9 @@ CHROMEOS EC USB TYPE-C DRIVER M: Prashant Malani <pmalani@chromium.org> L: chrome-platform@lists.linux.dev S: Maintained -F: drivers/platform/chrome/cros_ec_typec.c +F: drivers/platform/chrome/cros_ec_typec.* F: drivers/platform/chrome/cros_typec_switch.c +F: drivers/platform/chrome/cros_typec_vdm.* CHROMEOS EC USB PD NOTIFY DRIVER M: Prashant Malani <pmalani@chromium.org> diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 344ad03bdc42..02d4271dfe06 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -65,11 +65,6 @@ static const struct cros_feature_to_name cros_mcu_devices[] = { .desc = "System Control Processor", }, { - .id = EC_FEATURE_SCP_C1, - .name = CROS_EC_DEV_SCP_C1_NAME, - .desc = "System Control Processor 2nd Core", - }, - { .id = EC_FEATURE_TOUCHPAD, .name = CROS_EC_DEV_TP_NAME, .desc = "Touchpad", diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index c1ca247987d2..7d82a0946e1c 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -119,6 +119,16 @@ config CROS_EC_SPI response time cannot be guaranteed, we support ignoring 'pre-amble' bytes before the response actually starts. +config CROS_EC_UART + tristate "ChromeOS Embedded Controller (UART)" + depends on CROS_EC && ACPI && SERIAL_DEV_BUS + help + If you say Y here, you get support for talking to the ChromeOS EC + through a UART, using a byte-level protocol. + + To compile this driver as a module, choose M here: the + module will be called cros_ec_uart. + config CROS_EC_LPC tristate "ChromeOS Embedded Controller (LPC)" depends on CROS_EC && ACPI && (X86 || COMPILE_TEST) @@ -226,7 +236,7 @@ config CROS_EC_TYPEC information from the Chrome OS EC. To compile this driver as a module, choose M here: the module will be - called cros_ec_typec. + called cros-ec-typec. config CROS_HPS_I2C tristate "ChromeOS HPS device" diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index f6068d077a40..9e26e45c4a37 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -15,8 +15,10 @@ obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o obj-$(CONFIG_CROS_TYPEC_SWITCH) += cros_typec_switch.o obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_CROS_EC_UART) += cros_ec_uart.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o -obj-$(CONFIG_CROS_EC_TYPEC) += cros_ec_typec.o +cros-ec-typec-objs := cros_ec_typec.o cros_typec_vdm.o +obj-$(CONFIG_CROS_EC_TYPEC) += cros-ec-typec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index ec733f683f34..b895c8130bba 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -182,6 +182,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) int err = 0; BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); + BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->panic_notifier); ec_dev->max_request = sizeof(struct ec_params_hello); ec_dev->max_response = sizeof(struct ec_response_get_protocol_info); @@ -198,12 +199,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (!ec_dev->dout) return -ENOMEM; + lockdep_register_key(&ec_dev->lockdep_key); mutex_init(&ec_dev->lock); + lockdep_set_class(&ec_dev->lock, &ec_dev->lockdep_key); err = cros_ec_query_all(ec_dev); if (err) { dev_err(dev, "Cannot identify the EC: error %d\n", err); - return err; + goto destroy_mutex; } if (ec_dev->irq > 0) { @@ -215,7 +218,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (err) { dev_err(dev, "Failed to request IRQ %d: %d\n", ec_dev->irq, err); - return err; + goto destroy_mutex; } } @@ -226,7 +229,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (IS_ERR(ec_dev->ec)) { dev_err(ec_dev->dev, "Failed to create CrOS EC platform device\n"); - return PTR_ERR(ec_dev->ec); + err = PTR_ERR(ec_dev->ec); + goto destroy_mutex; } if (ec_dev->max_passthru) { @@ -292,6 +296,9 @@ int cros_ec_register(struct cros_ec_device *ec_dev) exit: platform_device_unregister(ec_dev->ec); platform_device_unregister(ec_dev->pd); +destroy_mutex: + mutex_destroy(&ec_dev->lock); + lockdep_unregister_key(&ec_dev->lockdep_key); return err; } EXPORT_SYMBOL(cros_ec_register); @@ -309,6 +316,8 @@ void cros_ec_unregister(struct cros_ec_device *ec_dev) if (ec_dev->pd) platform_device_unregister(ec_dev->pd); platform_device_unregister(ec_dev->ec); + mutex_destroy(&ec_dev->lock); + lockdep_unregister_key(&ec_dev->lockdep_key); } EXPORT_SYMBOL(cros_ec_unregister); diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 21d973fc6be2..a98c529d8c69 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -38,6 +38,8 @@ static DECLARE_WAIT_QUEUE_HEAD(cros_ec_debugfs_log_wq); * @log_mutex: mutex to protect circular buffer * @log_poll_work: recurring task to poll EC for new console log data * @panicinfo_blob: panicinfo debugfs blob + * @notifier_panic: notifier_block to let kernel to flush buffered log + * when EC panic */ struct cros_ec_debugfs { struct cros_ec_dev *ec; @@ -49,6 +51,7 @@ struct cros_ec_debugfs { struct delayed_work log_poll_work; /* EC panicinfo */ struct debugfs_blob_wrapper panicinfo_blob; + struct notifier_block notifier_panic; }; /* @@ -437,6 +440,22 @@ free: return ret; } +static int cros_ec_debugfs_panic_event(struct notifier_block *nb, + unsigned long queued_during_suspend, void *_notify) +{ + struct cros_ec_debugfs *debug_info = + container_of(nb, struct cros_ec_debugfs, notifier_panic); + + if (debug_info->log_buffer.buf) { + /* Force log poll work to run immediately */ + mod_delayed_work(debug_info->log_poll_work.wq, &debug_info->log_poll_work, 0); + /* Block until log poll work finishes */ + flush_delayed_work(&debug_info->log_poll_work); + } + + return NOTIFY_DONE; +} + static int cros_ec_debugfs_probe(struct platform_device *pd) { struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent); @@ -473,6 +492,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd) debugfs_create_u16("suspend_timeout_ms", 0664, debug_info->dir, &ec->ec_dev->suspend_timeout_ms); + debug_info->notifier_panic.notifier_call = cros_ec_debugfs_panic_event; + ret = blocking_notifier_chain_register(&ec->ec_dev->panic_notifier, + &debug_info->notifier_panic); + if (ret) + goto remove_debugfs; + ec->debug_info = debug_info; dev_set_drvdata(&pd->dev, ec); diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 1674105decfb..376425bbd8ff 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -34,7 +34,7 @@ static ssize_t interval_msec_show(struct device *dev, { unsigned long msec = lb_interval_jiffies * 1000 / HZ; - return scnprintf(buf, PAGE_SIZE, "%lu\n", msec); + return sysfs_emit(buf, "%lu\n", msec); } static ssize_t interval_msec_store(struct device *dev, @@ -169,7 +169,7 @@ static ssize_t version_show(struct device *dev, if (!get_lightbar_version(ec, &version, &flags)) return -EIO; - return scnprintf(buf, PAGE_SIZE, "%d %d\n", version, flags); + return sysfs_emit(buf, "%d %d\n", version, flags); } static ssize_t brightness_store(struct device *dev, @@ -302,17 +302,15 @@ static ssize_t sequence_show(struct device *dev, ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0) { - ret = scnprintf(buf, PAGE_SIZE, "XFER / EC ERROR %d / %d\n", - ret, msg->result); + ret = sysfs_emit(buf, "XFER / EC ERROR %d / %d\n", ret, msg->result); goto exit; } resp = (struct ec_response_lightbar *)msg->data; if (resp->get_seq.num >= ARRAY_SIZE(seqname)) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); + ret = sysfs_emit(buf, "%d\n", resp->get_seq.num); else - ret = scnprintf(buf, PAGE_SIZE, "%s\n", - seqname[resp->get_seq.num]); + ret = sysfs_emit(buf, "%s\n", seqname[resp->get_seq.num]); exit: kfree(msg); @@ -483,7 +481,7 @@ static ssize_t userspace_control_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control); + return sysfs_emit(buf, "%d\n", userspace_control); } static ssize_t userspace_control_store(struct device *dev, diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 7fc8f82280ac..68bba0fcafab 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -21,6 +21,7 @@ #include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_device.h> #include <linux/printk.h> +#include <linux/reboot.h> #include <linux/suspend.h> #include "cros_ec.h" @@ -320,6 +321,15 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data) ec_dev->last_event_time = cros_ec_get_time_ns(); + 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); + /* Begin orderly shutdown. Force shutdown after 1 second. */ + hw_protection_shutdown("CrOS EC Panic", 1000); + /* Do not query for other events after a panic is reported */ + return; + } + if (ec_dev->mkbp_event_supported) do { ret = cros_ec_get_next_event(ec_dev, NULL, @@ -340,7 +350,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev) struct acpi_device *adev; acpi_status status; struct cros_ec_device *ec_dev; - u8 buf[2]; + u8 buf[2] = {}; int irq, ret; /* diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index c6a83df91ae1..5b9748e0463b 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -5,7 +5,8 @@ #include <kunit/test.h> -#include <asm-generic/unaligned.h> +#include <asm/unaligned.h> + #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> @@ -2370,7 +2371,7 @@ static void cros_ec_proto_test_get_host_event_normal(struct kunit *test) static void cros_ec_proto_test_check_features_cached(struct kunit *test) { int ret, i; - struct cros_ec_dev ec; + static struct cros_ec_dev ec; ec.features.flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT); ec.features.flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP); @@ -2395,7 +2396,7 @@ static void cros_ec_proto_test_check_features_not_cached(struct kunit *test) struct cros_ec_device *ec_dev = &priv->ec_dev; struct ec_xfer_mock *mock; int ret, i; - struct cros_ec_dev ec; + static struct cros_ec_dev ec; ec_dev->max_request = 0xff; ec_dev->max_response = 0xee; @@ -2448,7 +2449,7 @@ static void cros_ec_proto_test_get_sensor_count_normal(struct kunit *test) struct cros_ec_device *ec_dev = &priv->ec_dev; struct ec_xfer_mock *mock; int ret; - struct cros_ec_dev ec; + static struct cros_ec_dev ec; ec_dev->max_request = 0xff; ec_dev->max_response = 0xee; @@ -2493,7 +2494,7 @@ static void cros_ec_proto_test_get_sensor_count_xfer_error(struct kunit *test) struct cros_ec_device *ec_dev = &priv->ec_dev; struct ec_xfer_mock *mock; int ret; - struct cros_ec_dev ec; + static struct cros_ec_dev ec; ec_dev->max_request = 0xff; ec_dev->max_response = 0xee; @@ -2533,7 +2534,7 @@ static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test) struct cros_ec_device *ec_dev = &priv->ec_dev; struct ec_xfer_mock *mock; int ret, i; - struct cros_ec_dev ec; + static struct cros_ec_dev ec; struct { u8 readmem_data; int expected_result; diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index f07eabcf9494..09e3bf5e8ec6 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -27,10 +27,9 @@ static ssize_t reboot_show(struct device *dev, { int count = 0; - count += scnprintf(buf + count, PAGE_SIZE - count, - "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off"); - count += scnprintf(buf + count, PAGE_SIZE - count, - " [at-shutdown]\n"); + count += sysfs_emit_at(buf, count, + "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off"); + count += sysfs_emit_at(buf, count, " [at-shutdown]\n"); return count; } @@ -138,12 +137,9 @@ static ssize_t version_show(struct device *dev, /* Strings should be null-terminated, but let's be sure. */ r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; - count += scnprintf(buf + count, PAGE_SIZE - count, - "RO version: %s\n", r_ver->version_string_ro); - count += scnprintf(buf + count, PAGE_SIZE - count, - "RW version: %s\n", r_ver->version_string_rw); - count += scnprintf(buf + count, PAGE_SIZE - count, - "Firmware copy: %s\n", + count += sysfs_emit_at(buf, count, "RO version: %s\n", r_ver->version_string_ro); + count += sysfs_emit_at(buf, count, "RW version: %s\n", r_ver->version_string_rw); + count += sysfs_emit_at(buf, count, "Firmware copy: %s\n", (r_ver->current_image < ARRAY_SIZE(image_names) ? image_names[r_ver->current_image] : "?")); @@ -152,13 +148,12 @@ static ssize_t version_show(struct device *dev, msg->insize = EC_HOST_PARAM_SIZE; ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0) { - count += scnprintf(buf + count, PAGE_SIZE - count, + count += sysfs_emit_at(buf, count, "Build info: XFER / EC ERROR %d / %d\n", ret, msg->result); } else { msg->data[EC_HOST_PARAM_SIZE - 1] = '\0'; - count += scnprintf(buf + count, PAGE_SIZE - count, - "Build info: %s\n", msg->data); + count += sysfs_emit_at(buf, count, "Build info: %s\n", msg->data); } /* Get chip info. */ @@ -166,7 +161,7 @@ static ssize_t version_show(struct device *dev, msg->insize = sizeof(*r_chip); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0) { - count += scnprintf(buf + count, PAGE_SIZE - count, + count += sysfs_emit_at(buf, count, "Chip info: XFER / EC ERROR %d / %d\n", ret, msg->result); } else { @@ -175,12 +170,9 @@ static ssize_t version_show(struct device *dev, r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; r_chip->name[sizeof(r_chip->name) - 1] = '\0'; r_chip->revision[sizeof(r_chip->revision) - 1] = '\0'; - count += scnprintf(buf + count, PAGE_SIZE - count, - "Chip vendor: %s\n", r_chip->vendor); - count += scnprintf(buf + count, PAGE_SIZE - count, - "Chip name: %s\n", r_chip->name); - count += scnprintf(buf + count, PAGE_SIZE - count, - "Chip revision: %s\n", r_chip->revision); + count += sysfs_emit_at(buf, count, "Chip vendor: %s\n", r_chip->vendor); + count += sysfs_emit_at(buf, count, "Chip name: %s\n", r_chip->name); + count += sysfs_emit_at(buf, count, "Chip revision: %s\n", r_chip->revision); } /* Get board version */ @@ -188,13 +180,13 @@ static ssize_t version_show(struct device *dev, msg->insize = sizeof(*r_board); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0) { - count += scnprintf(buf + count, PAGE_SIZE - count, + count += sysfs_emit_at(buf, count, "Board version: XFER / EC ERROR %d / %d\n", ret, msg->result); } else { r_board = (struct ec_response_board_version *)msg->data; - count += scnprintf(buf + count, PAGE_SIZE - count, + count += sysfs_emit_at(buf, count, "Board version: %d\n", r_board->board_version); } @@ -227,7 +219,7 @@ static ssize_t flashinfo_show(struct device *dev, resp = (struct ec_response_flash_info *)msg->data; - ret = scnprintf(buf, PAGE_SIZE, + ret = sysfs_emit(buf, "FlashSize %d\nWriteSize %d\n" "EraseSize %d\nProtectSize %d\n", resp->flash_size, resp->write_block_size, @@ -264,7 +256,7 @@ static ssize_t kb_wake_angle_show(struct device *dev, goto exit; resp = (struct ec_response_motion_sense *)msg->data; - ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->kb_wake_angle.ret); + ret = sysfs_emit(buf, "%d\n", resp->kb_wake_angle.ret); exit: kfree(msg); return ret; diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 001b0de95a46..a673c3342470 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -7,92 +7,22 @@ */ #include <linux/acpi.h> -#include <linux/list.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_data/cros_ec_commands.h> -#include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_data/cros_usbpd_notify.h> #include <linux/platform_device.h> -#include <linux/usb/pd.h> #include <linux/usb/pd_vdo.h> -#include <linux/usb/typec.h> -#include <linux/usb/typec_altmode.h> #include <linux/usb/typec_dp.h> -#include <linux/usb/typec_mux.h> -#include <linux/usb/typec_retimer.h> #include <linux/usb/typec_tbt.h> -#include <linux/usb/role.h> + +#include "cros_ec_typec.h" +#include "cros_typec_vdm.h" #define DRV_NAME "cros-ec-typec" #define DP_PORT_VDO (DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D)) | \ - DP_CAP_DFP_D) - -/* Supported alt modes. */ -enum { - CROS_EC_ALTMODE_DP = 0, - CROS_EC_ALTMODE_TBT, - CROS_EC_ALTMODE_MAX, -}; - -/* Container for altmode pointer nodes. */ -struct cros_typec_altmode_node { - struct typec_altmode *amode; - struct list_head list; -}; - -/* Per port data. */ -struct cros_typec_port { - struct typec_port *port; - /* Initial capabilities for the port. */ - struct typec_capability caps; - struct typec_partner *partner; - struct typec_cable *cable; - /* SOP' plug. */ - struct typec_plug *plug; - /* Port partner PD identity info. */ - struct usb_pd_identity p_identity; - /* Port cable PD identity info. */ - struct usb_pd_identity c_identity; - struct typec_switch *ori_sw; - struct typec_mux *mux; - struct typec_retimer *retimer; - struct usb_role_switch *role_sw; - - /* Variables keeping track of switch state. */ - struct typec_mux_state state; - uint8_t mux_flags; - uint8_t role; - - struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX]; - - /* Flag indicating that PD partner discovery data parsing is completed. */ - bool sop_disc_done; - bool sop_prime_disc_done; - struct ec_response_typec_discovery *disc_data; - struct list_head partner_mode_list; - struct list_head plug_mode_list; - - /* PDO-related structs */ - struct usb_power_delivery *partner_pd; - struct usb_power_delivery_capabilities *partner_src_caps; - struct usb_power_delivery_capabilities *partner_sink_caps; -}; - -/* Platform-specific data for the Chrome OS EC Type C controller. */ -struct cros_typec_data { - struct device *dev; - struct cros_ec_device *ec; - int num_ports; - unsigned int pd_ctrl_ver; - /* Array of ports, indexed by port number. */ - struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; - struct notifier_block nb; - struct work_struct port_work; - bool typec_cmd_supported; - bool needs_mux_ack; -}; + DP_CAP_DFP_D | DP_CAP_RECEPTACLE) static int cros_typec_parse_port_props(struct typec_capability *cap, struct fwnode_handle *fwnode, @@ -145,27 +75,33 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, struct fwnode_handle *fwnode, struct device *dev) { + int ret = 0; + port->mux = fwnode_typec_mux_get(fwnode, NULL); if (IS_ERR(port->mux)) { - dev_dbg(dev, "Mux handle not found.\n"); + ret = PTR_ERR(port->mux); + dev_dbg(dev, "Mux handle not found: %d.\n", ret); goto mux_err; } port->retimer = fwnode_typec_retimer_get(fwnode); if (IS_ERR(port->retimer)) { - dev_dbg(dev, "Retimer handle not found.\n"); + ret = PTR_ERR(port->retimer); + dev_dbg(dev, "Retimer handle not found: %d.\n", ret); goto retimer_sw_err; } port->ori_sw = fwnode_typec_switch_get(fwnode); if (IS_ERR(port->ori_sw)) { - dev_dbg(dev, "Orientation switch handle not found.\n"); + ret = PTR_ERR(port->ori_sw); + dev_dbg(dev, "Orientation switch handle not found: %d\n", ret); goto ori_sw_err; } port->role_sw = fwnode_usb_role_switch_get(fwnode); if (IS_ERR(port->role_sw)) { - dev_dbg(dev, "USB role switch handle not found.\n"); + ret = PTR_ERR(port->role_sw); + dev_dbg(dev, "USB role switch handle not found: %d\n", ret); goto role_sw_err; } @@ -181,7 +117,7 @@ retimer_sw_err: typec_mux_put(port->mux); port->mux = NULL; mux_err: - return -ENODEV; + return ret; } static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num, @@ -342,6 +278,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec, if (IS_ERR(amode)) return PTR_ERR(amode); port->port_altmode[CROS_EC_ALTMODE_DP] = amode; + typec_altmode_set_drvdata(amode, port); + amode->ops = &port_amode_ops; /* * Register TBT compatibility alt mode. The EC will not enter the mode @@ -355,6 +293,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec, if (IS_ERR(amode)) return PTR_ERR(amode); port->port_altmode[CROS_EC_ALTMODE_TBT] = amode; + typec_altmode_set_drvdata(amode, port); + amode->ops = &port_amode_ops; port->state.alt = NULL; port->state.mode = TYPEC_STATE_USB; @@ -408,6 +348,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) goto unregister_ports; } + cros_port->port_num = port_num; + cros_port->typec_data = typec; typec->ports[port_num] = cros_port; cap = &cros_port->caps; @@ -423,9 +365,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) } ret = cros_typec_get_switch_handles(cros_port, fwnode, dev); - if (ret) - dev_dbg(dev, "No switch control for port %d\n", - port_num); + if (ret) { + dev_dbg(dev, "No switch control for port %d, err: %d\n", port_num, ret); + if (ret == -EPROBE_DEFER) + goto unregister_ports; + } ret = cros_typec_register_port_altmodes(typec, port_num); if (ret) { @@ -1064,6 +1008,21 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num "Failed SOP Disc event clear, port: %d\n", port_num); } } + + if (resp.events & PD_STATUS_EVENT_VDM_REQ_REPLY) { + cros_typec_handle_vdm_response(typec, port_num); + ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_REQ_REPLY); + if (ret < 0) + dev_warn(typec->dev, "Failed VDM Reply event clear, port: %d\n", port_num); + } + + if (resp.events & PD_STATUS_EVENT_VDM_ATTENTION) { + cros_typec_handle_vdm_attention(typec, port_num); + ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_ATTENTION); + if (ret < 0) + dev_warn(typec->dev, "Failed VDM attention event clear, port: %d\n", + port_num); + } } static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) diff --git a/drivers/platform/chrome/cros_ec_typec.h b/drivers/platform/chrome/cros_ec_typec.h new file mode 100644 index 000000000000..deda180a646f --- /dev/null +++ b/drivers/platform/chrome/cros_ec_typec.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __CROS_EC_TYPEC__ +#define __CROS_EC_TYPEC__ + +#include <linux/list.h> +#include <linux/notifier.h> +#include <linux/platform_data/cros_ec_proto.h> +#include <linux/usb/pd.h> +#include <linux/usb/role.h> +#include <linux/usb/typec.h> +#include <linux/usb/typec_altmode.h> +#include <linux/usb/typec_mux.h> +#include <linux/usb/typec_retimer.h> +#include <linux/workqueue.h> + +/* Supported alt modes. */ +enum { + CROS_EC_ALTMODE_DP = 0, + CROS_EC_ALTMODE_TBT, + CROS_EC_ALTMODE_MAX, +}; + +/* Container for altmode pointer nodes. */ +struct cros_typec_altmode_node { + struct typec_altmode *amode; + struct list_head list; +}; + +/* Platform-specific data for the Chrome OS EC Type C controller. */ +struct cros_typec_data { + struct device *dev; + struct cros_ec_device *ec; + int num_ports; + unsigned int pd_ctrl_ver; + /* Array of ports, indexed by port number. */ + struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; + struct notifier_block nb; + struct work_struct port_work; + bool typec_cmd_supported; + bool needs_mux_ack; +}; + +/* Per port data. */ +struct cros_typec_port { + struct typec_port *port; + int port_num; + /* Initial capabilities for the port. */ + struct typec_capability caps; + struct typec_partner *partner; + struct typec_cable *cable; + /* SOP' plug. */ + struct typec_plug *plug; + /* Port partner PD identity info. */ + struct usb_pd_identity p_identity; + /* Port cable PD identity info. */ + struct usb_pd_identity c_identity; + struct typec_switch *ori_sw; + struct typec_mux *mux; + struct typec_retimer *retimer; + struct usb_role_switch *role_sw; + + /* Variables keeping track of switch state. */ + struct typec_mux_state state; + uint8_t mux_flags; + uint8_t role; + + struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX]; + + /* Flag indicating that PD partner discovery data parsing is completed. */ + bool sop_disc_done; + bool sop_prime_disc_done; + struct ec_response_typec_discovery *disc_data; + struct list_head partner_mode_list; + struct list_head plug_mode_list; + + /* PDO-related structs */ + struct usb_power_delivery *partner_pd; + struct usb_power_delivery_capabilities *partner_src_caps; + struct usb_power_delivery_capabilities *partner_sink_caps; + + struct cros_typec_data *typec_data; +}; + +#endif /* __CROS_EC_TYPEC__ */ diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c new file mode 100644 index 000000000000..788246559bbb --- /dev/null +++ b/drivers/platform/chrome/cros_ec_uart.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UART interface for ChromeOS Embedded Controller + * + * Copyright 2020-2022 Google LLC. + */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_data/cros_ec_proto.h> +#include <linux/serdev.h> +#include <linux/slab.h> +#include <uapi/linux/sched/types.h> + +#include "cros_ec.h" + +/* + * EC sends contiguous bytes of response packet on UART AP RX. + * TTY driver in AP accumulates incoming bytes and calls the registered callback + * function. Byte count can range from 1 to MAX bytes supported by EC. + * This driver should wait for long time for all callbacks to be processed. + * Considering the worst case scenario, wait for 500 msec. This timeout should + * account for max latency and some additional guard time. |
