summaryrefslogtreecommitdiffstats
path: root/drivers/media/cec
diff options
context:
space:
mode:
authorReka Norman <rekanorman@chromium.org>2023-08-25 04:43:59 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2023-09-27 09:39:54 +0200
commit425d20518c54bc6d66d733fb117a9a4046932d50 (patch)
treee18d8bf674d3545c616650b587cdd109fca44287 /drivers/media/cec
parentmedia: cros-ec-cec: Support multiple ports in MKBP cec_events (diff)
downloadlinux-425d20518c54bc6d66d733fb117a9a4046932d50.tar.xz
linux-425d20518c54bc6d66d733fb117a9a4046932d50.zip
media: cros-ec-cec: Support receiving messages from multiple ports
Currently, received messages are sent from the EC in the cec_message MKBP event. Since the size of ec_response_get_next_data_v1 is 16 bytes, which is also the maximum size of a CEC message, there is no space to add a port parameter. Increasing the size of ec_response_get_next_data_v1 is an option, but this would increase EC-kernel traffic for all MKBP event types. Instead, use an event to notify that data is ready, and add a new read command to read the data. For backwards compatibility with old EC firmware, continue to handle cec_message events as well. Signed-off-by: Reka Norman <rekanorman@chromium.org> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Diffstat (limited to 'drivers/media/cec')
-rw-r--r--drivers/media/cec/platform/cros-ec/cros-ec-cec.c59
1 files changed, 53 insertions, 6 deletions
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 18f78b7e034a..6989e63c05be 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -59,19 +59,63 @@ struct cros_ec_cec {
struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
};
+static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,
+ uint8_t *msg, uint8_t len)
+{
+ if (len > CEC_MAX_MSG_SIZE)
+ len = CEC_MAX_MSG_SIZE;
+
+ port->rx_msg.len = len;
+ memcpy(port->rx_msg.msg, msg, len);
+
+ cec_received_msg(port->adap, &port->rx_msg);
+}
+
static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
{
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
uint8_t *cec_message = cros_ec->event_data.data.cec_message;
unsigned int len = cros_ec->event_size;
- struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT];
+ struct cros_ec_cec_port *port;
+ /*
+ * There are two ways of receiving CEC messages:
+ * 1. Old EC firmware which only supports one port sends the data in a
+ * cec_message MKBP event.
+ * 2. New EC firmware which supports multiple ports uses
+ * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and
+ * EC_CMD_CEC_READ_MSG to read it.
+ * Check that the EC only has one CEC port, and then we can assume the
+ * message is from port 0.
+ */
+ if (cros_ec_cec->num_ports != 1) {
+ dev_err(cros_ec->dev,
+ "received cec_message on device with %d ports\n",
+ cros_ec_cec->num_ports);
+ return;
+ }
+ port = cros_ec_cec->ports[0];
- if (len > CEC_MAX_MSG_SIZE)
- len = CEC_MAX_MSG_SIZE;
- port->rx_msg.len = len;
- memcpy(port->rx_msg.msg, cec_message, len);
+ cros_ec_cec_received_message(port, cec_message, len);
+}
- cec_received_msg(port->adap, &port->rx_msg);
+static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)
+{
+ struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;
+ struct ec_params_cec_read params = {
+ .port = port->port_num,
+ };
+ struct ec_response_cec_read response;
+ int ret;
+
+ ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, &params,
+ sizeof(params), &response, sizeof(response));
+ if (ret < 0) {
+ dev_err(cros_ec->dev,
+ "error reading CEC message on EC: %d\n", ret);
+ return;
+ }
+
+ cros_ec_cec_received_message(port, response.msg, response.msg_len);
}
static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
@@ -97,6 +141,9 @@ static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
cec_transmit_attempt_done(port->adap,
CEC_TX_STATUS_MAX_RETRIES |
CEC_TX_STATUS_NACK);
+
+ if (events & EC_MKBP_CEC_HAVE_DATA)
+ cros_ec_cec_read_message(port);
}
static int cros_ec_cec_event(struct notifier_block *nb,