All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports
@ 2023-08-14  4:29 Reka Norman
  2023-08-14  4:29 ` [PATCH 1/9] media: cros-ec-cec: Use cros_ec_cmd to send host commands Reka Norman
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media


The Google Dibbi chromebox will have two HDMI ports with CEC enabled via
its EC. Currently, the cros-ec-cec driver and the host command interface
to the EC assume there is only one port. E.g. the commands have no
parameter to indicated which port to operate on.

This series adds support for multiple ports. The driver is modified to
manage an array of ports, each with their own CEC adapter and notifier.
The host command interface is modified to support multiple ports. All
changes to interface are backwards compatible.


Reka Norman (9):
  media: cros-ec-cec: Use cros_ec_cmd to send host commands
  media: cros-ec-cec: Manage an array of ports
  media: cros-ec-cec: Support multiple ports in set/get host commands
  media: cros-ec-cec: Support multiple ports in write command
  media: cros-ec-cec: Support multiple ports in MKBP cec_events
  media: cros-ec-cec: Support receiving messages from multiple ports
  media: cros-ec-cec: Allow specifying multiple HDMI connectors
  media: cros-ec-cec: Get number of CEC ports from EC
  media: cros-ec-cec: Add Dibbi to the match table

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 376 ++++++++++++++----
 .../linux/platform_data/cros_ec_commands.h    |  66 ++-
 2 files changed, 354 insertions(+), 88 deletions(-)

-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/9] media: cros-ec-cec: Use cros_ec_cmd to send host commands
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 2/9] media: cros-ec-cec: Manage an array of ports Reka Norman
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Use the cros_ec_cmd helper function to reduce the amount of boilerplate
when sending host commands.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 44 +++++++------------
 1 file changed, 16 insertions(+), 28 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 c17faf002877..8dd95fb38546 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -95,18 +95,14 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
 {
 	struct cros_ec_cec *cros_ec_cec = adap->priv;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
-	struct {
-		struct cros_ec_command msg;
-		struct ec_params_cec_set data;
-	} __packed msg = {};
+	struct ec_params_cec_set params = {
+		.cmd = CEC_CMD_LOGICAL_ADDRESS,
+		.val = logical_addr,
+	};
 	int ret;
 
-	msg.msg.command = EC_CMD_CEC_SET;
-	msg.msg.outsize = sizeof(msg.data);
-	msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS;
-	msg.data.val = logical_addr;
-
-	ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
+	ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, &params, sizeof(params),
+			  NULL, 0);
 	if (ret < 0) {
 		dev_err(cros_ec->dev,
 			"error setting CEC logical address on EC: %d\n", ret);
@@ -121,17 +117,13 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
 {
 	struct cros_ec_cec *cros_ec_cec = adap->priv;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
-	struct {
-		struct cros_ec_command msg;
-		struct ec_params_cec_write data;
-	} __packed msg = {};
+	struct ec_params_cec_write params;
 	int ret;
 
-	msg.msg.command = EC_CMD_CEC_WRITE_MSG;
-	msg.msg.outsize = cec_msg->len;
-	memcpy(msg.data.msg, cec_msg->msg, cec_msg->len);
+	memcpy(params.msg, cec_msg->msg, cec_msg->len);
 
-	ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
+	ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, &params,
+			  cec_msg->len, NULL, 0);
 	if (ret < 0) {
 		dev_err(cros_ec->dev,
 			"error writing CEC msg on EC: %d\n", ret);
@@ -145,18 +137,14 @@ static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
 	struct cros_ec_cec *cros_ec_cec = adap->priv;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
-	struct {
-		struct cros_ec_command msg;
-		struct ec_params_cec_set data;
-	} __packed msg = {};
+	struct ec_params_cec_set params = {
+		.cmd = CEC_CMD_ENABLE,
+		.val = enable,
+	};
 	int ret;
 
-	msg.msg.command = EC_CMD_CEC_SET;
-	msg.msg.outsize = sizeof(msg.data);
-	msg.data.cmd = CEC_CMD_ENABLE;
-	msg.data.val = enable;
-
-	ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
+	ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, &params, sizeof(params),
+			  NULL, 0);
 	if (ret < 0) {
 		dev_err(cros_ec->dev,
 			"error %sabling CEC on EC: %d\n",
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/9] media: cros-ec-cec: Manage an array of ports
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
  2023-08-14  4:29 ` [PATCH 1/9] media: cros-ec-cec: Use cros_ec_cmd to send host commands Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 3/9] media: cros-ec-cec: Support multiple ports in set/get host commands Reka Norman
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

To support multiple CEC ports, change cros_ec_cec to contain an array of
ports, each with their own CEC adapter, etc.

For now, only create a single port and use that port everywhere, so
there is no functional change. Support for multiple ports will be added
in the following patches.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 147 +++++++++++++-----
 .../linux/platform_data/cros_ec_commands.h    |   2 +
 2 files changed, 110 insertions(+), 39 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 8dd95fb38546..d76a25ae0cf1 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -21,21 +21,40 @@
 
 #define DRV_NAME	"cros-ec-cec"
 
+/* Only one port is supported for now */
+#define CEC_NUM_PORTS	1
+#define CEC_PORT	0
+
 /**
- * struct cros_ec_cec - Driver data for EC CEC
+ * struct cros_ec_cec_port - Driver data for a single EC CEC port
  *
- * @cros_ec: Pointer to EC device
- * @notifier: Notifier info for responding to EC events
+ * @port_num: port number
  * @adap: CEC adapter
  * @notify: CEC notifier pointer
  * @rx_msg: storage for a received message
+ * @cros_ec_cec: pointer to the parent struct
  */
-struct cros_ec_cec {
-	struct cros_ec_device *cros_ec;
-	struct notifier_block notifier;
+struct cros_ec_cec_port {
+	int port_num;
 	struct cec_adapter *adap;
 	struct cec_notifier *notify;
 	struct cec_msg rx_msg;
+	struct cros_ec_cec *cros_ec_cec;
+};
+
+/**
+ * struct cros_ec_cec - Driver data for EC CEC
+ *
+ * @cros_ec: Pointer to EC device
+ * @notifier: Notifier info for responding to EC events
+ * @num_ports: Number of CEC ports
+ * @ports: Array of ports
+ */
+struct cros_ec_cec {
+	struct cros_ec_device *cros_ec;
+	struct notifier_block notifier;
+	int num_ports;
+	struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
 };
 
 static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
@@ -43,27 +62,28 @@ 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];
 
 	if (len > CEC_MAX_MSG_SIZE)
 		len = CEC_MAX_MSG_SIZE;
-	cros_ec_cec->rx_msg.len = len;
-	memcpy(cros_ec_cec->rx_msg.msg, cec_message, len);
+	port->rx_msg.len = len;
+	memcpy(port->rx_msg.msg, cec_message, len);
 
-	cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg);
+	cec_received_msg(port->adap, &port->rx_msg);
 }
 
 static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
 {
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	uint32_t events = cros_ec->event_data.data.cec_events;
+	struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT];
 
 	if (events & EC_MKBP_CEC_SEND_OK)
-		cec_transmit_attempt_done(cros_ec_cec->adap,
-					  CEC_TX_STATUS_OK);
+		cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
 
 	/* FW takes care of all retries, tell core to avoid more retries */
 	if (events & EC_MKBP_CEC_SEND_FAILED)
