598 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * CEC driver for ChromeOS Embedded Controller4 *5 * Copyright (c) 2018 BayLibre, SAS6 * Author: Neil Armstrong <narmstrong@baylibre.com>7 */8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/mod_devicetable.h>12#include <linux/platform_device.h>13#include <linux/dmi.h>14#include <linux/pci.h>15#include <linux/cec.h>16#include <linux/slab.h>17#include <linux/interrupt.h>18#include <linux/platform_data/cros_ec_commands.h>19#include <linux/platform_data/cros_ec_proto.h>20#include <media/cec.h>21#include <media/cec-notifier.h>22 23#define DRV_NAME "cros-ec-cec"24 25/**26 * struct cros_ec_cec_port - Driver data for a single EC CEC port27 *28 * @port_num: port number29 * @adap: CEC adapter30 * @notify: CEC notifier pointer31 * @rx_msg: storage for a received message32 * @cros_ec_cec: pointer to the parent struct33 */34struct cros_ec_cec_port {35 int port_num;36 struct cec_adapter *adap;37 struct cec_notifier *notify;38 struct cec_msg rx_msg;39 struct cros_ec_cec *cros_ec_cec;40};41 42/**43 * struct cros_ec_cec - Driver data for EC CEC44 *45 * @cros_ec: Pointer to EC device46 * @notifier: Notifier info for responding to EC events47 * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.48 * @num_ports: Number of CEC ports49 * @ports: Array of ports50 */51struct cros_ec_cec {52 struct cros_ec_device *cros_ec;53 struct notifier_block notifier;54 int write_cmd_version;55 int num_ports;56 struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];57};58 59static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,60 uint8_t *msg, uint8_t len)61{62 if (len > CEC_MAX_MSG_SIZE)63 len = CEC_MAX_MSG_SIZE;64 65 port->rx_msg.len = len;66 memcpy(port->rx_msg.msg, msg, len);67 68 cec_received_msg(port->adap, &port->rx_msg);69}70 71static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)72{73 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;74 uint8_t *cec_message = cros_ec->event_data.data.cec_message;75 unsigned int len = cros_ec->event_size;76 struct cros_ec_cec_port *port;77 /*78 * There are two ways of receiving CEC messages:79 * 1. Old EC firmware which only supports one port sends the data in a80 * cec_message MKBP event.81 * 2. New EC firmware which supports multiple ports uses82 * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and83 * EC_CMD_CEC_READ_MSG to read it.84 * Check that the EC only has one CEC port, and then we can assume the85 * message is from port 0.86 */87 if (cros_ec_cec->num_ports != 1) {88 dev_err(cros_ec->dev,89 "received cec_message on device with %d ports\n",90 cros_ec_cec->num_ports);91 return;92 }93 port = cros_ec_cec->ports[0];94 95 cros_ec_cec_received_message(port, cec_message, len);96}97 98static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)99{100 struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;101 struct ec_params_cec_read params = {102 .port = port->port_num,103 };104 struct ec_response_cec_read response;105 int ret;106 107 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms,108 sizeof(params), &response, sizeof(response));109 if (ret < 0) {110 dev_err(cros_ec->dev,111 "error reading CEC message on EC: %d\n", ret);112 return;113 }114 115 cros_ec_cec_received_message(port, response.msg, response.msg_len);116}117 118static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)119{120 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;121 uint32_t cec_events = cros_ec->event_data.data.cec_events;122 uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);123 uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);124 struct cros_ec_cec_port *port;125 126 if (port_num >= cros_ec_cec->num_ports) {127 dev_err(cros_ec->dev,128 "received CEC event for invalid port %d\n", port_num);129 return;130 }131 port = cros_ec_cec->ports[port_num];132 133 if (events & EC_MKBP_CEC_SEND_OK)134 cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);135 136 /* FW takes care of all retries, tell core to avoid more retries */137 if (events & EC_MKBP_CEC_SEND_FAILED)138 cec_transmit_attempt_done(port->adap,139 CEC_TX_STATUS_MAX_RETRIES |140 CEC_TX_STATUS_NACK);141 142 if (events & EC_MKBP_CEC_HAVE_DATA)143 cros_ec_cec_read_message(port);144}145 146static int cros_ec_cec_event(struct notifier_block *nb,147 unsigned long queued_during_suspend,148 void *_notify)149{150 struct cros_ec_cec *cros_ec_cec;151 struct cros_ec_device *cros_ec;152 153 cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier);154 cros_ec = cros_ec_cec->cros_ec;155 156 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) {157 handle_cec_event(cros_ec_cec);158 return NOTIFY_OK;159 }160 161 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) {162 handle_cec_message(cros_ec_cec);163 return NOTIFY_OK;164 }165 166 return NOTIFY_DONE;167}168 169static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)170{171 struct cros_ec_cec_port *port = adap->priv;172 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;173 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;174 struct ec_params_cec_set params = {175 .cmd = CEC_CMD_LOGICAL_ADDRESS,176 .port = port->port_num,177 .val = logical_addr,178 };179 int ret;180 181 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),182 NULL, 0);183 if (ret < 0) {184 dev_err(cros_ec->dev,185 "error setting CEC logical address on EC: %d\n", ret);186 return ret;187 }188 189 return 0;190}191 192static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,193 u32 signal_free_time, struct cec_msg *cec_msg)194{195 struct cros_ec_cec_port *port = adap->priv;196 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;197 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;198 struct ec_params_cec_write params;199 struct ec_params_cec_write_v1 params_v1;200 int ret;201 202 if (cros_ec_cec->write_cmd_version == 0) {203 memcpy(params.msg, cec_msg->msg, cec_msg->len);204 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms,205 cec_msg->len, NULL, 0);206 } else {207 params_v1.port = port->port_num;208 params_v1.msg_len = cec_msg->len;209 memcpy(params_v1.msg, cec_msg->msg, cec_msg->len);210 ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version,211 EC_CMD_CEC_WRITE_MSG, ¶ms_v1,212 sizeof(params_v1), NULL, 0);213 }214 215 if (ret < 0) {216 dev_err(cros_ec->dev,217 "error writing CEC msg on EC: %d\n", ret);218 return ret;219 }220 221 return 0;222}223 224static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)225{226 struct cros_ec_cec_port *port = adap->priv;227 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;228 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;229 struct ec_params_cec_set params = {230 .cmd = CEC_CMD_ENABLE,231 .port = port->port_num,232 .val = enable,233 };234 int ret;235 236 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),237 NULL, 0);238 if (ret < 0) {239 dev_err(cros_ec->dev,240 "error %sabling CEC on EC: %d\n",241 (enable ? "en" : "dis"), ret);242 return ret;243 }244 245 return 0;246}247 248static const struct cec_adap_ops cros_ec_cec_ops = {249 .adap_enable = cros_ec_cec_adap_enable,250 .adap_log_addr = cros_ec_cec_set_log_addr,251 .adap_transmit = cros_ec_cec_transmit,252};253 254#ifdef CONFIG_PM_SLEEP255static int cros_ec_cec_suspend(struct device *dev)256{257 struct platform_device *pdev = to_platform_device(dev);258 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);259 260 if (device_may_wakeup(dev))261 enable_irq_wake(cros_ec_cec->cros_ec->irq);262 263 return 0;264}265 266static int cros_ec_cec_resume(struct device *dev)267{268 struct platform_device *pdev = to_platform_device(dev);269 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);270 271 if (device_may_wakeup(dev))272 disable_irq_wake(cros_ec_cec->cros_ec->irq);273 274 return 0;275}276#endif277 278static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,279 cros_ec_cec_suspend, cros_ec_cec_resume);280 281#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)282 283/*284 * Specify the DRM device name handling the HDMI output and the HDMI connector285 * corresponding to each CEC port. The order of connectors must match the order286 * in the EC (first connector is EC port 0, ...), and the number of connectors287 * must match the number of ports in the EC (which can be queried using the288 * EC_CMD_CEC_PORT_COUNT host command).289 */290 291struct cec_dmi_match {292 const char *sys_vendor;293 const char *product_name;294 const char *devname;295 const char *const *conns;296};297 298static const char *const port_b_conns[] = { "Port B", NULL };299static const char *const port_db_conns[] = { "Port D", "Port B", NULL };300static const char *const port_ba_conns[] = { "Port B", "Port A", NULL };301static const char *const port_d_conns[] = { "Port D", NULL };302 303static const struct cec_dmi_match cec_dmi_match_table[] = {304 /* Google Fizz */305 { "Google", "Fizz", "0000:00:02.0", port_b_conns },306 /* Google Brask */307 { "Google", "Brask", "0000:00:02.0", port_b_conns },308 /* Google Moli */309 { "Google", "Moli", "0000:00:02.0", port_b_conns },310 /* Google Kinox */311 { "Google", "Kinox", "0000:00:02.0", port_b_conns },312 /* Google Kuldax */313 { "Google", "Kuldax", "0000:00:02.0", port_b_conns },314 /* Google Aurash */315 { "Google", "Aurash", "0000:00:02.0", port_b_conns },316 /* Google Gladios */317 { "Google", "Gladios", "0000:00:02.0", port_b_conns },318 /* Google Lisbon */319 { "Google", "Lisbon", "0000:00:02.0", port_b_conns },320 /* Google Dibbi */321 { "Google", "Dibbi", "0000:00:02.0", port_db_conns },322 /* Google Constitution */323 { "Google", "Constitution", "0000:00:02.0", port_ba_conns },324 /* Google Boxy */325 { "Google", "Boxy", "0000:00:02.0", port_d_conns },326 /* Google Taranza */327 { "Google", "Taranza", "0000:00:02.0", port_db_conns },328 /* Google Dexi */329 { "Google", "Dexi", "0000:00:02.0", port_db_conns },330 /* Google Dita */331 { "Google", "Dita", "0000:00:02.0", port_db_conns },332};333 334static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,335 const char * const **conns)336{337 int i;338 339 for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) {340 const struct cec_dmi_match *m = &cec_dmi_match_table[i];341 342 if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&343 dmi_match(DMI_PRODUCT_NAME, m->product_name)) {344 struct device *d;345 346 /* Find the device, bail out if not yet registered */347 d = bus_find_device_by_name(&pci_bus_type, NULL,348 m->devname);349 if (!d)350 return ERR_PTR(-EPROBE_DEFER);351 put_device(d);352 *conns = m->conns;353 return d;354 }355 }356 357 /* Hardware support must be added in the cec_dmi_match_table */358 dev_warn(dev, "CEC notifier not configured for this hardware\n");359 360 return ERR_PTR(-ENODEV);361}362 363#else364 365static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,366 const char * const **conns)367{368 return ERR_PTR(-ENODEV);369}370 371#endif372 373static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec)374{375 struct ec_response_cec_port_count response;376 int ret;377 378 ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL,379 0, &response, sizeof(response));380 if (ret < 0) {381 /*382 * Old EC firmware only supports one port and does not support383 * the port count command, so fall back to assuming one port.384 */385 cros_ec_cec->num_ports = 1;386 return 0;387 }388 389 if (response.port_count == 0) {390 dev_err(cros_ec_cec->cros_ec->dev,391 "EC reports 0 CEC ports\n");392 return -ENODEV;393 }394 395 if (response.port_count > EC_CEC_MAX_PORTS) {396 dev_err(cros_ec_cec->cros_ec->dev,397 "EC reports too many ports: %d\n", response.port_count);398 return -EINVAL;399 }400 401 cros_ec_cec->num_ports = response.port_count;402 return 0;403}404 405static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)406{407 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;408 struct ec_params_get_cmd_versions_v1 params = {409 .cmd = EC_CMD_CEC_WRITE_MSG,410 };411 struct ec_response_get_cmd_versions response;412 int ret;413 414 ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms,415 sizeof(params), &response, sizeof(response));416 if (ret < 0) {417 dev_err(cros_ec->dev,418 "error getting CEC write command version: %d\n", ret);419 return ret;420 }421 422 if (response.version_mask & EC_VER_MASK(1)) {423 cros_ec_cec->write_cmd_version = 1;424 } else {425 if (cros_ec_cec->num_ports != 1) {426 dev_err(cros_ec->dev,427 "v0 write command only supports 1 port, %d reported\n",428 cros_ec_cec->num_ports);429 return -EINVAL;430 }431 cros_ec_cec->write_cmd_version = 0;432 }433 434 return 0;435}436 437static int cros_ec_cec_init_port(struct device *dev,438 struct cros_ec_cec *cros_ec_cec,439 int port_num, struct device *hdmi_dev,440 const char * const *conns)441{442 struct cros_ec_cec_port *port;443 int ret;444 445 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);446 if (!port)447 return -ENOMEM;448 449 port->cros_ec_cec = cros_ec_cec;450 port->port_num = port_num;451 452 port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME,453 CEC_CAP_DEFAULTS |454 CEC_CAP_CONNECTOR_INFO, 1);455 if (IS_ERR(port->adap))456 return PTR_ERR(port->adap);457 458 if (!conns[port_num]) {459 dev_err(dev, "no conn for port %d\n", port_num);460 ret = -ENODEV;461 goto out_probe_adapter;462 }463 464 port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],465 port->adap);466 if (!port->notify) {467 ret = -ENOMEM;468 goto out_probe_adapter;469 }470 471 ret = cec_register_adapter(port->adap, dev);472 if (ret < 0)473 goto out_probe_notify;474 475 cros_ec_cec->ports[port_num] = port;476 477 return 0;478 479out_probe_notify:480 cec_notifier_cec_adap_unregister(port->notify, port->adap);481out_probe_adapter:482 cec_delete_adapter(port->adap);483 return ret;484}485 486static int cros_ec_cec_probe(struct platform_device *pdev)487{488 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);489 struct cros_ec_device *cros_ec = ec_dev->ec_dev;490 struct cros_ec_cec *cros_ec_cec;491 struct cros_ec_cec_port *port;492 struct device *hdmi_dev;493 const char * const *conns = NULL;494 int ret;495 496 hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);497 if (IS_ERR(hdmi_dev))498 return PTR_ERR(hdmi_dev);499 500 cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec),501 GFP_KERNEL);502 if (!cros_ec_cec)503 return -ENOMEM;504 505 platform_set_drvdata(pdev, cros_ec_cec);506 cros_ec_cec->cros_ec = cros_ec;507 508 device_init_wakeup(&pdev->dev, 1);509 510 ret = cros_ec_cec_get_num_ports(cros_ec_cec);511 if (ret)512 return ret;513 514 ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);515 if (ret)516 return ret;517 518 for (int i = 0; i < cros_ec_cec->num_ports; i++) {519 ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,520 hdmi_dev, conns);521 if (ret)522 goto unregister_ports;523 }524 525 /* Get CEC events from the EC. */526 cros_ec_cec->notifier.notifier_call = cros_ec_cec_event;527 ret = blocking_notifier_chain_register(&cros_ec->event_notifier,528 &cros_ec_cec->notifier);529 if (ret) {530 dev_err(&pdev->dev, "failed to register notifier\n");531 goto unregister_ports;532 }533 534 return 0;535 536unregister_ports:537 /*538 * Unregister any adapters which have been registered. We don't add the539 * port to the array until the adapter has been registered successfully,540 * so any non-NULL ports must have been registered.541 */542 for (int i = 0; i < cros_ec_cec->num_ports; i++) {543 port = cros_ec_cec->ports[i];544 if (!port)545 break;546 cec_notifier_cec_adap_unregister(port->notify, port->adap);547 cec_unregister_adapter(port->adap);548 }549 return ret;550}551 552static void cros_ec_cec_remove(struct platform_device *pdev)553{554 struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);555 struct device *dev = &pdev->dev;556 struct cros_ec_cec_port *port;557 int ret;558 559 /*560 * blocking_notifier_chain_unregister() only fails if the notifier isn't561 * in the list. We know it was added to it by .probe(), so there should562 * be no need for error checking. Be cautious and still check.563 */564 ret = blocking_notifier_chain_unregister(565 &cros_ec_cec->cros_ec->event_notifier,566 &cros_ec_cec->notifier);567 if (ret)568 dev_err(dev, "failed to unregister notifier\n");569 570 for (int i = 0; i < cros_ec_cec->num_ports; i++) {571 port = cros_ec_cec->ports[i];572 cec_notifier_cec_adap_unregister(port->notify, port->adap);573 cec_unregister_adapter(port->adap);574 }575}576 577static const struct platform_device_id cros_ec_cec_id[] = {578 { DRV_NAME, 0 },579 {}580};581MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);582 583static struct platform_driver cros_ec_cec_driver = {584 .probe = cros_ec_cec_probe,585 .remove_new = cros_ec_cec_remove,586 .driver = {587 .name = DRV_NAME,588 .pm = &cros_ec_cec_pm_ops,589 },590 .id_table = cros_ec_cec_id,591};592 593module_platform_driver(cros_ec_cec_driver);594 595MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");596MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");597MODULE_LICENSE("GPL");598