-		cec_transmit_attempt_done(cros_ec_cec->adap,
+		cec_transmit_attempt_done(port->adap,
 					  CEC_TX_STATUS_MAX_RETRIES |
 					  CEC_TX_STATUS_NACK);
 }
@@ -93,7 +113,8 @@ static int cros_ec_cec_event(struct notifier_block *nb,
 
 static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
 {
-	struct cros_ec_cec *cros_ec_cec = adap->priv;
+	struct cros_ec_cec_port *port = adap->priv;
+	struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_set params = {
 		.cmd = CEC_CMD_LOGICAL_ADDRESS,
@@ -115,7 +136,8 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
 static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
 				u32 signal_free_time, struct cec_msg *cec_msg)
 {
-	struct cros_ec_cec *cros_ec_cec = adap->priv;
+	struct cros_ec_cec_port *port = adap->priv;
+	struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_write params;
 	int ret;
@@ -135,7 +157,8 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
 
 static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
-	struct cros_ec_cec *cros_ec_cec = adap->priv;
+	struct cros_ec_cec_port *port = adap->priv;
+	struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_set params = {
 		.cmd = CEC_CMD_ENABLE,
@@ -260,11 +283,55 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
 
 #endif
 
+static int cros_ec_cec_init_port(struct device *dev,
+				 struct cros_ec_cec *cros_ec_cec,
+				 int port_num, struct device *hdmi_dev,
+				 const char *conn)
+{
+	struct cros_ec_cec_port *port;
+	int ret;
+
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->cros_ec_cec = cros_ec_cec;
+	port->port_num = port_num;
+
+	port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME,
+					  CEC_CAP_DEFAULTS |
+					  CEC_CAP_CONNECTOR_INFO, 1);
+	if (IS_ERR(port->adap))
+		return PTR_ERR(port->adap);
+
+	port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
+						      port->adap);
+	if (!port->notify) {
+		ret = -ENOMEM;
+		goto out_probe_adapter;
+	}
+
+	ret = cec_register_adapter(port->adap, dev);
+	if (ret < 0)
+		goto out_probe_notify;
+
+	cros_ec_cec->ports[port_num] = port;
+
+	return 0;
+
+out_probe_notify:
+	cec_notifier_cec_adap_unregister(port->notify, port->adap);
+out_probe_adapter:
+	cec_delete_adapter(port->adap);
+	return ret;
+}
+
 static int cros_ec_cec_probe(struct platform_device *pdev)
 {
 	struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
 	struct cros_ec_device *cros_ec = ec_dev->ec_dev;
 	struct cros_ec_cec *cros_ec_cec;
+	struct cros_ec_cec_port *port;
 	struct device *hdmi_dev;
 	const char *conn = NULL;
 	int ret;
@@ -283,18 +350,13 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 
 	device_init_wakeup(&pdev->dev, 1);
 
-	cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec,
-						 DRV_NAME,
-						 CEC_CAP_DEFAULTS |
-						 CEC_CAP_CONNECTOR_INFO, 1);
-	if (IS_ERR(cros_ec_cec->adap))
-		return PTR_ERR(cros_ec_cec->adap);
+	cros_ec_cec->num_ports = CEC_NUM_PORTS;
 
-	cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
-							     cros_ec_cec->adap);
-	if (!cros_ec_cec->notify) {
-		ret = -ENOMEM;
-		goto out_probe_adapter;
+	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
+		ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
+					    hdmi_dev, conn);
+		if (ret)
+			goto unregister_ports;
 	}
 
 	/* Get CEC events from the EC. */
@@ -303,20 +365,24 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 					       &cros_ec_cec->notifier);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register notifier\n");
-		goto out_probe_notify;
+		goto unregister_ports;
 	}
 
-	ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev);
-	if (ret < 0)
-		goto out_probe_notify;
-
 	return 0;
 
-out_probe_notify:
-	cec_notifier_cec_adap_unregister(cros_ec_cec->notify,
-					 cros_ec_cec->adap);
-out_probe_adapter:
-	cec_delete_adapter(cros_ec_cec->adap);
+unregister_ports:
+	/*
+	 * Unregister any adapters which have been registered. We don't add the
+	 * port to the array until the adapter has been registered successfully,
+	 * so any non-NULL ports must have been registered.
+	 */
+	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
+		port = cros_ec_cec->ports[i];
+		if (!port)
+			break;
+		cec_notifier_cec_adap_unregister(port->notify, port->adap);
+		cec_unregister_adapter(port->adap);
+	}
 	return ret;
 }
 
@@ -324,6 +390,7 @@ static void cros_ec_cec_remove(struct platform_device *pdev)
 {
 	struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);
 	struct device *dev = &pdev->dev;
+	struct cros_ec_cec_port *port;
 	int ret;
 
 	/*
@@ -337,9 +404,11 @@ static void cros_ec_cec_remove(struct platform_device *pdev)
 	if (ret)
 		dev_err(dev, "failed to unregister notifier\n");
 
-	cec_notifier_cec_adap_unregister(cros_ec_cec->notify,
-					 cros_ec_cec->adap);
-	cec_unregister_adapter(cros_ec_cec->adap);
+	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
+		port = cros_ec_cec->ports[i];
+		cec_notifier_cec_adap_unregister(port->notify, port->adap);
+		cec_unregister_adapter(port->adap);
+	}
 }
 
 static struct platform_driver cros_ec_cec_driver = {
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index ab721cf13a98..cb2ddd10a613 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4436,6 +4436,8 @@ struct ec_response_i2c_passthru_protect {
  * These commands are for sending and receiving message via HDMI CEC
  */
 
+#define EC_CEC_MAX_PORTS 16
+
 #define MAX_CEC_MSG_LEN 16
 
 /* CEC message from the AP to be written on the CEC bus */
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/9] media: cros-ec-cec: Support multiple ports in set/get host commands
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
  2023-08-14  4:29 ` [PATCH 1/9] media: cros-ec-cec: Use cros_ec_cmd to send host commands Reka Norman
  2023-08-14  4:29 ` [PATCH 2/9] media: cros-ec-cec: Manage an array of ports Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 4/9] media: cros-ec-cec: Support multiple ports in write command Reka Norman
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Reuse the top four bits of the cmd field to specify the port number.
The reason for doing this as opposed to adding a separate uint8_t field
is it avoids the need to add new versions of these commands. The change
is backwards compatible since these bits were previously always zero, so
the default behaviour is to always operate on port 0.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 2 ++
 include/linux/platform_data/cros_ec_commands.h   | 8 ++++++--
 2 files changed, 8 insertions(+), 2 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 d76a25ae0cf1..e969031e1e0e 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -118,6 +118,7 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_set params = {
 		.cmd = CEC_CMD_LOGICAL_ADDRESS,
+		.port = port->port_num,
 		.val = logical_addr,
 	};
 	int ret;
@@ -162,6 +163,7 @@ static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_set params = {
 		.cmd = CEC_CMD_ENABLE,
+		.port = port->port_num,
 		.val = enable,
 	};
 	int ret;
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index cb2ddd10a613..e8bb05db360f 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4457,13 +4457,15 @@ struct ec_params_cec_write {
 /**
  * struct ec_params_cec_set - CEC parameters set
  * @cmd: parameter type, can be CEC_CMD_ENABLE or CEC_CMD_LOGICAL_ADDRESS
+ * @port: CEC port to set the parameter on
  * @val: in case cmd is CEC_CMD_ENABLE, this field can be 0 to disable CEC
  *	or 1 to enable CEC functionality, in case cmd is
  *	CEC_CMD_LOGICAL_ADDRESS, this field encodes the requested logical
  *	address between 0 and 15 or 0xff to unregister
  */
 struct ec_params_cec_set {
-	uint8_t cmd; /* enum cec_command */
+	uint8_t cmd : 4; /* enum cec_command */
+	uint8_t port : 4;
 	uint8_t val;
 } __ec_align1;
 
@@ -4473,9 +4475,11 @@ struct ec_params_cec_set {
 /**
  * struct ec_params_cec_get - CEC parameters get
  * @cmd: parameter type, can be CEC_CMD_ENABLE or CEC_CMD_LOGICAL_ADDRESS
+ * @port: CEC port to get the parameter on
  */
 struct ec_params_cec_get {
-	uint8_t cmd; /* enum cec_command */
+	uint8_t cmd : 4; /* enum cec_command */
+	uint8_t port : 4;
 } __ec_align1;
 
 /**
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/9] media: cros-ec-cec: Support multiple ports in write command
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (2 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 3/9] media: cros-ec-cec: Support multiple ports in set/get host commands Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events Reka Norman
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Add a v1 of the CEC write command which contains a port parameter. Check
which versions of the write command the EC supports and use the highest
supported version. If it only supports v0, check that there is only one
port. With v0, the EC will assume all write commands are for port 0.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 54 +++++++++++++++++--
 .../linux/platform_data/cros_ec_commands.h    | 12 +++++
 2 files changed, 63 insertions(+), 3 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 e969031e1e0e..d674a432dfdd 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -47,12 +47,14 @@ struct cros_ec_cec_port {
  *
  * @cros_ec: Pointer to EC device
  * @notifier: Notifier info for responding to EC events
+ * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.
  * @num_ports: Number of CEC ports
  * @ports: Array of ports
  */
 struct cros_ec_cec {
 	struct cros_ec_device *cros_ec;
 	struct notifier_block notifier;
+	int write_cmd_version;
 	int num_ports;
 	struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
 };
@@ -141,12 +143,22 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
 	struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
 	struct ec_params_cec_write params;
+	struct ec_params_cec_write_v1 params_v1;
 	int ret;
 
-	memcpy(params.msg, cec_msg->msg, cec_msg->len);
+	if (cros_ec_cec->write_cmd_version == 0) {
+		memcpy(params.msg, cec_msg->msg, cec_msg->len);
+		ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, &params,
+				  cec_msg->len, NULL, 0);
+	} else {
+		params_v1.port = port->port_num;
+		params_v1.msg_len = cec_msg->len;
+		memcpy(params_v1.msg, cec_msg->msg, cec_msg->len);
+		ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version,
+				  EC_CMD_CEC_WRITE_MSG, &params_v1,
+				  sizeof(params_v1), NULL, 0);
+	}
 
-	ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, &params,
-			  cec_msg->len, NULL, 0);
 	if (ret < 0) {
 		dev_err(cros_ec->dev,
 			"error writing CEC msg on EC: %d\n", ret);
@@ -285,6 +297,38 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
 
 #endif
 
+static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
+{
+	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
+	struct ec_params_get_cmd_versions_v1 params = {
+		.cmd = EC_CMD_CEC_WRITE_MSG,
+	};
+	struct ec_response_get_cmd_versions response;
+	int ret;
+
+	ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, &params,
+			  sizeof(params), &response, sizeof(response));
+	if (ret < 0) {
+		dev_err(cros_ec->dev,
+			"error getting CEC write command version: %d\n", ret);
+		return ret;
+	}
+
+	if (response.version_mask & EC_VER_MASK(1)) {
+		cros_ec_cec->write_cmd_version = 1;
+	} else {
+		if (cros_ec_cec->num_ports != 1) {
+			dev_err(cros_ec->dev,
+				"v0 write command only supports 1 port, %d reported\n",
+				cros_ec_cec->num_ports);
+			return -EINVAL;
+		}
+		cros_ec_cec->write_cmd_version = 0;
+	}
+
+	return 0;
+}
+
 static int cros_ec_cec_init_port(struct device *dev,
 				 struct cros_ec_cec *cros_ec_cec,
 				 int port_num, struct device *hdmi_dev,
@@ -354,6 +398,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 
 	cros_ec_cec->num_ports = CEC_NUM_PORTS;
 
+	ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);
+	if (ret)
+		return ret;
+
 	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
 		ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
 					    hdmi_dev, conn);
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index e8bb05db360f..9a0c6e28f370 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4451,6 +4451,18 @@ struct ec_params_cec_write {
 	uint8_t msg[MAX_CEC_MSG_LEN];
 } __ec_align1;
 
+/**
+ * struct ec_params_cec_write_v1 - Message to write to the CEC bus
+ * @port: CEC port to write the message on
+ * @msg_len: length of msg in bytes
+ * @msg: message content to write to the CEC bus
+ */
+struct ec_params_cec_write_v1 {
+	uint8_t port;
+	uint8_t msg_len;
+	uint8_t msg[MAX_CEC_MSG_LEN];
+} __ec_align1;
+
 /* Set various CEC parameters */
 #define EC_CMD_CEC_SET 0x00BA
 
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (3 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 4/9] media: cros-ec-cec: Support multiple ports in write command Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-21  8:51   ` Hans Verkuil
  2023-08-14  4:29 ` [PATCH 6/9] media: cros-ec-cec: Support receiving messages from multiple ports Reka Norman
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Use the top four bits of the cec_events MKBP event to store the port
number.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 13 +++++++++++--
 include/linux/platform_data/cros_ec_commands.h   | 10 ++++++++++
 2 files changed, 21 insertions(+), 2 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 d674a432dfdd..eb4b778f83e9 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -77,8 +77,17 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
 static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
 {
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
-	uint32_t events = cros_ec->event_data.data.cec_events;
-	struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT];
+	uint32_t cec_events = cros_ec->event_data.data.cec_events;
+	int port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
+	uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
+	struct cros_ec_cec_port *port;
+
+	if (port_num < 0 || port_num >= cros_ec_cec->num_ports) {
+		dev_err(cros_ec->dev,
+			"received CEC event for invalid port %d\n", port_num);
+		return;
+	}
+	port = cros_ec_cec->ports[port_num];
 
 	if (events & EC_MKBP_CEC_SEND_OK)
 		cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 9a0c6e28f370..b7e8573a8a49 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4440,6 +4440,16 @@ struct ec_response_i2c_passthru_protect {
 
 #define MAX_CEC_MSG_LEN 16
 
+/*
+ * Helper macros for packing/unpacking cec_events.
+ * bits[27:0] : bitmask of events from enum mkbp_cec_event
+ * bits[31:28]: port number
+ */
+#define EC_MKBP_EVENT_CEC_PACK(events, port) \
+		(((events) & GENMASK(27, 0)) | (((port) & 0xf) << 28))
+#define EC_MKBP_EVENT_CEC_GET_EVENTS(event) ((event) & GENMASK(27, 0))
+#define EC_MKBP_EVENT_CEC_GET_PORT(event) (((event) >> 28) & 0xf)
+
 /* CEC message from the AP to be written on the CEC bus */
 #define EC_CMD_CEC_WRITE_MSG 0x00B8
 
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/9] media: cros-ec-cec: Support receiving messages from multiple ports
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (4 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors Reka Norman
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

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>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 59 +++++++++++++++++--
 .../linux/platform_data/cros_ec_commands.h    | 23 ++++++++
 2 files changed, 76 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 eb4b778f83e9..c68ed5d4bda0 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,
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index b7e8573a8a49..ad61c7ff0b28 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4473,6 +4473,27 @@ struct ec_params_cec_write_v1 {
 	uint8_t msg[MAX_CEC_MSG_LEN];
 } __ec_align1;
 
+/* CEC message read from a CEC bus reported back to the AP */
+#define EC_CMD_CEC_READ_MSG 0x00B9
+
+/**
+ * struct ec_params_cec_read - Read a message from the CEC bus
+ * @port: CEC port to read a message on
+ */
+struct ec_params_cec_read {
+	uint8_t port;
+} __ec_align1;
+
+/**
+ * struct ec_response_cec_read - Message read from the CEC bus
+ * @msg_len: length of msg in bytes
+ * @msg: message content read from the CEC bus
+ */
+struct ec_response_cec_read {
+	uint8_t msg_len;
+	uint8_t msg[MAX_CEC_MSG_LEN];
+} __ec_align1;
+
 /* Set various CEC parameters */
 #define EC_CMD_CEC_SET 0x00BA
 
@@ -4529,6 +4550,8 @@ enum mkbp_cec_event {
 	EC_MKBP_CEC_SEND_OK			= BIT(0),
 	/* Outgoing message was not acknowledged */
 	EC_MKBP_CEC_SEND_FAILED			= BIT(1),
+	/* Incoming message can be read out by AP */
+	EC_MKBP_CEC_HAVE_DATA			= BIT(2),
 };
 
 /*****************************************************************************/
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (5 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 6/9] media: cros-ec-cec: Support receiving messages from multiple ports Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-21  9:12   ` Hans Verkuil
  2023-08-14  4:29 ` [PATCH 8/9] media: cros-ec-cec: Get number of CEC ports from EC Reka Norman
  2023-08-14  4:29 ` [PATCH 9/9] media: cros-ec-cec: Add Dibbi to the match table Reka Norman
  8 siblings, 1 reply; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Update the cec_dmi_match_table to allow specifying multiple HDMI
connectors for each device.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 47 +++++++++++--------
 1 file changed, 28 insertions(+), 19 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 c68ed5d4bda0..f2f397d9a6d8 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -284,38 +284,41 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
 #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
 
 /*
- * The Firmware only handles a single CEC interface tied to a single HDMI
- * connector we specify along with the DRM device name handling the HDMI output
+ * Specify the DRM device name handling the HDMI output and the HDMI connector
+ * corresponding to each CEC port. The order of connectors must match the order
+ * in the EC (first connector is EC port 0, ...), and the number of connectors
+ * must match the number of ports in the EC (which can be queried using the
+ * EC_CMD_CEC_PORT_COUNT host command).
  */
 
 struct cec_dmi_match {
 	const char *sys_vendor;
 	const char *product_name;
 	const char *devname;
-	const char *conn;
+	const char *conns[EC_CEC_MAX_PORTS];
 };
 
 static const struct cec_dmi_match cec_dmi_match_table[] = {
 	/* Google Fizz */
-	{ "Google", "Fizz", "0000:00:02.0", "Port B" },
+	{ "Google", "Fizz", "0000:00:02.0", { "Port B" } },
 	/* Google Brask */
-	{ "Google", "Brask", "0000:00:02.0", "Port B" },
+	{ "Google", "Brask", "0000:00:02.0", { "Port B" } },
 	/* Google Moli */
-	{ "Google", "Moli", "0000:00:02.0", "Port B" },
+	{ "Google", "Moli", "0000:00:02.0", { "Port B" } },
 	/* Google Kinox */
-	{ "Google", "Kinox", "0000:00:02.0", "Port B" },
+	{ "Google", "Kinox", "0000:00:02.0", { "Port B" } },
 	/* Google Kuldax */
-	{ "Google", "Kuldax", "0000:00:02.0", "Port B" },
+	{ "Google", "Kuldax", "0000:00:02.0", { "Port B" } },
 	/* Google Aurash */
-	{ "Google", "Aurash", "0000:00:02.0", "Port B" },
+	{ "Google", "Aurash", "0000:00:02.0", { "Port B" } },
 	/* Google Gladios */
-	{ "Google", "Gladios", "0000:00:02.0", "Port B" },
+	{ "Google", "Gladios", "0000:00:02.0", { "Port B" } },
 	/* Google Lisbon */
-	{ "Google", "Lisbon", "0000:00:02.0", "Port B" },
+	{ "Google", "Lisbon", "0000:00:02.0", { "Port B" } },
 };
 
 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
-						const char **conn)
+						const char * const **conns)
 {
 	int i;
 
@@ -332,7 +335,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
 			if (!d)
 				return ERR_PTR(-EPROBE_DEFER);
 			put_device(d);
-			*conn = m->conn;
+			*conns = m->conns;
 			return d;
 		}
 	}
@@ -346,7 +349,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
 #else
 
 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
-						const char **conn)
+						const char * const **conns)
 {
 	return ERR_PTR(-ENODEV);
 }
@@ -388,7 +391,7 @@ static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
 static int cros_ec_cec_init_port(struct device *dev,
 				 struct cros_ec_cec *cros_ec_cec,
 				 int port_num, struct device *hdmi_dev,
-				 const char *conn)
+				 const char * const *conns)
 {
 	struct cros_ec_cec_port *port;
 	int ret;
@@ -406,7 +409,13 @@ static int cros_ec_cec_init_port(struct device *dev,
 	if (IS_ERR(port->adap))
 		return PTR_ERR(port->adap);
 
-	port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
+	if (!conns[port_num]) {
+		dev_err(dev, "no conn for port %d\n", port_num);
+		ret = -ENODEV;
+		goto out_probe_adapter;
+	}
+
+	port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
 						      port->adap);
 	if (!port->notify) {
 		ret = -ENOMEM;
@@ -435,10 +444,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 	struct cros_ec_cec *cros_ec_cec;
 	struct cros_ec_cec_port *port;
 	struct device *hdmi_dev;
-	const char *conn = NULL;
+	const char * const *conns = NULL;
 	int ret;
 
-	hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn);
+	hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
 	if (IS_ERR(hdmi_dev))
 		return PTR_ERR(hdmi_dev);
 
@@ -460,7 +469,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 
 	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
 		ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
-					    hdmi_dev, conn);
+					    hdmi_dev, conns);
 		if (ret)
 			goto unregister_ports;
 	}
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/9] media: cros-ec-cec: Get number of CEC ports from EC
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (6 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  2023-08-14  4:29 ` [PATCH 9/9] media: cros-ec-cec: Add Dibbi to the match table Reka Norman
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Add a new CEC port count host command and use it to query the number of
CEC ports from the EC. If the host command is not supported then it must
be old EC firmware which only supports one port, so fall back to
assuming one port.

This patch completes support for multiple ports in cros-ec-cec.

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 .../media/cec/platform/cros-ec/cros-ec-cec.c  | 40 ++++++++++++++++---
 .../linux/platform_data/cros_ec_commands.h    | 11 +++++
 2 files changed, 46 insertions(+), 5 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 f2f397d9a6d8..cfc0a204d591 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -21,10 +21,6 @@
 
 #define DRV_NAME	"cros-ec-cec"
 
-/* Only one port is supported for now */
-#define CEC_NUM_PORTS	1
-#define CEC_PORT	0
-
 /**
  * struct cros_ec_cec_port - Driver data for a single EC CEC port
  *
@@ -356,6 +352,38 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
 
 #endif
 
+static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec)
+{
+	struct ec_response_cec_port_count response;
+	int ret;
+
+	ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL,
+			  0, &response, sizeof(response));
+	if (ret < 0) {
+		/*
+		 * Old EC firmware only supports one port and does not support
+		 * the port count command, so fall back to assuming one port.
+		 */
+		cros_ec_cec->num_ports = 1;
+		return 0;
+	}
+
+	if (response.port_count == 0) {
+		dev_err(cros_ec_cec->cros_ec->dev,
+			"EC reports 0 CEC ports\n");
+		return -ENODEV;
+	}
+
+	if (response.port_count > EC_CEC_MAX_PORTS) {
+		dev_err(cros_ec_cec->cros_ec->dev,
+			"EC reports too many ports: %d\n", response.port_count);
+		return -EINVAL;
+	}
+
+	cros_ec_cec->num_ports = response.port_count;
+	return 0;
+}
+
 static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
 {
 	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
@@ -461,7 +489,9 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
 
 	device_init_wakeup(&pdev->dev, 1);
 
-	cros_ec_cec->num_ports = CEC_NUM_PORTS;
+	ret = cros_ec_cec_get_num_ports(cros_ec_cec);
+	if (ret)
+		return ret;
 
 	ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);
 	if (ret)
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index ad61c7ff0b28..7dae17b62a4d 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4536,6 +4536,17 @@ struct ec_response_cec_get {
 	uint8_t val;
 } __ec_align1;
 
+/* Get the number of CEC ports */
+#define EC_CMD_CEC_PORT_COUNT 0x00C1
+
+/**
+ * struct ec_response_cec_port_count - CEC port count response
+ * @port_count: number of CEC ports
+ */
+struct ec_response_cec_port_count {
+	uint8_t port_count;
+} __ec_align1;
+
 /* CEC parameters command */
 enum cec_command {
 	/* CEC reading, writing and events enable */
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 9/9] media: cros-ec-cec: Add Dibbi to the match table
  2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
                   ` (7 preceding siblings ...)
  2023-08-14  4:29 ` [PATCH 8/9] media: cros-ec-cec: Get number of CEC ports from EC Reka Norman
@ 2023-08-14  4:29 ` Reka Norman
  8 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-14  4:29 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Reka Norman,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

Dibbi has two HDMI ports which support CEC:
Port D is EC port 0
Port B is EC port 1

Signed-off-by: Reka Norman <rekanorman@chromium.org>
---

 drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 2 ++
 1 file changed, 2 insertions(+)

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 cfc0a204d591..29f9a464857b 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -311,6 +311,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
 	{ "Google", "Gladios", "0000:00:02.0", { "Port B" } },
 	/* Google Lisbon */
 	{ "Google", "Lisbon", "0000:00:02.0", { "Port B" } },
+	/* Google Dibbi */
+	{ "Google", "Dibbi", "0000:00:02.0", { "Port D", "Port B" } },
 };
 
 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
-- 
2.41.0.640.ga95def55d0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events
  2023-08-14  4:29 ` [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events Reka Norman
@ 2023-08-21  8:51   ` Hans Verkuil
  2023-08-25  2:58     ` Reka Norman
  0 siblings, 1 reply; 15+ messages in thread
From: Hans Verkuil @ 2023-08-21  8:51 UTC (permalink / raw)
  To: Reka Norman
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Benson Leung,
	Guenter Roeck, Mauro Carvalho Chehab, chrome-platform,
	linux-kernel, linux-media

Hi Reka,

On 14/08/2023 06:29, Reka Norman wrote:
> Use the top four bits of the cec_events MKBP event to store the port
> number.
> 
> Signed-off-by: Reka Norman <rekanorman@chromium.org>
> ---
> 
>  drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 13 +++++++++++--
>  include/linux/platform_data/cros_ec_commands.h   | 10 ++++++++++
>  2 files changed, 21 insertions(+), 2 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 d674a432dfdd..eb4b778f83e9 100644
> --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> @@ -77,8 +77,17 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
>  static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
>  {
>  	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
> -	uint32_t events = cros_ec->event_data.data.cec_events;
> -	struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT];
> +	uint32_t cec_events = cros_ec->event_data.data.cec_events;
> +	int port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
> +	uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
> +	struct cros_ec_cec_port *port;
> +
> +	if (port_num < 0 || port_num >= cros_ec_cec->num_ports) {

Since cec_events is unsigned, then I would also keep port_num unsigned.
Mixing signed and unsigned for bit shifting is a bit dangerous.

That will also mean that you can skip the 'port_num < 0' check.

Regards,

	Hans

> +		dev_err(cros_ec->dev,
> +			"received CEC event for invalid port %d\n", port_num);
> +		return;
> +	}
> +	port = cros_ec_cec->ports[port_num];
>  
>  	if (events & EC_MKBP_CEC_SEND_OK)
>  		cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
> diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
> index 9a0c6e28f370..b7e8573a8a49 100644
> --- a/include/linux/platform_data/cros_ec_commands.h
> +++ b/include/linux/platform_data/cros_ec_commands.h
> @@ -4440,6 +4440,16 @@ struct ec_response_i2c_passthru_protect {
>  
>  #define MAX_CEC_MSG_LEN 16
>  
> +/*
> + * Helper macros for packing/unpacking cec_events.
> + * bits[27:0] : bitmask of events from enum mkbp_cec_event
> + * bits[31:28]: port number
> + */
> +#define EC_MKBP_EVENT_CEC_PACK(events, port) \
> +		(((events) & GENMASK(27, 0)) | (((port) & 0xf) << 28))
> +#define EC_MKBP_EVENT_CEC_GET_EVENTS(event) ((event) & GENMASK(27, 0))
> +#define EC_MKBP_EVENT_CEC_GET_PORT(event) (((event) >> 28) & 0xf)
> +
>  /* CEC message from the AP to be written on the CEC bus */
>  #define EC_CMD_CEC_WRITE_MSG 0x00B8
>  


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors
  2023-08-14  4:29 ` [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors Reka Norman
@ 2023-08-21  9:12   ` Hans Verkuil
  2023-08-21 13:15     ` Guenter Roeck
  0 siblings, 1 reply; 15+ messages in thread
From: Hans Verkuil @ 2023-08-21  9:12 UTC (permalink / raw)
  To: Reka Norman
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Benson Leung,
	Guenter Roeck, Mauro Carvalho Chehab, chrome-platform,
	linux-kernel, linux-media

Hi Reka,

On 14/08/2023 06:29, Reka Norman wrote:
> Update the cec_dmi_match_table to allow specifying multiple HDMI
> connectors for each device.
> 
> Signed-off-by: Reka Norman <rekanorman@chromium.org>
> ---
> 
>  .../media/cec/platform/cros-ec/cros-ec-cec.c  | 47 +++++++++++--------
>  1 file changed, 28 insertions(+), 19 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 c68ed5d4bda0..f2f397d9a6d8 100644
> --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> @@ -284,38 +284,41 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
>  #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
>  
>  /*
> - * The Firmware only handles a single CEC interface tied to a single HDMI
> - * connector we specify along with the DRM device name handling the HDMI output
> + * Specify the DRM device name handling the HDMI output and the HDMI connector
> + * corresponding to each CEC port. The order of connectors must match the order
> + * in the EC (first connector is EC port 0, ...), and the number of connectors
> + * must match the number of ports in the EC (which can be queried using the
> + * EC_CMD_CEC_PORT_COUNT host command).
>   */
>  
>  struct cec_dmi_match {
>  	const char *sys_vendor;
>  	const char *product_name;
>  	const char *devname;
> -	const char *conn;
> +	const char *conns[EC_CEC_MAX_PORTS];

Since EC_CEC_MAX_PORTS is 16, this will waste a lot of space here.

I would suggest creating a separate define (CEC_MAX_PORTS?) that is set
to 2 and is the max port that is actually used.

When you get the actual number of ports from the EC you can check if
CEC_MAX_PORTS isn't too small and return an error if it is.

You can use CEC_MAX_PORTS here and in the ports array of struct cros_ec_cec.

Regards,

	Hans

>  };
>  
>  static const struct cec_dmi_match cec_dmi_match_table[] = {
>  	/* Google Fizz */
> -	{ "Google", "Fizz", "0000:00:02.0", "Port B" },
> +	{ "Google", "Fizz", "0000:00:02.0", { "Port B" } },
>  	/* Google Brask */
> -	{ "Google", "Brask", "0000:00:02.0", "Port B" },
> +	{ "Google", "Brask", "0000:00:02.0", { "Port B" } },
>  	/* Google Moli */
> -	{ "Google", "Moli", "0000:00:02.0", "Port B" },
> +	{ "Google", "Moli", "0000:00:02.0", { "Port B" } },
>  	/* Google Kinox */
> -	{ "Google", "Kinox", "0000:00:02.0", "Port B" },
> +	{ "Google", "Kinox", "0000:00:02.0", { "Port B" } },
>  	/* Google Kuldax */
> -	{ "Google", "Kuldax", "0000:00:02.0", "Port B" },
> +	{ "Google", "Kuldax", "0000:00:02.0", { "Port B" } },
>  	/* Google Aurash */
> -	{ "Google", "Aurash", "0000:00:02.0", "Port B" },
> +	{ "Google", "Aurash", "0000:00:02.0", { "Port B" } },
>  	/* Google Gladios */
> -	{ "Google", "Gladios", "0000:00:02.0", "Port B" },
> +	{ "Google", "Gladios", "0000:00:02.0", { "Port B" } },
>  	/* Google Lisbon */
> -	{ "Google", "Lisbon", "0000:00:02.0", "Port B" },
> +	{ "Google", "Lisbon", "0000:00:02.0", { "Port B" } },
>  };
>  
>  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> -						const char **conn)
> +						const char * const **conns)
>  {
>  	int i;
>  
> @@ -332,7 +335,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
>  			if (!d)
>  				return ERR_PTR(-EPROBE_DEFER);
>  			put_device(d);
> -			*conn = m->conn;
> +			*conns = m->conns;
>  			return d;
>  		}
>  	}
> @@ -346,7 +349,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
>  #else
>  
>  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> -						const char **conn)
> +						const char * const **conns)
>  {
>  	return ERR_PTR(-ENODEV);
>  }
> @@ -388,7 +391,7 @@ static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
>  static int cros_ec_cec_init_port(struct device *dev,
>  				 struct cros_ec_cec *cros_ec_cec,
>  				 int port_num, struct device *hdmi_dev,
> -				 const char *conn)
> +				 const char * const *conns)
>  {
>  	struct cros_ec_cec_port *port;
>  	int ret;
> @@ -406,7 +409,13 @@ static int cros_ec_cec_init_port(struct device *dev,
>  	if (IS_ERR(port->adap))
>  		return PTR_ERR(port->adap);
>  
> -	port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
> +	if (!conns[port_num]) {
> +		dev_err(dev, "no conn for port %d\n", port_num);
> +		ret = -ENODEV;
> +		goto out_probe_adapter;
> +	}
> +
> +	port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
>  						      port->adap);
>  	if (!port->notify) {
>  		ret = -ENOMEM;
> @@ -435,10 +444,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
>  	struct cros_ec_cec *cros_ec_cec;
>  	struct cros_ec_cec_port *port;
>  	struct device *hdmi_dev;
> -	const char *conn = NULL;
> +	const char * const *conns = NULL;
>  	int ret;
>  
> -	hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn);
> +	hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
>  	if (IS_ERR(hdmi_dev))
>  		return PTR_ERR(hdmi_dev);
>  
> @@ -460,7 +469,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
>  
>  	for (int i = 0; i < cros_ec_cec->num_ports; i++) {
>  		ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
> -					    hdmi_dev, conn);
> +					    hdmi_dev, conns);
>  		if (ret)
>  			goto unregister_ports;
>  	}


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors
  2023-08-21  9:12   ` Hans Verkuil
@ 2023-08-21 13:15     ` Guenter Roeck
  2023-08-25  3:03       ` Reka Norman
  0 siblings, 1 reply; 15+ messages in thread
From: Guenter Roeck @ 2023-08-21 13:15 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Reka Norman, Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

On Mon, Aug 21, 2023 at 2:12 AM Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> Hi Reka,
>
> On 14/08/2023 06:29, Reka Norman wrote:
> > Update the cec_dmi_match_table to allow specifying multiple HDMI
> > connectors for each device.
> >
> > Signed-off-by: Reka Norman <rekanorman@chromium.org>
> > ---
> >
> >  .../media/cec/platform/cros-ec/cros-ec-cec.c  | 47 +++++++++++--------
> >  1 file changed, 28 insertions(+), 19 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 c68ed5d4bda0..f2f397d9a6d8 100644
> > --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > @@ -284,38 +284,41 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
> >  #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
> >
> >  /*
> > - * The Firmware only handles a single CEC interface tied to a single HDMI
> > - * connector we specify along with the DRM device name handling the HDMI output
> > + * Specify the DRM device name handling the HDMI output and the HDMI connector
> > + * corresponding to each CEC port. The order of connectors must match the order
> > + * in the EC (first connector is EC port 0, ...), and the number of connectors
> > + * must match the number of ports in the EC (which can be queried using the
> > + * EC_CMD_CEC_PORT_COUNT host command).
> >   */
> >
> >  struct cec_dmi_match {
> >       const char *sys_vendor;
> >       const char *product_name;
> >       const char *devname;
> > -     const char *conn;
> > +     const char *conns[EC_CEC_MAX_PORTS];
>
> Since EC_CEC_MAX_PORTS is 16, this will waste a lot of space here.
>
> I would suggest creating a separate define (CEC_MAX_PORTS?) that is set
> to 2 and is the max port that is actually used.
>

Possibly it could also be declared as const char * const ** and be
terminated with NULL (though that would require {{ "Port B", NULL } in
the declarations). Not sure which one is better.

Guenter

> When you get the actual number of ports from the EC you can check if
> CEC_MAX_PORTS isn't too small and return an error if it is.
>
> You can use CEC_MAX_PORTS here and in the ports array of struct cros_ec_cec.
>
> Regards,
>
>         Hans
>
> >  };
> >
> >  static const struct cec_dmi_match cec_dmi_match_table[] = {
> >       /* Google Fizz */
> > -     { "Google", "Fizz", "0000:00:02.0", "Port B" },
> > +     { "Google", "Fizz", "0000:00:02.0", { "Port B" } },
> >       /* Google Brask */
> > -     { "Google", "Brask", "0000:00:02.0", "Port B" },
> > +     { "Google", "Brask", "0000:00:02.0", { "Port B" } },
> >       /* Google Moli */
> > -     { "Google", "Moli", "0000:00:02.0", "Port B" },
> > +     { "Google", "Moli", "0000:00:02.0", { "Port B" } },
> >       /* Google Kinox */
> > -     { "Google", "Kinox", "0000:00:02.0", "Port B" },
> > +     { "Google", "Kinox", "0000:00:02.0", { "Port B" } },
> >       /* Google Kuldax */
> > -     { "Google", "Kuldax", "0000:00:02.0", "Port B" },
> > +     { "Google", "Kuldax", "0000:00:02.0", { "Port B" } },
> >       /* Google Aurash */
> > -     { "Google", "Aurash", "0000:00:02.0", "Port B" },
> > +     { "Google", "Aurash", "0000:00:02.0", { "Port B" } },
> >       /* Google Gladios */
> > -     { "Google", "Gladios", "0000:00:02.0", "Port B" },
> > +     { "Google", "Gladios", "0000:00:02.0", { "Port B" } },
> >       /* Google Lisbon */
> > -     { "Google", "Lisbon", "0000:00:02.0", "Port B" },
> > +     { "Google", "Lisbon", "0000:00:02.0", { "Port B" } },
> >  };
> >
> >  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > -                                             const char **conn)
> > +                                             const char * const **conns)
> >  {
> >       int i;
> >
> > @@ -332,7 +335,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> >                       if (!d)
> >                               return ERR_PTR(-EPROBE_DEFER);
> >                       put_device(d);
> > -                     *conn = m->conn;
> > +                     *conns = m->conns;
> >                       return d;
> >               }
> >       }
> > @@ -346,7 +349,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> >  #else
> >
> >  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > -                                             const char **conn)
> > +                                             const char * const **conns)
> >  {
> >       return ERR_PTR(-ENODEV);
> >  }
> > @@ -388,7 +391,7 @@ static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
> >  static int cros_ec_cec_init_port(struct device *dev,
> >                                struct cros_ec_cec *cros_ec_cec,
> >                                int port_num, struct device *hdmi_dev,
> > -                              const char *conn)
> > +                              const char * const *conns)
> >  {
> >       struct cros_ec_cec_port *port;
> >       int ret;
> > @@ -406,7 +409,13 @@ static int cros_ec_cec_init_port(struct device *dev,
> >       if (IS_ERR(port->adap))
> >               return PTR_ERR(port->adap);
> >
> > -     port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
> > +     if (!conns[port_num]) {
> > +             dev_err(dev, "no conn for port %d\n", port_num);
> > +             ret = -ENODEV;
> > +             goto out_probe_adapter;
> > +     }
> > +
> > +     port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
> >                                                     port->adap);
> >       if (!port->notify) {
> >               ret = -ENOMEM;
> > @@ -435,10 +444,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
> >       struct cros_ec_cec *cros_ec_cec;
> >       struct cros_ec_cec_port *port;
> >       struct device *hdmi_dev;
> > -     const char *conn = NULL;
> > +     const char * const *conns = NULL;
> >       int ret;
> >
> > -     hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn);
> > +     hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
> >       if (IS_ERR(hdmi_dev))
> >               return PTR_ERR(hdmi_dev);
> >
> > @@ -460,7 +469,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
> >
> >       for (int i = 0; i < cros_ec_cec->num_ports; i++) {
> >               ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
> > -                                         hdmi_dev, conn);
> > +                                         hdmi_dev, conns);
> >               if (ret)
> >                       goto unregister_ports;
> >       }
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events
  2023-08-21  8:51   ` Hans Verkuil
@ 2023-08-25  2:58     ` Reka Norman
  0 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-25  2:58 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson, Benson Leung,
	Guenter Roeck, Mauro Carvalho Chehab, chrome-platform,
	linux-kernel, linux-media

Hi Hans,

Thanks for the review.

On Mon, Aug 21, 2023 at 6:51 PM Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> Hi Reka,
>
> On 14/08/2023 06:29, Reka Norman wrote:
> > Use the top four bits of the cec_events MKBP event to store the port
> > number.
> >
> > Signed-off-by: Reka Norman <rekanorman@chromium.org>
> > ---
> >
> >  drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 13 +++++++++++--
> >  include/linux/platform_data/cros_ec_commands.h   | 10 ++++++++++
> >  2 files changed, 21 insertions(+), 2 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 d674a432dfdd..eb4b778f83e9 100644
> > --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > @@ -77,8 +77,17 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
> >  static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
> >  {
> >       struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
> > -     uint32_t events = cros_ec->event_data.data.cec_events;
> > -     struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT];
> > +     uint32_t cec_events = cros_ec->event_data.data.cec_events;
> > +     int port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
> > +     uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
> > +     struct cros_ec_cec_port *port;
> > +
> > +     if (port_num < 0 || port_num >= cros_ec_cec->num_ports) {
>
> Since cec_events is unsigned, then I would also keep port_num unsigned.
> Mixing signed and unsigned for bit shifting is a bit dangerous.
>
> That will also mean that you can skip the 'port_num < 0' check.

Done in v2.

>
> Regards,
>
>         Hans
>
> > +             dev_err(cros_ec->dev,
> > +                     "received CEC event for invalid port %d\n", port_num);
> > +             return;
> > +     }
> > +     port = cros_ec_cec->ports[port_num];
> >
> >       if (events & EC_MKBP_CEC_SEND_OK)
> >               cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
> > diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
> > index 9a0c6e28f370..b7e8573a8a49 100644
> > --- a/include/linux/platform_data/cros_ec_commands.h
> > +++ b/include/linux/platform_data/cros_ec_commands.h
> > @@ -4440,6 +4440,16 @@ struct ec_response_i2c_passthru_protect {
> >
> >  #define MAX_CEC_MSG_LEN 16
> >
> > +/*
> > + * Helper macros for packing/unpacking cec_events.
> > + * bits[27:0] : bitmask of events from enum mkbp_cec_event
> > + * bits[31:28]: port number
> > + */
> > +#define EC_MKBP_EVENT_CEC_PACK(events, port) \
> > +             (((events) & GENMASK(27, 0)) | (((port) & 0xf) << 28))
> > +#define EC_MKBP_EVENT_CEC_GET_EVENTS(event) ((event) & GENMASK(27, 0))
> > +#define EC_MKBP_EVENT_CEC_GET_PORT(event) (((event) >> 28) & 0xf)
> > +
> >  /* CEC message from the AP to be written on the CEC bus */
> >  #define EC_CMD_CEC_WRITE_MSG 0x00B8
> >
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors
  2023-08-21 13:15     ` Guenter Roeck
@ 2023-08-25  3:03       ` Reka Norman
  0 siblings, 0 replies; 15+ messages in thread
From: Reka Norman @ 2023-08-25  3:03 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Hans Verkuil, Neil Armstrong, Daisuke Nojiri, Stefan Adolfsson,
	Benson Leung, Guenter Roeck, Mauro Carvalho Chehab,
	chrome-platform, linux-kernel, linux-media

On Mon, Aug 21, 2023 at 11:15 PM Guenter Roeck <groeck@google.com> wrote:
>
> On Mon, Aug 21, 2023 at 2:12 AM Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >
> > Hi Reka,
> >
> > On 14/08/2023 06:29, Reka Norman wrote:
> > > Update the cec_dmi_match_table to allow specifying multiple HDMI
> > > connectors for each device.
> > >
> > > Signed-off-by: Reka Norman <rekanorman@chromium.org>
> > > ---
> > >
> > >  .../media/cec/platform/cros-ec/cros-ec-cec.c  | 47 +++++++++++--------
> > >  1 file changed, 28 insertions(+), 19 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 c68ed5d4bda0..f2f397d9a6d8 100644
> > > --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > > +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> > > @@ -284,38 +284,41 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
> > >  #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
> > >
> > >  /*
> > > - * The Firmware only handles a single CEC interface tied to a single HDMI
> > > - * connector we specify along with the DRM device name handling the HDMI output
> > > + * Specify the DRM device name handling the HDMI output and the HDMI connector
> > > + * corresponding to each CEC port. The order of connectors must match the order
> > > + * in the EC (first connector is EC port 0, ...), and the number of connectors
> > > + * must match the number of ports in the EC (which can be queried using the
> > > + * EC_CMD_CEC_PORT_COUNT host command).
> > >   */
> > >
> > >  struct cec_dmi_match {
> > >       const char *sys_vendor;
> > >       const char *product_name;
> > >       const char *devname;
> > > -     const char *conn;
> > > +     const char *conns[EC_CEC_MAX_PORTS];
> >
> > Since EC_CEC_MAX_PORTS is 16, this will waste a lot of space here.
> >
> > I would suggest creating a separate define (CEC_MAX_PORTS?) that is set
> > to 2 and is the max port that is actually used.
> >
>
> Possibly it could also be declared as const char * const ** and be
> terminated with NULL (though that would require {{ "Port B", NULL } in
> the declarations). Not sure which one is better.

I went with Guenter's suggestion. Let me know what you think.

>
> Guenter
>
> > When you get the actual number of ports from the EC you can check if
> > CEC_MAX_PORTS isn't too small and return an error if it is.
> >
> > You can use CEC_MAX_PORTS here and in the ports array of struct cros_ec_cec.
> >
> > Regards,
> >
> >         Hans
> >
> > >  };
> > >
> > >  static const struct cec_dmi_match cec_dmi_match_table[] = {
> > >       /* Google Fizz */
> > > -     { "Google", "Fizz", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Fizz", "0000:00:02.0", { "Port B" } },
> > >       /* Google Brask */
> > > -     { "Google", "Brask", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Brask", "0000:00:02.0", { "Port B" } },
> > >       /* Google Moli */
> > > -     { "Google", "Moli", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Moli", "0000:00:02.0", { "Port B" } },
> > >       /* Google Kinox */
> > > -     { "Google", "Kinox", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Kinox", "0000:00:02.0", { "Port B" } },
> > >       /* Google Kuldax */
> > > -     { "Google", "Kuldax", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Kuldax", "0000:00:02.0", { "Port B" } },
> > >       /* Google Aurash */
> > > -     { "Google", "Aurash", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Aurash", "0000:00:02.0", { "Port B" } },
> > >       /* Google Gladios */
> > > -     { "Google", "Gladios", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Gladios", "0000:00:02.0", { "Port B" } },
> > >       /* Google Lisbon */
> > > -     { "Google", "Lisbon", "0000:00:02.0", "Port B" },
> > > +     { "Google", "Lisbon", "0000:00:02.0", { "Port B" } },
> > >  };
> > >
> > >  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > > -                                             const char **conn)
> > > +                                             const char * const **conns)
> > >  {
> > >       int i;
> > >
> > > @@ -332,7 +335,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > >                       if (!d)
> > >                               return ERR_PTR(-EPROBE_DEFER);
> > >                       put_device(d);
> > > -                     *conn = m->conn;
> > > +                     *conns = m->conns;
> > >                       return d;
> > >               }
> > >       }
> > > @@ -346,7 +349,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > >  #else
> > >
> > >  static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
> > > -                                             const char **conn)
> > > +                                             const char * const **conns)
> > >  {
> > >       return ERR_PTR(-ENODEV);
> > >  }
> > > @@ -388,7 +391,7 @@ static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
> > >  static int cros_ec_cec_init_port(struct device *dev,
> > >                                struct cros_ec_cec *cros_ec_cec,
> > >                                int port_num, struct device *hdmi_dev,
> > > -                              const char *conn)
> > > +                              const char * const *conns)
> > >  {
> > >       struct cros_ec_cec_port *port;
> > >       int ret;
> > > @@ -406,7 +409,13 @@ static int cros_ec_cec_init_port(struct device *dev,
> > >       if (IS_ERR(port->adap))
> > >               return PTR_ERR(port->adap);
> > >
> > > -     port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
> > > +     if (!conns[port_num]) {
> > > +             dev_err(dev, "no conn for port %d\n", port_num);
> > > +             ret = -ENODEV;
> > > +             goto out_probe_adapter;
> > > +     }
> > > +
> > > +     port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
> > >                                                     port->adap);
> > >       if (!port->notify) {
> > >               ret = -ENOMEM;
> > > @@ -435,10 +444,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
> > >       struct cros_ec_cec *cros_ec_cec;
> > >       struct cros_ec_cec_port *port;
> > >       struct device *hdmi_dev;
> > > -     const char *conn = NULL;
> > > +     const char * const *conns = NULL;
> > >       int ret;
> > >
> > > -     hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn);
> > > +     hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
> > >       if (IS_ERR(hdmi_dev))
> > >               return PTR_ERR(hdmi_dev);
> > >
> > > @@ -460,7 +469,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
> > >
> > >       for (int i = 0; i < cros_ec_cec->num_ports; i++) {
> > >               ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
> > > -                                         hdmi_dev, conn);
> > > +                                         hdmi_dev, conns);
> > >               if (ret)
> > >                       goto unregister_ports;
> > >       }
> >

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-08-25  3:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-14  4:29 [PATCH 0/9] media: cros-ec-cec: Add support for multiple ports Reka Norman
2023-08-14  4:29 ` [PATCH 1/9] media: cros-ec-cec: Use cros_ec_cmd to send host commands Reka Norman
2023-08-14  4:29 ` [PATCH 2/9] media: cros-ec-cec: Manage an array of ports Reka Norman
2023-08-14  4:29 ` [PATCH 3/9] media: cros-ec-cec: Support multiple ports in set/get host commands Reka Norman
2023-08-14  4:29 ` [PATCH 4/9] media: cros-ec-cec: Support multiple ports in write command Reka Norman
2023-08-14  4:29 ` [PATCH 5/9] media: cros-ec-cec: Support multiple ports in MKBP cec_events Reka Norman
2023-08-21  8:51   ` Hans Verkuil
2023-08-25  2:58     ` Reka Norman
2023-08-14  4:29 ` [PATCH 6/9] media: cros-ec-cec: Support receiving messages from multiple ports Reka Norman
2023-08-14  4:29 ` [PATCH 7/9] media: cros-ec-cec: Allow specifying multiple HDMI connectors Reka Norman
2023-08-21  9:12   ` Hans Verkuil
2023-08-21 13:15     ` Guenter Roeck
2023-08-25  3:03       ` Reka Norman
2023-08-14  4:29 ` [PATCH 8/9] media: cros-ec-cec: Get number of CEC ports from EC Reka Norman
2023-08-14  4:29 ` [PATCH 9/9] media: cros-ec-cec: Add Dibbi to the match table Reka Norman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.