linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/13] TVP5150 new features
@ 2019-04-15 12:44 Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
                   ` (13 more replies)
  0 siblings, 14 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

Hi,

many thanks to Hans and Jacopo for the feedack :) this v6 address the
comments both made on my v5 [1].

In short this is round fixes just some minor issues rather than major
ones so the diff to the v5 is really small. The changed patches contain
the changelog so I omit it here.

I've tested it on a custom hardware but I can't test the em28xx usb
use-case since I haven't such a device. So other testers are welcome :)

Looking forward for your feedack,

	Marco

[1] https://patchwork.kernel.org/cover/10886903/

Javier Martinez Canillas (1):
  partial revert of "[media] tvp5150: add HW input connectors support"

Marco Felsch (11):
  dt-bindings: connector: analog: add tv norms property
  media: v4l2-fwnode: add v4l2_fwnode_connector
  media: v4l2-fwnode: add initial connector parsing support
  media: tvp5150: add input source selection of_graph support
  media: dt-bindings: tvp5150: Add input port connectors DT bindings
  media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  media: tvp5150: add s_power callback
  media: dt-bindings: tvp5150: cleanup bindings stlye
  media: dt-bindings: tvp5150: add optional tvnorms documentation
  media: tvp5150: add support to limit tv norms on connector
  media: tvp5150: make debug output more readable

Michael Tretter (1):
  media: tvp5150: initialize subdev before parsing device tree

 .../display/connector/analog-tv-connector.txt |   4 +
 .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
 drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
 drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
 include/dt-bindings/media/tvnorms.h           |  56 ++
 include/dt-bindings/media/tvp5150.h           |   2 -
 include/media/v4l2-connector.h                |  30 +
 include/media/v4l2-fwnode.h                   |  49 ++
 8 files changed, 859 insertions(+), 190 deletions(-)
 create mode 100644 include/dt-bindings/media/tvnorms.h
 create mode 100644 include/media/v4l2-connector.h

-- 
2.20.1


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

* [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06 10:01   ` Hans Verkuil
  2019-05-16 16:27   ` Laurent Pinchart
  2019-04-15 12:44 ` [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

Some connectors no matter if in- or output supports only a limited
range of tv norms. It doesn't matter if the hardware behind that
connector supports more than the listed formats since the users are
restriced by a label e.g. to plug only a camera into this connector
which uses the PAL format.

This patch adds the capability to describe such limitation within the
firmware. There are no format restrictions if the property isn't
present, so it's completely backward compatible.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
[1] https://patchwork.kernel.org/cover/10794703/

v6:
- tvnorms.h: use tabs instead of spaces
- tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
- tvnorms.h: drop rarely used TVNORM_ATSC_* norms

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.

 .../display/connector/analog-tv-connector.txt |  4 ++
 include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
 2 files changed, 60 insertions(+)
 create mode 100644 include/dt-bindings/media/tvnorms.h

diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
index 0c0970c210ab..346f8937a0b7 100644
--- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
+++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
@@ -6,6 +6,9 @@ Required properties:
 
 Optional properties:
 - label: a symbolic name for the connector
+- tvnorms: limit the supported tv norms on a connector to the given ones else
+           all tv norms are allowed. Possible video standards are defined in
+           include/dt-bindings/media/tvnorms.h.
 
 Required nodes:
 - Video port for TV input
@@ -16,6 +19,7 @@ Example
 tv: connector {
 	compatible = "composite-video-connector";
 	label = "tv";
+	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
 
 	port {
 		tv_connector_in: endpoint {
diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
new file mode 100644
index 000000000000..058ab8414145
--- /dev/null
+++ b/include/dt-bindings/media/tvnorms.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only or X11 */
+/*
+ * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
+#define _DT_BINDINGS_MEDIA_TVNORMS_H
+
+/* one bit for each */
+#define TVNORM_PAL_B		0x00000001
+#define TVNORM_PAL_B1		0x00000002
+#define TVNORM_PAL_G		0x00000004
+#define TVNORM_PAL_H		0x00000008
+#define TVNORM_PAL_I		0x00000010
+#define TVNORM_PAL_D		0x00000020
+#define TVNORM_PAL_D1		0x00000040
+#define TVNORM_PAL_K		0x00000080
+
+#define TVNORM_PAL		(TVNORM_PAL_B  | \
+				 TVNORM_PAL_B1 | \
+				 TVNORM_PAL_G  | \
+				 TVNORM_PAL_H  | \
+				 TVNORM_PAL_I  | \
+				 TVNORM_PAL_D  | \
+				 TVNORM_PAL_D1 | \
+				 TVNORM_PAL_K)
+
+#define TVNORM_PAL_M		0x00000100
+#define TVNORM_PAL_N		0x00000200
+#define TVNORM_PAL_Nc		0x00000400
+#define TVNORM_PAL_60		0x00000800
+
+#define TVNORM_NTSC_M		0x00001000	/* BTSC */
+#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
+#define TVNORM_NTSC_443		0x00004000
+#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
+
+#define TVNORM_SECAM_B		0x00010000
+#define TVNORM_SECAM_D		0x00020000
+#define TVNORM_SECAM_G		0x00040000
+#define TVNORM_SECAM_H		0x00080000
+#define TVNORM_SECAM_K		0x00100000
+#define TVNORM_SECAM_K1		0x00200000
+#define TVNORM_SECAM_L		0x00400000
+#define TVNORM_SECAM_LC		0x00800000
+
+#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
+				 TVNORM_SECAM_D  | \
+				 TVNORM_SECAM_G  | \
+				 TVNORM_SECAM_H  | \
+				 TVNORM_SECAM_K  | \
+				 TVNORM_SECAM_K1 | \
+				 TVNORM_SECAM_L  | \
+				 TVNORM_SECAM_LC)
+
+#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
-- 
2.20.1


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

* [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06  9:50   ` Hans Verkuil
  2019-05-16 16:36   ` Laurent Pinchart
  2019-04-15 12:44 ` [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi

Currently every driver needs to parse the connector endpoints by it self.
This is the initial work to make this generic. The generic connector has
some common fields and some connector specific parts. The generic one
includes:
  - type
  - label
  - remote_port (the port where the connector is connected to)
  - remote_id   (the endpoint where the connector is connected to)

The specific fields are within a union, since only one of them can be
available at the time. Since this is the initial support the patch adds
only the analog-connector specific ones.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
---
[1] https://patchwork.kernel.org/cover/10794703/

v6:
- fix some spelling and style issues
- rm unnecessary comments
- drop vga and dvi connector

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.

 include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
 include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 include/media/v4l2-connector.h

diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
new file mode 100644
index 000000000000..3a951c54f50e
--- /dev/null
+++ b/include/media/v4l2-connector.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * v4l2-connector.h
+ *
+ * V4L2 connector types.
+ *
+ * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#ifndef V4L2_CONNECTOR_H
+#define V4L2_CONNECTOR_H
+
+#define V4L2_CONNECTOR_MAX_LABEL 41
+
+/**
+ * enum v4l2_connector_type - connector type
+ * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
+ * @V4L2_CON_COMPOSITE: analog composite connector
+ * @V4L2_CON_SVIDEO:    analog svideo connector
+ * @V4L2_CON_HDMI:      digital hdmi connector
+ */
+enum v4l2_connector_type {
+	V4L2_CON_UNKNOWN,
+	V4L2_CON_COMPOSITE,
+	V4L2_CON_SVIDEO,
+	V4L2_CON_HDMI,
+};
+
+#endif /* V4L2_CONNECTOR_H */
+
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 6c07825e18b9..f4df1b95c5ef 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
+#include <media/v4l2-connector.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-subdev.h>
 
@@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
 	unsigned int remote_port;
 };
 
+/**
+ * struct v4l2_fwnode_connector_analog - analog connector data structure
+ * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
+ *                     if no restrictions are specified.
+ */
+struct v4l2_fwnode_connector_analog {
+	v4l2_std_id supported_tvnorms;
+};
+
+/**
+ * struct v4l2_fwnode_connector - the connector data structure
+ * @remote_port: identifier of the remote endpoint port the connector connects
+ *		 to
+ * @remote_id: identifier of the remote endpoint the connector connects to
+ * @label: connetor label
+ * @type: connector type
+ * @connector: connector configuration
+ * @connector.analog: analog connector configuration
+ *                    &struct v4l2_fwnode_connector_analog
+ */
+struct v4l2_fwnode_connector {
+	unsigned int remote_port;
+	unsigned int remote_id;
+	char label[V4L2_CONNECTOR_MAX_LABEL];
+	enum v4l2_connector_type type;
+
+	union {
+		struct v4l2_fwnode_connector_analog analog;
+		/* future connectors */
+	} connector;
+};
+
 /**
  * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
  * @fwnode: pointer to the endpoint's fwnode handle
-- 
2.20.1


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

* [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06 10:10   ` Hans Verkuil
  2019-04-15 12:44 ` [PATCH v6 04/13] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi

The patch adds the initial connector parsing code, so we can move from a
driver specific parsing code to a generic one. Currently only the
generic fields and the analog-connector specific fields are parsed. Parsing
the other connector specific fields can be added by a simple callbacks.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
---
[1] https://patchwork.kernel.org/cover/10794703/

v6:
- use 'unsigned int' count var
- fix comment and style issues
- place '/* fall through */' to correct places
- fix error handling and cleanup by releasing fwnode
- drop vga and dvi parsing support as those connectors are rarely used
  these days

v5:
- s/strlcpy/strscpy/

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.

 drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
 include/media/v4l2-fwnode.h           |  16 ++++
 2 files changed, 127 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 20571846e636..f1cca95c8fef 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 
+static const struct v4l2_fwnode_connector_conv {
+	enum v4l2_connector_type type;
+	const char *name;
+} connectors[] = {
+	{
+		.type = V4L2_CON_COMPOSITE,
+		.name = "composite-video-connector",
+	}, {
+		.type = V4L2_CON_SVIDEO,
+		.name = "svideo-connector",
+	}, {
+		.type = V4L2_CON_HDMI,
+		.name = "hdmi-connector",
+	},
+};
+
+static enum v4l2_connector_type
+v4l2_fwnode_string_to_connector_type(const char *con_str)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(connectors); i++)
+		if (!strcmp(con_str, connectors[i].name))
+			return connectors[i].type;
+
+	/* no valid connector found */
+	return V4L2_CON_UNKNOWN;
+}
+
+static int
+v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
+				   struct v4l2_fwnode_connector *vc)
+{
+	u32 tvnorms;
+	int ret;
+
+	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
+
+	/* tvnorms is optional */
+	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
+
+	return 0;
+}
+
+int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
+				struct v4l2_fwnode_connector *connector)
+{
+	struct fwnode_handle *fwnode;
+	struct fwnode_endpoint __ep;
+	const char *c_type_str, *label;
+	int ret;
+
+	memset(connector, 0, sizeof(*connector));
+
+	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
+	if (!fwnode)
+		return -EINVAL;
+
+	/* parse all common properties first */
+	/* connector-type is stored within the compatible string */
+	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
+	if (ret) {
+		fwnode_handle_put(fwnode);
+		return -EINVAL;
+	}
+
+	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
+
+	fwnode_graph_parse_endpoint(__fwnode, &__ep);
+	connector->remote_port = __ep.port;
+	connector->remote_id = __ep.id;
+
+	ret = fwnode_property_read_string(fwnode, "label", &label);
+	if (!ret) {
+		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
+		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
+	} else {
+		/*
+		 * labels are optional, if none is given create one:
+		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
+		 */
+		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
+			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
+			 connector->remote_id);
+	}
+
+	/* now parse the connector specific properties */
+	switch (connector->type) {
+	case V4L2_CON_COMPOSITE:
+		/* fall through */
+	case V4L2_CON_SVIDEO:
+		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
+		break;
+	case V4L2_CON_HDMI:
+		pr_warn("Connector specific parsing is currently not supported for %s\n",
+			c_type_str);
+		ret = 0;
+		break;
+	case V4L2_CON_UNKNOWN:
+		/* fall through */
+	default:
+		pr_err("Unknown connector type\n");
+		ret = -EINVAL;
+	};
+
+	fwnode_handle_put(fwnode);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
+
 static int
 v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
 					  struct v4l2_async_notifier *notifier,
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index f4df1b95c5ef..e072f2915ddb 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
  */
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
 
+/**
+ * v4l2_fwnode_parse_connector() - parse the connector on endpoint
+ * @fwnode: pointer to the endpoint's fwnode handle where the connector is
+ *          connected to
+ * @connector: pointer to the V4L2 fwnode connector data structure
+ *
+ * Fill the connector data structure with the connector type, label and the
+ * endpoint id and port where the connector belongs to. If no label is present
+ * a unique one will be created. Labels with more than 40 characters are cut.
+ *
+ * Return: %0 on success or a negative error code on failure:
+ *	   %-EINVAL on parsing failure
+ */
+int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
+				struct v4l2_fwnode_connector *connector);
+
 /**
  * typedef parse_endpoint_func - Driver's callback function to be called on
  *	each V4L2 fwnode endpoint.
-- 
2.20.1


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

* [PATCH v6 04/13] partial revert of "[media] tvp5150: add HW input connectors support"
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (2 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support Marco Felsch
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel,
	Javier Martinez Canillas, Mauro Carvalho Chehab, Rob Herring

From: Javier Martinez Canillas <javierm@redhat.com>

Commit f7b4b54e6364 ("[media] tvp5150: add HW input connectors support")
added input signals support for the tvp5150, but the approach was found
to be incorrect so the corresponding DT binding commit 82c2ffeb217a
("[media] tvp5150: document input connectors DT bindings") was reverted.

This left the driver with an undocumented (and wrong) DT parsing logic,
so lets get rid of this code as well until the input connectors support
is implemented properly.

It's a partial revert due other patches added on top of mentioned commit
not allowing the commit to be reverted cleanly anymore. But all the code
related to the DT parsing logic and input entities creation are removed.

Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
[m.felsch@pengutronix.de: rm TVP5150_INPUT_NUM define]
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 drivers/media/i2c/tvp5150.c         | 141 ----------------------------
 include/dt-bindings/media/tvp5150.h |   2 -
 2 files changed, 143 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index eaddd977ba40..89da921c8886 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -53,8 +53,6 @@ struct tvp5150 {
 	struct v4l2_subdev sd;
 #ifdef CONFIG_MEDIA_CONTROLLER
 	struct media_pad pads[TVP5150_NUM_PADS];
-	struct media_entity input_ent[TVP5150_INPUT_NUM];
-	struct media_pad input_pad[TVP5150_INPUT_NUM];
 #endif
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_rect rect;
@@ -1169,40 +1167,6 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
-/****************************************************************************
-			Media entity ops
- ****************************************************************************/
-
-#ifdef CONFIG_MEDIA_CONTROLLER
-static int tvp5150_link_setup(struct media_entity *entity,
-			      const struct media_pad *local,
-			      const struct media_pad *remote, u32 flags)
-{
-	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
-	struct tvp5150 *decoder = to_tvp5150(sd);
-	int i;
-
-	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-		if (remote->entity == &decoder->input_ent[i])
-			break;
-	}
-
-	/* Do nothing for entities that are not input connectors */
-	if (i == TVP5150_INPUT_NUM)
-		return 0;
-
-	decoder->input = i;
-
-	tvp5150_selmux(sd);
-
-	return 0;
-}
-
-static const struct media_entity_operations tvp5150_sd_media_ops = {
-	.link_setup = tvp5150_link_setup,
-};
-#endif
-
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
@@ -1350,42 +1314,6 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	return 0;
 }
 
-static int tvp5150_registered(struct v4l2_subdev *sd)
-{
-#ifdef CONFIG_MEDIA_CONTROLLER
-	struct tvp5150 *decoder = to_tvp5150(sd);
-	int ret = 0;
-	int i;
-
-	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-		struct media_entity *input = &decoder->input_ent[i];
-		struct media_pad *pad = &decoder->input_pad[i];
-
-		if (!input->name)
-			continue;
-
-		decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
-
-		ret = media_entity_pads_init(input, 1, pad);
-		if (ret < 0)
-			return ret;
-
-		ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
-		if (ret < 0)
-			return ret;
-
-		ret = media_create_pad_link(input, 0, &sd->entity,
-					    TVP5150_PAD_IF_INPUT, 0);
-		if (ret < 0) {
-			media_device_unregister_entity(input);
-			return ret;
-		}
-	}
-#endif
-
-	return 0;
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1439,10 +1367,6 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 	.pad = &tvp5150_pad_ops,
 };
 
-static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
-	.registered = tvp5150_registered,
-};
-
 /****************************************************************************
 			I2C Client & Driver
  ****************************************************************************/
@@ -1595,12 +1519,6 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
 {
 	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
 	struct device_node *ep;
-#ifdef CONFIG_MEDIA_CONTROLLER
-	struct device_node *connectors, *child;
-	struct media_entity *input;
-	const char *name;
-	u32 input_type;
-#endif
 	unsigned int flags;
 	int ret = 0;
 
@@ -1624,63 +1542,6 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
 
 	decoder->mbus_type = bus_cfg.bus_type;
 
-#ifdef CONFIG_MEDIA_CONTROLLER
-	connectors = of_get_child_by_name(np, "connectors");
-
-	if (!connectors)
-		goto err;
-
-	for_each_available_child_of_node(connectors, child) {
-		ret = of_property_read_u32(child, "input", &input_type);
-		if (ret) {
-			dev_err(decoder->sd.dev,
-				 "missing type property in node %pOFn\n",
-				 child);
-			goto err_connector;
-		}
-
-		if (input_type >= TVP5150_INPUT_NUM) {
-			ret = -EINVAL;
-			goto err_connector;
-		}
-
-		input = &decoder->input_ent[input_type];
-
-		/* Each input connector can only be defined once */
-		if (input->name) {
-			dev_err(decoder->sd.dev,
-				 "input %s with same type already exists\n",
-				 input->name);
-			ret = -EINVAL;
-			goto err_connector;
-		}
-
-		switch (input_type) {
-		case TVP5150_COMPOSITE0:
-		case TVP5150_COMPOSITE1:
-			input->function = MEDIA_ENT_F_CONN_COMPOSITE;
-			break;
-		case TVP5150_SVIDEO:
-			input->function = MEDIA_ENT_F_CONN_SVIDEO;
-			break;
-		}
-
-		input->flags = MEDIA_ENT_FL_CONNECTOR;
-
-		ret = of_property_read_string(child, "label", &name);
-		if (ret < 0) {
-			dev_err(decoder->sd.dev,
-				 "missing label property in node %pOFn\n",
-				 child);
-			goto err_connector;
-		}
-
-		input->name = name;
-	}
-
-err_connector:
-	of_node_put(connectors);
-#endif
 err:
 	of_node_put(ep);
 	return ret;
@@ -1732,7 +1593,6 @@ static int tvp5150_probe(struct i2c_client *c,
 	}
 
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
-	sd->internal_ops = &tvp5150_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
@@ -1747,7 +1607,6 @@ static int tvp5150_probe(struct i2c_client *c,
 	if (res < 0)
 		return res;
 
-	sd->entity.ops = &tvp5150_sd_media_ops;
 #endif
 
 	res = tvp5150_detect_version(core);
diff --git a/include/dt-bindings/media/tvp5150.h b/include/dt-bindings/media/tvp5150.h
index c852a35e916e..8637910aae76 100644
--- a/include/dt-bindings/media/tvp5150.h
+++ b/include/dt-bindings/media/tvp5150.h
@@ -26,8 +26,6 @@
 #define TVP5150_COMPOSITE1 1
 #define TVP5150_SVIDEO     2
 
-#define TVP5150_INPUT_NUM  3
-
 /* TVP5150 HW outputs */
 #define TVP5150_NORMAL       0
 #define TVP5150_BLACK_SCREEN 1
-- 
2.20.1


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

* [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (3 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 04/13] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06 10:09   ` Jacopo Mondi
  2019-05-14 18:25   ` Mauro Carvalho Chehab
  2019-04-15 12:44 ` [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
                   ` (8 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

This patch adds the of_graph support to describe the tvp connections.
Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
connector must be conneted to port@0/endpoint@1, look at the Documentation
for more information. Since the TVP5150 is a converter the device-tree
must contain at least 1-input and 1-output port. The mc-connectors and
mc-links are only created if the device-tree contains the corresponding
connector nodes. If more than one connector is available the
media_entity_operations.link_setup() callback ensures that only one
connector is active.

[1] https://www.spinics.net/lists/linux-media/msg138545.html
[2] https://www.spinics.net/lists/linux-media/msg138546.html

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:

[1] https://patchwork.kernel.org/cover/10794703/
[2] https://patchwork.kernel.org/cover/10786553/

v6:
- fix misspelled comments
- use 'unsigned int' where it's possible
- cleanup ifdef part-2:
  - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
    CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
- tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
  internal function do this.
- tvp5150_add_of_connectors: call within probe() to make it cleaner
- tvp5150_parse_dt: move local loop vars within the loop.

v5:
- Fixing build deps:
  - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
  - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
    includes. This leads into to complex deps for futher development.
  - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
  - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
  - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled

- Simplify link_setup routine:
  - use generic connector parsing since both series [1,2] are squashed into
    one
  - struct tvp5150: drop pads_state and modify_second_link property
    due to link_setup() rework.
  - tvp5150_link_setup: add more comments
  - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
    link directly within the driver instead of a recursive media-framework
    call (__media_entity_setup_link). This improves the readability and
    shrinks the driver code.
  - tvp5150_link_setup: disable all active links in case user switches
    connectors without disable it first.
  - tvp5150_registered: simplify default link enable path due to link_setup()
    rework.

- General cleanups
  - tvp5150_parse_dt: drop unecessary test
  - tvp5150_parse_dt: add err message due to misconfiguration
  - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
  - s/dev_dbg/dev_dbg_lvl

v4:
 - rebase on top of media_tree/master, fix merge conflict due to commit
   60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
   to zero")

v3:
- probe(): s/err/err_free_v4l2_ctrls
- drop MC dependency for tvp5150_pads

v2:
- adapt commit message
- unify ifdef switches
- rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
- mc: use 2-input and 1-output pad
- mc: link svideo connector to both input pads
- mc: enable/disable svideo links in one go
- mc: change link_setup() behaviour, switch the input src don't require a
      explicite disable before.
- mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
- mc: enable link to the first available connector and set the
      corresponding tvp5150 input src per default during registered()
- mc/of: factor out oftree connector allocation
- of: drop svideo dt port
- of: move svideo connector to port@0/endpoint@1
- of: require at least 1-in and 1-out endpoint

 drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
 1 file changed, 370 insertions(+), 39 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 89da921c8886..4e3228b2ccbc 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
 
 enum tvp5150_pads {
-	TVP5150_PAD_IF_INPUT,
+	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
+	TVP5150_PAD_AIP1B,
 	TVP5150_PAD_VID_OUT,
 	TVP5150_NUM_PADS
 };
 
+struct tvp5150_connector {
+	struct v4l2_fwnode_connector base;
+	struct media_entity ent;
+	struct media_pad pad;
+};
+
 struct tvp5150 {
 	struct v4l2_subdev sd;
-#ifdef CONFIG_MEDIA_CONTROLLER
+	/* additional endpoint for the svideo connector */
+	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
+	unsigned int endpoints_num;
+
+	/* media-ctl properties */
 	struct media_pad pads[TVP5150_NUM_PADS];
-#endif
+	struct tvp5150_connector *connectors;
+	int connectors_num;
+
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_rect rect;
 	struct regmap *regmap;
@@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
+/****************************************************************************
+ *			Media entity ops
+ ****************************************************************************/
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_set_link(struct media_pad *connector_pad,
+			    struct media_pad *tvp5150_pad, u32 flags)
+{
+	struct media_link *link;
+
+	link = media_entity_find_link(connector_pad, tvp5150_pad);
+	if (!link)
+		return -EINVAL;
+
+	link->flags = flags;
+	link->reverse->flags = link->flags;
+
+	return 0;
+}
+
+static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
+{
+	struct media_pad *connector_pad;
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
+		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
+		if (!connector_pad)
+			continue;
+
+		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+			     u32 config);
+
+static int tvp5150_link_setup(struct media_entity *entity,
+			      const struct media_pad *tvp5150_pad,
+			      const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct media_pad *other_tvp5150_pad =
+		&decoder->pads[tvp5150_pad->index ^ 1];
+	bool is_svideo = false;
+	unsigned int i;
+	int err;
+
+	/*
+	 * The TVP5150 state is determined by the enabled sink pad link(s).
+	 * Enabling or disabling the source pad link has no effect.
+	 */
+	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
+		return 0;
+
+	/* Check if the svideo connector should be enabled */
+	for (i = 0; i < decoder->connectors_num; i++) {
+		if (remote->entity == &decoder->connectors[i].ent) {
+			is_svideo =
+			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
+			break;
+		}
+	}
+
+	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
+		    remote->entity->name, remote->index,
+		    tvp5150_pad->entity->name, tvp5150_pad->index,
+		    flags & MEDIA_LNK_FL_ENABLED);
+	if (is_svideo)
+		dev_dbg_lvl(sd->dev, 1, debug,
+			    "link setup '%s':%d->'%s':%d[%d]",
+			    remote->entity->name, remote->index,
+			    other_tvp5150_pad->entity->name,
+			    other_tvp5150_pad->index,
+			    flags & MEDIA_LNK_FL_ENABLED);
+
+	/*
+	 * The TVP5150 has an internal mux which allows the following setup:
+	 *
+	 * comp-connector1  --\
+	 *		       |---> AIP1A
+	 *		      /
+	 * svideo-connector -|
+	 *		      \
+	 *		       |---> AIP1B
+	 * comp-connector2  --/
+	 *
+	 * We can't rely on user space that the current connector gets disabled
+	 * first before enabling the new connector. Disable all active
+	 * connector links to be on the safe side.
+	 */
+	err = tvp5150_disable_all_input_links(decoder);
+	if (err)
+		return err;
+
+	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
+			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
+			  TVP5150_BLACK_SCREEN, 0);
+
+	if (flags & MEDIA_LNK_FL_ENABLED) {
+		/*
+		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
+		 * Both links must be enabled in one-shot regardless which link
+		 * the user requests.
+		 */
+		if (is_svideo) {
+			err = tvp5150_set_link((struct media_pad *) remote,
+					       other_tvp5150_pad, flags);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations tvp5150_sd_media_ops = {
+	.link_setup = tvp5150_link_setup,
+};
+#endif
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
@@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	return 0;
 }
 
+static int tvp5150_registered(struct v4l2_subdev *sd)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Setup connector pads and links. Enable the link to the first
+	 * available connector per default.
+	 */
+	for (i = 0; i < decoder->connectors_num; i++) {
+		struct media_entity *con = &decoder->connectors[i].ent;
+		struct media_pad *pad = &decoder->connectors[i].pad;
+		unsigned int port = decoder->connectors[i].base.remote_port;
+		bool is_svideo =
+			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
+		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
+
+		pad->flags = MEDIA_PAD_FL_SOURCE;
+		ret = media_entity_pads_init(con, 1, pad);
+		if (ret < 0)
+			return ret;
+
+		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
+		if (ret < 0)
+			return ret;
+
+		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
+		if (ret < 0) {
+			media_device_unregister_entity(con);
+			return ret;
+		}
+
+		if (is_svideo) {
+			/* svideo links to both aip1a and aip1b */
+			ret = media_create_pad_link(con, 0, &sd->entity,
+						    port + 1, flags);
+			if (ret < 0) {
+				media_device_unregister_entity(con);
+				return ret;
+			}
+		}
+
+		/* enable default input */
+		if (flags == MEDIA_LNK_FL_ENABLED) {
+			decoder->input =
+				is_svideo ? TVP5150_SVIDEO :
+				port == 0 ? TVP5150_COMPOSITE0 :
+				TVP5150_COMPOSITE1;
+
+			tvp5150_selmux(sd);
+		}
+	}
+#endif
+	return 0;
+}
+
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 	.pad = &tvp5150_pad_ops,
 };
 
+static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
+	.registered = tvp5150_registered,
+};
+
 /****************************************************************************
 			I2C Client & Driver
  ****************************************************************************/
@@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
 	return 0;
 }
 
-static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
 {
-	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
-	struct device_node *ep;
-	unsigned int flags;
-	int ret = 0;
+	struct device *dev = decoder->sd.dev;
+	struct tvp5150_connector *connectors;
+	unsigned int connectors_num = decoder->connectors_num;
+	int i, ret;
 
-	ep = of_graph_get_next_endpoint(np, NULL);
-	if (!ep)
-		return -EINVAL;
+	/*
+	 * Only add of_connectors if device really is a OF device since
+	 * the driver is used by usb devices e.g. em28xx and embedded
+	 * devices.
+	 */
+	if (!decoder->connectors_num)
+		return 0;
 
-	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
-	if (ret)
-		goto err;
+	/* Allocate and initialize all available input connectors */
+	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
+				  GFP_KERNEL);
+	if (!connectors)
+		return -ENOMEM;
+
+	for (i = 0; i < connectors_num; i++) {
+		struct v4l2_fwnode_connector *c = &connectors[i].base;
+
+		ret = v4l2_fwnode_parse_connector(
+				   of_fwnode_handle(decoder->endpoints[i]), c);
+
+		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
+		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
+			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
+		connectors[i].ent.name = c->label;
+	}
+
+	decoder->connectors = connectors;
+
+	return 0;
+}
+
+static int tvp5150_mc_init(struct tvp5150 *decoder)
+{
+	struct v4l2_subdev *sd = &decoder->sd;
+	unsigned int i;
+
+	sd->entity.ops = &tvp5150_sd_media_ops;
+	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+	/* Initialize all TVP5150 pads */
+	for (i = 0; i < TVP5150_NUM_PADS; i++) {
+		if (i < TVP5150_NUM_PADS - 1) {
+			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
+			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
+		} else {
+			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
+		}
+	}
+
+	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
+				      decoder->pads);
+}
+
+#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
+
+static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
+{
+	return 0;
+}
 
-	flags = bus_cfg.bus.parallel.flags;
+static inline int tvp5150_mc_init(struct tvp5150 *decoder)
+{
+	return 0;
+}
+#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
 
-	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
-	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
-	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
-	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
+static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+{
+	struct device *dev = decoder->sd.dev;
+	struct device_node *ep_np;
+	unsigned int i = 0, in = 0;
+	int ret;
+	bool found = false;
+
+	/* at least 1 output and 1 input */
+	decoder->endpoints_num = of_graph_get_endpoint_count(np);
+	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
+		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
 		ret = -EINVAL;
 		goto err;
 	}
 
-	decoder->mbus_type = bus_cfg.bus_type;
+	for_each_endpoint_of_node(np, ep_np) {
+		struct v4l2_fwnode_endpoint bus_cfg = {
+			.bus_type = V4L2_MBUS_UNKNOWN
+		};
+		struct v4l2_fwnode_connector c;
+		struct of_endpoint ep;
+		unsigned int flags;
+
+		of_graph_parse_endpoint(ep_np, &ep);
+		switch (ep.port) {
+		case TVP5150_PAD_AIP1A:
+			/* fall through */
+		case TVP5150_PAD_AIP1B:
+			ret = v4l2_fwnode_parse_connector(
+						   of_fwnode_handle(ep_np), &c);
+			if (c.type != V4L2_CON_COMPOSITE &&
+			    c.type != V4L2_CON_SVIDEO) {
+				dev_err(dev,
+					"Invalid endpoint %d on port %d\n",
+					c.remote_id, c.remote_port);
+				ret = -EINVAL;
+				goto err;
+			}
+			in++;
+			break;
+		case TVP5150_PAD_VID_OUT:
+			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
+							 &bus_cfg);
+			if (ret)
+				goto err;
+
+			flags = bus_cfg.bus.parallel.flags;
+
+			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
+			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
+			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
+			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
+				ret = -EINVAL;
+				goto err;
+			}
+
+			decoder->mbus_type = bus_cfg.bus_type;
+			break;
+		default:
+			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
+				ep.port, ep.local_node);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		of_node_get(ep_np);
+		decoder->endpoints[i] = ep_np;
+		i++;
+
+		found = true;
+	}
 
+	decoder->connectors_num = in;
+	return found ? 0 : -ENODEV;
 err:
-	of_node_put(ep);
 	return ret;
 }
 
+static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
+{
+	unsigned int i;
+
+	for (i = 0; i < TVP5150_NUM_PADS; i++)
+		of_node_put(decoder->endpoints[i]);
+}
+
 static const char * const tvp5150_test_patterns[2] = {
 	"Disabled",
 	"Black screen"
@@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
 		res = tvp5150_parse_dt(core, np);
 		if (res) {
 			dev_err(sd->dev, "DT parsing error: %d\n", res);
-			return res;
+			goto err_cleanup_dt;
 		}
 	} else {
 		/* Default to BT.656 embedded sync */
@@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
 	}
 
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+	sd->internal_ops = &tvp5150_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-#if defined(CONFIG_MEDIA_CONTROLLER)
-	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
-	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
-	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
-	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
-
-	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
-
-	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
-	if (res < 0)
-		return res;
+	res = tvp5150_mc_init(core);
+	if (res)
+		goto err_cleanup_dt;
 
-#endif
+	res = tvp5150_add_of_connectors(core);
+	if (res)
+		goto err_cleanup_dt;
 
 	res = tvp5150_detect_version(core);
 	if (res < 0)
-		return res;
+		goto err_cleanup_dt;
 
 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
 	core->detected_norm = V4L2_STD_UNKNOWN;
@@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
 	sd->ctrl_handler = &core->hdl;
 	if (core->hdl.error) {
 		res = core->hdl.error;
-		goto err;
+		goto err_free_v4l2_ctrls;
 	}
 
 	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
@@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
 						tvp5150_isr, IRQF_TRIGGER_HIGH |
 						IRQF_ONESHOT, "tvp5150", core);
 		if (res)
-			goto err;
+			goto err_free_v4l2_ctrls;
 	}
 
 	res = v4l2_async_register_subdev(sd);
 	if (res < 0)
-		goto err;
+		goto err_free_v4l2_ctrls;
 
 	if (debug > 1)
 		tvp5150_log_status(sd);
+
 	return 0;
 
-err:
+err_free_v4l2_ctrls:
 	v4l2_ctrl_handler_free(&core->hdl);
+err_cleanup_dt:
+	if (IS_ENABLED(CONFIG_OF) && np)
+		tvp5150_dt_cleanup(core);
+
 	return res;
 }
 
-- 
2.20.1


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

* [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (4 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-14 18:27   ` Mauro Carvalho Chehab
  2019-05-16 18:05   ` Laurent Pinchart
  2019-04-15 12:44 ` [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

The TVP5150/1 decoders support different video input sources to their
AIP1A/B pins.

Possible configurations are as follows:
  - Analog Composite signal connected to AIP1A.
  - Analog Composite signal connected to AIP1B.
  - Analog S-Video Y (luminance) and C (chrominance)
    signals connected to AIP1A and AIP1B respectively.

This patch extends the device tree bindings documentation to describe
how the input connectors for these devices should be defined in a DT.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changelog:

v3:
- remove examples for one and two inputs
- replace space by tabs

v2:
- adapt port layout in accordance with
  https://www.spinics.net/lists/linux-media/msg138546.html with the
  svideo-connector deviation (use only one endpoint)

 .../devicetree/bindings/media/i2c/tvp5150.txt | 92 +++++++++++++++++--
 1 file changed, 85 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index 8c0fc1a26bf0..bdd273d8b44d 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -12,11 +12,31 @@ Optional Properties:
 - pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
 - reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
 
-The device node must contain one 'port' child node for its digital output
-video port, in accordance with the video interface bindings defined in
-Documentation/devicetree/bindings/media/video-interfaces.txt.
+The device node must contain one 'port' child node per device physical input
+and output port, in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
+are numbered as follows
 
-Required Endpoint Properties for parallel synchronization:
+	  Name		Type		Port
+	--------------------------------------
+	  AIP1A		sink		0
+	  AIP1B		sink		1
+	  Y-OUT		src		2
+
+The device node must contain at least one sink port and the src port. Each input
+port must be linked to an endpoint defined in
+Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
+port/connector layout is as follows
+
+tvp-5150 port@0 (AIP1A)
+	endpoint@0 -----------> Comp0-Con  port
+	endpoint@1 -----------> Svideo-Con port
+tvp-5150 port@1 (AIP1B)
+	endpoint   -----------> Comp1-Con  port
+tvp-5150 port@2
+	endpoint (video bitstream output at YOUT[0-7] parallel bus)
+
+Required Endpoint Properties for parallel synchronization on output port:
 
 - hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
 - vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
@@ -26,17 +46,75 @@ Required Endpoint Properties for parallel synchronization:
 If none of hsync-active, vsync-active and field-even-active is specified,
 the endpoint is assumed to use embedded BT.656 synchronization.
 
-Example:
+Example - three input sources:
+
+comp_connector_0 {
+	compatible = "composite-video-connector";
+	label = "Composite0";
+
+	port {
+		composite0_to_tvp5150: endpoint {
+			remote-endpoint = <&tvp5150_to_composite0>;
+		};
+	};
+};
+
+comp_connector_1 {
+	compatible = "composite-video-connector";
+	label = "Composite1";
+
+	port {
+		composite1_to_tvp5150: endpoint {
+			remote-endpoint = <&tvp5150_to_composite1>;
+		};
+	};
+};
+
+svid_connector {
+	compatible = "svideo-connector";
+	label = "S-Video";
+
+	port {
+		svideo_to_tvp5150: endpoint {
+			remote-endpoint = <&tvp5150_to_svideo>;
+		};
+	};
+};
 
 &i2c2 {
-	...
 	tvp5150@5c {
 		compatible = "ti,tvp5150";
 		reg = <0x5c>;
 		pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
 		reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
 
-		port {
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			tvp5150_to_composite0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&composite0_to_tvp5150>;
+			};
+
+			tvp5150_to_svideo: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&svideo_to_tvp5150>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+
+			tvp5150_to_composite1: endpoint {
+                                remote-endpoint = <&composite1_to_tvp5150>;
+			};
+		};
+
+		port@2 {
+			reg = <2>;
+
 			tvp5150_1: endpoint {
 				remote-endpoint = <&ccdc_ep>;
 			};
-- 
2.20.1


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

* [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (5 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06 13:36   ` Jacopo Mondi
  2019-05-14 18:48   ` Mauro Carvalho Chehab
  2019-04-15 12:44 ` [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
no way to try different selections. The patch adds a helper function to
select the correct selection memory space (sub-device file handle or
driver state) which will be set/returned.

The TVP5150 AVID will be updated if the 'which' field is FORMAT_ACTIVE
and the requested selection rectangle differs from the already set one.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:

v5:
 - handle stub for v4l2_subdev_get_try_crop() internal since commit
   ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
   isn't anymore part of this series.
 - add error handling of __tvp5150_get_pad_crop()
v4:
 - fix merge conflict due to rebase on top of media-tree/master
 - __tvp5150_get_pad_crop(): cosmetic alignment fixes

 drivers/media/i2c/tvp5150.c | 130 ++++++++++++++++++++++++++----------
 1 file changed, 96 insertions(+), 34 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 4e3228b2ccbc..9331609425bf 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -19,6 +19,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-mc.h>
+#include <media/v4l2-rect.h>
 
 #include "tvp5150_reg.h"
 
@@ -997,20 +998,48 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
 		crop->height = TVP5150_V_MAX_OTHERS;
 }
 
+static struct v4l2_rect *
+__tvp5150_get_pad_crop(struct tvp5150 *decoder,
+		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+		       enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
+#else
+		return ERR_PTR(-ENOTTY);
+#endif
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &decoder->rect;
+	default:
+		return NULL;
+	}
+}
+
 static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_format *format)
 {
 	struct v4l2_mbus_framefmt *f;
+	struct v4l2_rect *__crop;
 	struct tvp5150 *decoder = to_tvp5150(sd);
 
 	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
 		return -EINVAL;
 
 	f = &format->format;
+	__crop = __tvp5150_get_pad_crop(decoder, cfg, format->pad,
+					format->which);
+	if (IS_ERR_OR_NULL(__crop)) {
+		if (!__crop)
+			return -EINVAL;
+		else
+			return PTR_ERR(__crop);
+	}
 
-	f->width = decoder->rect.width;
-	f->height = decoder->rect.height / 2;
+	f->width = __crop->width;
+	f->height = __crop->height / 2;
 
 	f->code = TVP5150_MBUS_FMT;
 	f->field = TVP5150_FIELD;
@@ -1021,17 +1050,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
+unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	return (std & V4L2_STD_525_60) ?
+		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
+}
+
+static inline void
+__tvp5150_set_selection(struct v4l2_subdev *sd, struct v4l2_rect rect)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int hmax = tvp5150_get_hmax(sd);
+
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
+		     rect.top + rect.height - hmax);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
+		     rect.left >> TVP5150_CROP_SHIFT);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
+		     rect.left | (1 << TVP5150_CROP_SHIFT));
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
+		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+		     TVP5150_CROP_SHIFT);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
+		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+}
+
 static int tvp5150_set_selection(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_selection *sel)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
 	struct v4l2_rect rect = sel->r;
-	v4l2_std_id std;
-	int hmax;
+	struct v4l2_rect *__crop;
+	unsigned int hmax;
 
-	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-	    sel->target != V4L2_SEL_TGT_CROP)
+	if (sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
 
 	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -1040,17 +1103,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 	/* tvp5150 has some special limits */
 	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
 	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
-
-	/* Calculate height based on current standard */
-	if (decoder->norm == V4L2_STD_ALL)
-		std = tvp5150_read_std(sd);
-	else
-		std = decoder->norm;
-
-	if (std & V4L2_STD_525_60)
-		hmax = TVP5150_V_MAX_525_60;
-	else
-		hmax = TVP5150_V_MAX_OTHERS;
+	hmax = tvp5150_get_hmax(sd);
 
 	/*
 	 * alignments:
@@ -1063,20 +1116,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
 			      hmax - rect.top, 0, 0);
 
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
-		     rect.top + rect.height - hmax);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
-		     rect.left >> TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
-		     rect.left | (1 << TVP5150_CROP_SHIFT));
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
-		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
-		     TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
-		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+	__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
+	if (IS_ERR_OR_NULL(__crop)) {
+		if (!__crop)
+			return -EINVAL;
+		else
+			return PTR_ERR(__crop);
+	}
+
+	/*
+	 * Update output image size if the selection (crop) rectangle size or
+	 * position has been modified.
+	 */
+	if (!v4l2_rect_equal(&rect, __crop))
+		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+			__tvp5150_set_selection(sd, rect);
 
-	decoder->rect = rect;
+	*__crop = rect;
 
 	return 0;
 }
@@ -1086,11 +1142,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_selection *sel)
 {
 	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+	struct v4l2_rect *__crop;
 	v4l2_std_id std;
 
-	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
-
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP_BOUNDS:
 		sel->r.left = 0;
@@ -1108,7 +1162,15 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
 			sel->r.height = TVP5150_V_MAX_OTHERS;
 		return 0;
 	case V4L2_SEL_TGT_CROP:
-		sel->r = decoder->rect;
+		__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad,
+						sel->which);
+		if (IS_ERR_OR_NULL(__crop)) {
+			if (!__crop)
+				return -EINVAL;
+			else
+				return PTR_ERR(__crop);
+		}
+		sel->r = *__crop;
 		return 0;
 	default:
 		return -EINVAL;
-- 
2.20.1


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

* [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (6 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-14 20:20   ` Mauro Carvalho Chehab
  2019-04-15 12:44 ` [PATCH v6 09/13] media: tvp5150: add s_power callback Marco Felsch
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Michael Tretter

From: Michael Tretter <m.tretter@pengutronix.de>

There are several debug prints in the tvp5150_parse_dt() function, which
do not print the prefix, because the v4l2_subdev is not initialized, yet.

Initialize the v4l2_subdev before parsing the device tree to fix the
debug messages.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 9331609425bf..305a5e256b31 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1973,6 +1973,9 @@ static int tvp5150_probe(struct i2c_client *c,
 
 	core->regmap = map;
 	sd = &core->sd;
+	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+	sd->internal_ops = &tvp5150_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	if (IS_ENABLED(CONFIG_OF) && np) {
 		res = tvp5150_parse_dt(core, np);
@@ -1985,10 +1988,6 @@ static int tvp5150_probe(struct i2c_client *c,
 		core->mbus_type = V4L2_MBUS_BT656;
 	}
 
-	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
-	sd->internal_ops = &tvp5150_internal_ops;
-	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
 	res = tvp5150_mc_init(core);
 	if (res)
 		goto err_cleanup_dt;
-- 
2.20.1


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

* [PATCH v6 09/13] media: tvp5150: add s_power callback
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (7 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-14 20:13   ` Mauro Carvalho Chehab
  2019-04-15 12:44 ` [PATCH v6 10/13] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

Don't en-/disable the interrupts during s_stream because someone can
disable the stream but wants to get informed if the stream is locked
again. So keep the interrupts enabled the whole time the pipeline is
opened.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 305a5e256b31..cd54715eb641 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1370,11 +1370,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
+static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int val = 0;
+
+	if (on)
+		val = TVP5150_INT_A_LOCK;
+
+	if (decoder->irq)
+		/* Enable / Disable lock interrupt */
+		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
+				   TVP5150_INT_A_LOCK, val);
+
+	return 0;
+}
 
 static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
-	unsigned int mask, val = 0, int_val = 0;
+	unsigned int mask, val = 0;
 
 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
 	       TVP5150_MISC_CTL_CLOCK_OE;
@@ -1387,15 +1402,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 			val = decoder->lock ? decoder->oe : 0;
 		else
 			val = decoder->oe;
-		int_val = TVP5150_INT_A_LOCK;
 		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
 	}
 
 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
-	if (decoder->irq)
-		/* Enable / Disable lock interrupt */
-		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
-				   TVP5150_INT_A_LOCK, int_val);
 
 	return 0;
 }
@@ -1586,6 +1596,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
 	.g_register = tvp5150_g_register,
 	.s_register = tvp5150_s_register,
 #endif
+	.s_power = tvp5150_s_power,
 };
 
 static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
-- 
2.20.1


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

* [PATCH v6 10/13] media: dt-bindings: tvp5150: cleanup bindings stlye
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (8 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 09/13] media: tvp5150: add s_power callback Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 11/13] media: dt-bindings: tvp5150: add optional tvnorms documentation Marco Felsch
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

Use underlines to highlight optional and required properties. This is
quite common for all bindings. Align descriptions and start sentence
with uppercase letter. Also reword the usage of the required
endpoint properties for the output port in case BT.656 should be used.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/media/i2c/tvp5150.txt | 30 +++++++++++--------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index bdd273d8b44d..82fff80fa63a 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -5,12 +5,14 @@ The TVP5150 and TVP5151 are video decoders that convert baseband NTSC and PAL
 with discrete syncs or 8-bit ITU-R BT.656 with embedded syncs output formats.
 
 Required Properties:
-- compatible: value must be "ti,tvp5150"
-- reg: I2C slave address
+====================
+- compatible:	Value must be "ti,tvp5150".
+- reg:		I2C slave address.
 
 Optional Properties:
-- pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
-- reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
+====================
+- pdn-gpios:	Phandle for the GPIO connected to the PDN pin, if any.
+- reset-gpios:	Phandle for the GPIO connected to the RESETB pin, if any.
 
 The device node must contain one 'port' child node per device physical input
 and output port, in accordance with the video interface bindings defined in
@@ -24,9 +26,8 @@ are numbered as follows
 	  Y-OUT		src		2
 
 The device node must contain at least one sink port and the src port. Each input
-port must be linked to an endpoint defined in
-Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
-port/connector layout is as follows
+port must be linked to an endpoint defined in [1]. The port/connector layout is
+as follows
 
 tvp-5150 port@0 (AIP1A)
 	endpoint@0 -----------> Comp0-Con  port
@@ -37,14 +38,17 @@ tvp-5150 port@2
 	endpoint (video bitstream output at YOUT[0-7] parallel bus)
 
 Required Endpoint Properties for parallel synchronization on output port:
+=========================================================================
 
-- hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
-- vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
-- field-even-active: field signal level during the even field data
-  transmission. Must be <0>.
+- hsync-active:		Active state of the HSYNC signal. Must be <1> (HIGH).
+- vsync-active:		Active state of the VSYNC signal. Must be <1> (HIGH).
+- field-even-active:	Field signal level during the even field data
+			transmission. Must be <0>.
 
-If none of hsync-active, vsync-active and field-even-active is specified,
-the endpoint is assumed to use embedded BT.656 synchronization.
+Note: Do not specify any of these properties if you want to use the embedded
+      BT.656 synchronization.
+
+[1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt.
 
 Example - three input sources:
 
-- 
2.20.1


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

* [PATCH v6 11/13] media: dt-bindings: tvp5150: add optional tvnorms documentation
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (9 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 10/13] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-04-15 12:44 ` [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector Marco Felsch
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

Document the optional binding to limit the possible tv-norms on the
input connectors.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/media/i2c/tvp5150.txt | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index 82fff80fa63a..970be21fb191 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -48,6 +48,13 @@ Required Endpoint Properties for parallel synchronization on output port:
 Note: Do not specify any of these properties if you want to use the embedded
       BT.656 synchronization.
 
+Optional Connector Properties:
+==============================
+
+- tvnorms: Set the possible signals to which the hardware tries to lock instead
+	   of using the autodetection mechnism. Please look at [1] for more
+	   information.
+
 [1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt.
 
 Example - three input sources:
@@ -55,6 +62,7 @@ Example - three input sources:
 comp_connector_0 {
 	compatible = "composite-video-connector";
 	label = "Composite0";
+	tvnorms = <TVNORM_PAL_M>; /* limit to pal-m signals */
 
 	port {
 		composite0_to_tvp5150: endpoint {
@@ -66,6 +74,7 @@ comp_connector_0 {
 comp_connector_1 {
 	compatible = "composite-video-connector";
 	label = "Composite1";
+	tvnorms = <TVNORM_NTSC_M>; /* limit to ntsc-m signals */
 
 	port {
 		composite1_to_tvp5150: endpoint {
-- 
2.20.1


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

* [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (10 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 11/13] media: dt-bindings: tvp5150: add optional tvnorms documentation Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-16 18:07   ` Laurent Pinchart
  2019-04-15 12:44 ` [PATCH v6 13/13] media: tvp5150: make debug output more readable Marco Felsch
  2019-05-06  5:47 ` [PATCH v6 00/13] TVP5150 new features Marco Felsch
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
data and is able to auto-detect the input signal. The auto-detection
does not work if the connector does not receive an input signal and the
tvp5150 might not be configured correctly. This misconfiguration leads
into wrong decoded video streams if the tvp5150 gets powered on before
the video signal is present.

Limit the supported tv norms according to the actual selected connector
to avoid a misconfiguration.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
[1] https://patchwork.kernel.org/cover/10794703/

v5:
- probe() initialize supported tv-norms according the given connectors
  if they are available.
- check if media-controller is used. Don't limit the norm if it isn't
  used.
- add more logic to be smarter during connector changing so it is
  intuitiver for the user space.

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.

 drivers/media/i2c/tvp5150.c | 69 +++++++++++++++++++++++++++++++++++--
 1 file changed, 67 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index cd54715eb641..c0ee08546643 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -32,6 +32,13 @@
 #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
 #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
 #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
+#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
+				 V4L2_STD_NTSC_443 | \
+				 V4L2_STD_PAL      | \
+				 V4L2_STD_PAL_M    | \
+				 V4L2_STD_PAL_N    | \
+				 V4L2_STD_PAL_Nc   | \
+				 V4L2_STD_SECAM)
 
 MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
@@ -66,6 +73,7 @@ struct tvp5150 {
 	/* media-ctl properties */
 	struct media_pad pads[TVP5150_NUM_PADS];
 	struct tvp5150_connector *connectors;
+	struct tvp5150_connector *cur_connector;
 	int connectors_num;
 
 	struct v4l2_ctrl_handler hdl;
@@ -785,17 +793,28 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
 static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct tvp5150_connector *cur_con = decoder->cur_connector;
+	v4l2_std_id supported_norms = cur_con ?
+		cur_con->base.connector.analog.supported_tvnorms : V4L2_STD_ALL;
 
 	if (decoder->norm == std)
 		return 0;
 
+	/*
+	 * check if requested std or group of std's is/are supported by the
+	 * connector
+	 */
+	if ((supported_norms & std) == 0)
+		return -EINVAL;
+
 	/* Change cropping height limits */
 	if (std & V4L2_STD_525_60)
 		decoder->rect.height = TVP5150_V_MAX_525_60;
 	else
 		decoder->rect.height = TVP5150_V_MAX_OTHERS;
 
-	decoder->norm = std;
+	/* set only the specific supported std in case of group of std's */
+	decoder->norm = supported_norms & std;
 
 	return tvp5150_set_std(sd, std);
 }
@@ -1347,6 +1366,8 @@ static int tvp5150_link_setup(struct media_entity *entity,
 			  TVP5150_BLACK_SCREEN, 0);
 
 	if (flags & MEDIA_LNK_FL_ENABLED) {
+		u32 new_norm;
+
 		/*
 		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
 		 * Both links must be enabled in one-shot regardless which link
@@ -1358,6 +1379,26 @@ static int tvp5150_link_setup(struct media_entity *entity,
 			if (err)
 				return err;
 		}
+
+		/* Update the current connector */
+		decoder->cur_connector =
+			container_of(remote, struct tvp5150_connector, pad);
+
+		/*
+		 * Do nothing if the new connector supports the same tv-norms as
+		 * the old one.
+		 */
+		new_norm = decoder->norm &
+			decoder->cur_connector->base.connector.analog.supported_tvnorms;
+		if (decoder->norm == new_norm)
+			return 0;
+
+		/*
+		 * Fallback to the new connector tv-norms if we can't find any
+		 * common between the current tv-norm and the new one.
+		 */
+		tvp5150_s_std(sd, new_norm ? new_norm :
+			decoder->cur_connector->base.connector.analog.supported_tvnorms);
 	}
 
 	return 0;
@@ -1576,6 +1617,9 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
 				TVP5150_COMPOSITE1;
 
 			tvp5150_selmux(sd);
+			decoder->cur_connector = &decoder->connectors[i];
+			tvp5150_s_std(sd,
+				decoder->connectors[i].base.connector.analog.supported_tvnorms);
 		}
 	}
 #endif
@@ -1903,6 +1947,11 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
 				ret = -EINVAL;
 				goto err;
 			}
+			if (!(c.connector.analog.supported_tvnorms &
+			    TVP5150_STD_MASK))
+				dev_warn(dev,
+					"Unsupported tv-norm on connector %s.\n",
+					c.label);
 			in++;
 			break;
 		case TVP5150_PAD_VID_OUT:
@@ -2011,7 +2060,23 @@ static int tvp5150_probe(struct i2c_client *c,
 	if (res < 0)
 		goto err_cleanup_dt;
 
-	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
+	/*
+	 * Iterate over all available connectors in case they are supported and
+	 * successfully parsed. Fallback to default autodetect in case they
+	 * aren't supported.
+	 */
+	if (core->connectors) {
+		struct v4l2_fwnode_connector *con;
+		int i;
+
+		for (i = 0; i < core->connectors_num; i++) {
+			con = &core->connectors[i].base;
+			core->norm |= con->connector.analog.supported_tvnorms;
+		}
+	} else {
+		core->norm = V4L2_STD_ALL;
+	}
+
 	core->detected_norm = V4L2_STD_UNKNOWN;
 	core->input = TVP5150_COMPOSITE1;
 	core->enable = true;
-- 
2.20.1


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

* [PATCH v6 13/13] media: tvp5150: make debug output more readable
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (11 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector Marco Felsch
@ 2019-04-15 12:44 ` Marco Felsch
  2019-05-06 13:39   ` Jacopo Mondi
  2019-05-06  5:47 ` [PATCH v6 00/13] TVP5150 new features Marco Felsch
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-04-15 12:44 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel

The debug output for tvp5150_selmux() isn't really intuitive. Register
values are printed decimal formatted and the input/output driver states
are printed as enum. Even more the "normal" output enum mapps to zero so
a active output will printing output=0 and a inactive output=1.

Change this by brinting the register values hex formatted and the states
as more readable string.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index c0ee08546643..13ee6d781efb 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -302,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
 		break;
 	}
 
-	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
-			decoder->input, decoder->output,
-			input, opmode);
+	dev_dbg_lvl(sd->dev, 1, debug,
+		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
+		    decoder->input == 0 ? "aip1a" :
+		    decoder->input == 2 ? "aip1b" : "svideo",
+		    decoder->output == 0 ? "normal" : "black-frame-gen",
+		    input, opmode);
 
 	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
 	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
-- 
2.20.1


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

* Re: [PATCH v6 00/13] TVP5150 new features
  2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
                   ` (12 preceding siblings ...)
  2019-04-15 12:44 ` [PATCH v6 13/13] media: tvp5150: make debug output more readable Marco Felsch
@ 2019-05-06  5:47 ` Marco Felsch
  2019-05-14 17:18   ` Mauro Carvalho Chehab
  13 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-05-06  5:47 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt
  Cc: devicetree, laurent.pinchart, kernel, linux-media

Hi Mauro,

I know you are busy but can you have a look on it?

Regards,
  Marco

On 19-04-15 14:44, Marco Felsch wrote:
> Hi,
> 
> many thanks to Hans and Jacopo for the feedack :) this v6 address the
> comments both made on my v5 [1].
> 
> In short this is round fixes just some minor issues rather than major
> ones so the diff to the v5 is really small. The changed patches contain
> the changelog so I omit it here.
> 
> I've tested it on a custom hardware but I can't test the em28xx usb
> use-case since I haven't such a device. So other testers are welcome :)
> 
> Looking forward for your feedack,
> 
> 	Marco
> 
> [1] https://patchwork.kernel.org/cover/10886903/
> 
> Javier Martinez Canillas (1):
>   partial revert of "[media] tvp5150: add HW input connectors support"
> 
> Marco Felsch (11):
>   dt-bindings: connector: analog: add tv norms property
>   media: v4l2-fwnode: add v4l2_fwnode_connector
>   media: v4l2-fwnode: add initial connector parsing support
>   media: tvp5150: add input source selection of_graph support
>   media: dt-bindings: tvp5150: Add input port connectors DT bindings
>   media: tvp5150: add FORMAT_TRY support for get/set selection handlers
>   media: tvp5150: add s_power callback
>   media: dt-bindings: tvp5150: cleanup bindings stlye
>   media: dt-bindings: tvp5150: add optional tvnorms documentation
>   media: tvp5150: add support to limit tv norms on connector
>   media: tvp5150: make debug output more readable
> 
> Michael Tretter (1):
>   media: tvp5150: initialize subdev before parsing device tree
> 
>  .../display/connector/analog-tv-connector.txt |   4 +
>  .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
>  drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
>  drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
>  include/dt-bindings/media/tvnorms.h           |  56 ++
>  include/dt-bindings/media/tvp5150.h           |   2 -
>  include/media/v4l2-connector.h                |  30 +
>  include/media/v4l2-fwnode.h                   |  49 ++
>  8 files changed, 859 insertions(+), 190 deletions(-)
>  create mode 100644 include/dt-bindings/media/tvnorms.h
>  create mode 100644 include/media/v4l2-connector.h
> 
> -- 
> 2.20.1
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-04-15 12:44 ` [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
@ 2019-05-06  9:50   ` Hans Verkuil
  2019-05-14 18:17     ` Mauro Carvalho Chehab
  2019-08-09  7:20     ` Marco Felsch
  2019-05-16 16:36   ` Laurent Pinchart
  1 sibling, 2 replies; 70+ messages in thread
From: Hans Verkuil @ 2019-05-06  9:50 UTC (permalink / raw)
  To: Marco Felsch, mchehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi

On 4/15/19 2:44 PM, Marco Felsch wrote:
> Currently every driver needs to parse the connector endpoints by it self.
> This is the initial work to make this generic. The generic connector has
> some common fields and some connector specific parts. The generic one
> includes:
>   - type
>   - label
>   - remote_port (the port where the connector is connected to)
>   - remote_id   (the endpoint where the connector is connected to)
> 
> The specific fields are within a union, since only one of them can be
> available at the time. Since this is the initial support the patch adds
> only the analog-connector specific ones.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v6:
> - fix some spelling and style issues
> - rm unnecessary comments
> - drop vga and dvi connector
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
>  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 include/media/v4l2-connector.h
> 
> diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> new file mode 100644
> index 000000000000..3a951c54f50e
> --- /dev/null
> +++ b/include/media/v4l2-connector.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * v4l2-connector.h
> + *
> + * V4L2 connector types.
> + *
> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> + */
> +
> +#ifndef V4L2_CONNECTOR_H
> +#define V4L2_CONNECTOR_H
> +
> +#define V4L2_CONNECTOR_MAX_LABEL 41

Where does 41 come from? It's a weird number...

> +
> +/**
> + * enum v4l2_connector_type - connector type
> + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration

typo: connetor -> connector

> + * @V4L2_CON_COMPOSITE: analog composite connector
> + * @V4L2_CON_SVIDEO:    analog svideo connector
> + * @V4L2_CON_HDMI:      digital hdmi connector
> + */
> +enum v4l2_connector_type {
> +	V4L2_CON_UNKNOWN,
> +	V4L2_CON_COMPOSITE,
> +	V4L2_CON_SVIDEO,
> +	V4L2_CON_HDMI,
> +};
> +
> +#endif /* V4L2_CONNECTOR_H */
> +

Is there a reason to create a new header for this? I think it is perfectly OK to
add this define + enum for v4l2-fwnode.h.

> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 6c07825e18b9..f4df1b95c5ef 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -22,6 +22,7 @@
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> +#include <media/v4l2-connector.h>
>  #include <media/v4l2-mediabus.h>
>  #include <media/v4l2-subdev.h>
>  
> @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
>  	unsigned int remote_port;
>  };
>  
> +/**
> + * struct v4l2_fwnode_connector_analog - analog connector data structure
> + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> + *                     if no restrictions are specified.
> + */
> +struct v4l2_fwnode_connector_analog {
> +	v4l2_std_id supported_tvnorms;
> +};
> +
> +/**
> + * struct v4l2_fwnode_connector - the connector data structure
> + * @remote_port: identifier of the remote endpoint port the connector connects
> + *		 to
> + * @remote_id: identifier of the remote endpoint the connector connects to
> + * @label: connetor label

Same typo. It's probably a good idea to grep for this typo in this patch series :-)

> + * @type: connector type
> + * @connector: connector configuration
> + * @connector.analog: analog connector configuration
> + *                    &struct v4l2_fwnode_connector_analog
> + */
> +struct v4l2_fwnode_connector {
> +	unsigned int remote_port;
> +	unsigned int remote_id;
> +	char label[V4L2_CONNECTOR_MAX_LABEL];
> +	enum v4l2_connector_type type;
> +
> +	union {
> +		struct v4l2_fwnode_connector_analog analog;
> +		/* future connectors */
> +	} connector;
> +};
> +
>  /**
>   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
>   * @fwnode: pointer to the endpoint's fwnode handle
> 

Regards,

	Hans

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
@ 2019-05-06 10:01   ` Hans Verkuil
  2019-05-06 10:06     ` Hans Verkuil
  2019-05-14 18:11     ` Mauro Carvalho Chehab
  2019-05-16 16:27   ` Laurent Pinchart
  1 sibling, 2 replies; 70+ messages in thread
From: Hans Verkuil @ 2019-05-06 10:01 UTC (permalink / raw)
  To: Marco Felsch, mchehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

On 4/15/19 2:44 PM, Marco Felsch wrote:
> Some connectors no matter if in- or output supports only a limited
> range of tv norms. It doesn't matter if the hardware behind that
> connector supports more than the listed formats since the users are
> restriced by a label e.g. to plug only a camera into this connector
> which uses the PAL format.

For S-Video and Composite connectors there are really just two formats
to consider: 50 and 60 Hz. I.e. there is no difference between PAL
and SECAM. Only for tuners/modulators does this matter.

So it is a good idea to add TVNORM_525_60, TVNORM_625_50 to tvnorms.h.

In the various bindings examples I would recommend that you use
TVNORM_525_60 or TVNORM_625_50 rather than e.g. PAL_M since that's what
you would use in practice for Composite/S-Video.

Regards,

	Hans

> 
> This patch adds the capability to describe such limitation within the
> firmware. There are no format restrictions if the property isn't
> present, so it's completely backward compatible.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v6:
> - tvnorms.h: use tabs instead of spaces
> - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  .../display/connector/analog-tv-connector.txt |  4 ++
>  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
>  2 files changed, 60 insertions(+)
>  create mode 100644 include/dt-bindings/media/tvnorms.h
> 
> diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> index 0c0970c210ab..346f8937a0b7 100644
> --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> @@ -6,6 +6,9 @@ Required properties:
>  
>  Optional properties:
>  - label: a symbolic name for the connector
> +- tvnorms: limit the supported tv norms on a connector to the given ones else
> +           all tv norms are allowed. Possible video standards are defined in
> +           include/dt-bindings/media/tvnorms.h.
>  
>  Required nodes:
>  - Video port for TV input
> @@ -16,6 +19,7 @@ Example
>  tv: connector {
>  	compatible = "composite-video-connector";
>  	label = "tv";
> +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
>  
>  	port {
>  		tv_connector_in: endpoint {
> diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> new file mode 100644
> index 000000000000..058ab8414145
> --- /dev/null
> +++ b/include/dt-bindings/media/tvnorms.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> +/*
> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> + */
> +
> +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> +
> +/* one bit for each */
> +#define TVNORM_PAL_B		0x00000001
> +#define TVNORM_PAL_B1		0x00000002
> +#define TVNORM_PAL_G		0x00000004
> +#define TVNORM_PAL_H		0x00000008
> +#define TVNORM_PAL_I		0x00000010
> +#define TVNORM_PAL_D		0x00000020
> +#define TVNORM_PAL_D1		0x00000040
> +#define TVNORM_PAL_K		0x00000080
> +
> +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> +				 TVNORM_PAL_B1 | \
> +				 TVNORM_PAL_G  | \
> +				 TVNORM_PAL_H  | \
> +				 TVNORM_PAL_I  | \
> +				 TVNORM_PAL_D  | \
> +				 TVNORM_PAL_D1 | \
> +				 TVNORM_PAL_K)
> +
> +#define TVNORM_PAL_M		0x00000100
> +#define TVNORM_PAL_N		0x00000200
> +#define TVNORM_PAL_Nc		0x00000400
> +#define TVNORM_PAL_60		0x00000800
> +
> +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> +#define TVNORM_NTSC_443		0x00004000
> +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> +
> +#define TVNORM_SECAM_B		0x00010000
> +#define TVNORM_SECAM_D		0x00020000
> +#define TVNORM_SECAM_G		0x00040000
> +#define TVNORM_SECAM_H		0x00080000
> +#define TVNORM_SECAM_K		0x00100000
> +#define TVNORM_SECAM_K1		0x00200000
> +#define TVNORM_SECAM_L		0x00400000
> +#define TVNORM_SECAM_LC		0x00800000
> +
> +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> +				 TVNORM_SECAM_D  | \
> +				 TVNORM_SECAM_G  | \
> +				 TVNORM_SECAM_H  | \
> +				 TVNORM_SECAM_K  | \
> +				 TVNORM_SECAM_K1 | \
> +				 TVNORM_SECAM_L  | \
> +				 TVNORM_SECAM_LC)
> +
> +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
> 


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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-05-06 10:01   ` Hans Verkuil
@ 2019-05-06 10:06     ` Hans Verkuil
  2019-05-14 18:11     ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 70+ messages in thread
From: Hans Verkuil @ 2019-05-06 10:06 UTC (permalink / raw)
  To: Marco Felsch, mchehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

On 5/6/19 12:01 PM, Hans Verkuil wrote:
> On 4/15/19 2:44 PM, Marco Felsch wrote:
>> Some connectors no matter if in- or output supports only a limited
>> range of tv norms. It doesn't matter if the hardware behind that
>> connector supports more than the listed formats since the users are
>> restriced by a label e.g. to plug only a camera into this connector
>> which uses the PAL format.
> 
> For S-Video and Composite connectors there are really just two formats
> to consider: 50 and 60 Hz. I.e. there is no difference between PAL
> and SECAM. Only for tuners/modulators does this matter.

Sorry, I'm wrong about that. SECAM does matter.

But I still recommend adding these two defines and in the bindings
examples you can do something like TVNORM_PAL | TVNORM_NTSC.

Regards,

	Hans

> 
> So it is a good idea to add TVNORM_525_60, TVNORM_625_50 to tvnorms.h.
> 
> In the various bindings examples I would recommend that you use
> TVNORM_525_60 or TVNORM_625_50 rather than e.g. PAL_M since that's what
> you would use in practice for Composite/S-Video.
> 
> Regards,
> 
> 	Hans
> 
>>
>> This patch adds the capability to describe such limitation within the
>> firmware. There are no format restrictions if the property isn't
>> present, so it's completely backward compatible.
>>
>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
>> Reviewed-by: Rob Herring <robh@kernel.org>
>> ---
>> [1] https://patchwork.kernel.org/cover/10794703/
>>
>> v6:
>> - tvnorms.h: use tabs instead of spaces
>> - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
>> - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
>>
>> v2-v4:
>> - nothing since the patch was squashed from series [1] into this
>>   series.
>>
>>  .../display/connector/analog-tv-connector.txt |  4 ++
>>  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
>>  2 files changed, 60 insertions(+)
>>  create mode 100644 include/dt-bindings/media/tvnorms.h
>>
>> diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
>> index 0c0970c210ab..346f8937a0b7 100644
>> --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
>> +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
>> @@ -6,6 +6,9 @@ Required properties:
>>  
>>  Optional properties:
>>  - label: a symbolic name for the connector
>> +- tvnorms: limit the supported tv norms on a connector to the given ones else
>> +           all tv norms are allowed. Possible video standards are defined in
>> +           include/dt-bindings/media/tvnorms.h.
>>  
>>  Required nodes:
>>  - Video port for TV input
>> @@ -16,6 +19,7 @@ Example
>>  tv: connector {
>>  	compatible = "composite-video-connector";
>>  	label = "tv";
>> +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
>>  
>>  	port {
>>  		tv_connector_in: endpoint {
>> diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
>> new file mode 100644
>> index 000000000000..058ab8414145
>> --- /dev/null
>> +++ b/include/dt-bindings/media/tvnorms.h
>> @@ -0,0 +1,56 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
>> +/*
>> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
>> + */
>> +
>> +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
>> +#define _DT_BINDINGS_MEDIA_TVNORMS_H
>> +
>> +/* one bit for each */
>> +#define TVNORM_PAL_B		0x00000001
>> +#define TVNORM_PAL_B1		0x00000002
>> +#define TVNORM_PAL_G		0x00000004
>> +#define TVNORM_PAL_H		0x00000008
>> +#define TVNORM_PAL_I		0x00000010
>> +#define TVNORM_PAL_D		0x00000020
>> +#define TVNORM_PAL_D1		0x00000040
>> +#define TVNORM_PAL_K		0x00000080
>> +
>> +#define TVNORM_PAL		(TVNORM_PAL_B  | \
>> +				 TVNORM_PAL_B1 | \
>> +				 TVNORM_PAL_G  | \
>> +				 TVNORM_PAL_H  | \
>> +				 TVNORM_PAL_I  | \
>> +				 TVNORM_PAL_D  | \
>> +				 TVNORM_PAL_D1 | \
>> +				 TVNORM_PAL_K)
>> +
>> +#define TVNORM_PAL_M		0x00000100
>> +#define TVNORM_PAL_N		0x00000200
>> +#define TVNORM_PAL_Nc		0x00000400
>> +#define TVNORM_PAL_60		0x00000800
>> +
>> +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
>> +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
>> +#define TVNORM_NTSC_443		0x00004000
>> +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
>> +
>> +#define TVNORM_SECAM_B		0x00010000
>> +#define TVNORM_SECAM_D		0x00020000
>> +#define TVNORM_SECAM_G		0x00040000
>> +#define TVNORM_SECAM_H		0x00080000
>> +#define TVNORM_SECAM_K		0x00100000
>> +#define TVNORM_SECAM_K1		0x00200000
>> +#define TVNORM_SECAM_L		0x00400000
>> +#define TVNORM_SECAM_LC		0x00800000
>> +
>> +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
>> +				 TVNORM_SECAM_D  | \
>> +				 TVNORM_SECAM_G  | \
>> +				 TVNORM_SECAM_H  | \
>> +				 TVNORM_SECAM_K  | \
>> +				 TVNORM_SECAM_K1 | \
>> +				 TVNORM_SECAM_L  | \
>> +				 TVNORM_SECAM_LC)
>> +
>> +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
>>
> 


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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-04-15 12:44 ` [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support Marco Felsch
@ 2019-05-06 10:09   ` Jacopo Mondi
  2019-05-14 18:25   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 70+ messages in thread
From: Jacopo Mondi @ 2019-05-06 10:09 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 20507 bytes --]

Hi Marco,
   thanks, I still have a few more suggestions, but they're minors,
feel free to pick what you consider more appropriate.

On Mon, Apr 15, 2019 at 02:44:05PM +0200, Marco Felsch wrote:
> This patch adds the of_graph support to describe the tvp connections.
> Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> connector must be conneted to port@0/endpoint@1, look at the Documentation
> for more information. Since the TVP5150 is a converter the device-tree
> must contain at least 1-input and 1-output port. The mc-connectors and
> mc-links are only created if the device-tree contains the corresponding
> connector nodes. If more than one connector is available the
> media_entity_operations.link_setup() callback ensures that only one
> connector is active.
>
> [1] https://www.spinics.net/lists/linux-media/msg138545.html
> [2] https://www.spinics.net/lists/linux-media/msg138546.html
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> Changelog:
>
> [1] https://patchwork.kernel.org/cover/10794703/
> [2] https://patchwork.kernel.org/cover/10786553/
>
> v6:
> - fix misspelled comments
> - use 'unsigned int' where it's possible
> - cleanup ifdef part-2:
>   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
>     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
>   internal function do this.
> - tvp5150_add_of_connectors: call within probe() to make it cleaner
> - tvp5150_parse_dt: move local loop vars within the loop.
>
> v5:
> - Fixing build deps:
>   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
>   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
>     includes. This leads into to complex deps for futher development.
>   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
>   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
>   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
>
> - Simplify link_setup routine:
>   - use generic connector parsing since both series [1,2] are squashed into
>     one
>   - struct tvp5150: drop pads_state and modify_second_link property
>     due to link_setup() rework.
>   - tvp5150_link_setup: add more comments
>   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
>     link directly within the driver instead of a recursive media-framework
>     call (__media_entity_setup_link). This improves the readability and
>     shrinks the driver code.
>   - tvp5150_link_setup: disable all active links in case user switches
>     connectors without disable it first.
>   - tvp5150_registered: simplify default link enable path due to link_setup()
>     rework.
>
> - General cleanups
>   - tvp5150_parse_dt: drop unecessary test
>   - tvp5150_parse_dt: add err message due to misconfiguration
>   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
>   - s/dev_dbg/dev_dbg_lvl
>
> v4:
>  - rebase on top of media_tree/master, fix merge conflict due to commit
>    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
>    to zero")
>
> v3:
> - probe(): s/err/err_free_v4l2_ctrls
> - drop MC dependency for tvp5150_pads
>
> v2:
> - adapt commit message
> - unify ifdef switches
> - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> - mc: use 2-input and 1-output pad
> - mc: link svideo connector to both input pads
> - mc: enable/disable svideo links in one go
> - mc: change link_setup() behaviour, switch the input src don't require a
>       explicite disable before.
> - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> - mc: enable link to the first available connector and set the
>       corresponding tvp5150 input src per default during registered()
> - mc/of: factor out oftree connector allocation
> - of: drop svideo dt port
> - of: move svideo connector to port@0/endpoint@1
> - of: require at least 1-in and 1-out endpoint
>
>  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
>  1 file changed, 370 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 89da921c8886..4e3228b2ccbc 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
>  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
>
>  enum tvp5150_pads {
> -	TVP5150_PAD_IF_INPUT,
> +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> +	TVP5150_PAD_AIP1B,
>  	TVP5150_PAD_VID_OUT,
>  	TVP5150_NUM_PADS
>  };
>
> +struct tvp5150_connector {
> +	struct v4l2_fwnode_connector base;
> +	struct media_entity ent;
> +	struct media_pad pad;
> +};
> +
>  struct tvp5150 {
>  	struct v4l2_subdev sd;
> -#ifdef CONFIG_MEDIA_CONTROLLER
> +	/* additional endpoint for the svideo connector */
> +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> +	unsigned int endpoints_num;
> +
> +	/* media-ctl properties */
>  	struct media_pad pads[TVP5150_NUM_PADS];
> -#endif
> +	struct tvp5150_connector *connectors;
> +	int connectors_num;
> +
>  	struct v4l2_ctrl_handler hdl;
>  	struct v4l2_rect rect;
>  	struct regmap *regmap;
> @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
>  	return 0;
>  }
>
> +/****************************************************************************
> + *			Media entity ops
> + ****************************************************************************/
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +static int tvp5150_set_link(struct media_pad *connector_pad,
> +			    struct media_pad *tvp5150_pad, u32 flags)
> +{
> +	struct media_link *link;
> +
> +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> +	if (!link)
> +		return -EINVAL;
> +
> +	link->flags = flags;
> +	link->reverse->flags = link->flags;
> +
> +	return 0;
> +}
> +
> +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> +{
> +	struct media_pad *connector_pad;
> +	unsigned int i;
> +	int err;
> +
> +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> +		if (!connector_pad)
> +			continue;
> +
> +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> +			     u32 config);
> +
> +static int tvp5150_link_setup(struct media_entity *entity,
> +			      const struct media_pad *tvp5150_pad,
> +			      const struct media_pad *remote, u32 flags)
> +{
> +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct media_pad *other_tvp5150_pad =
> +		&decoder->pads[tvp5150_pad->index ^ 1];
> +	bool is_svideo = false;
> +	unsigned int i;
> +	int err;
> +
> +	/*
> +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> +	 * Enabling or disabling the source pad link has no effect.
> +	 */
> +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> +		return 0;
> +
> +	/* Check if the svideo connector should be enabled */
> +	for (i = 0; i < decoder->connectors_num; i++) {
> +		if (remote->entity == &decoder->connectors[i].ent) {
> +			is_svideo =
> +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> +			break;
> +		}
> +	}
> +
> +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> +		    remote->entity->name, remote->index,
> +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> +		    flags & MEDIA_LNK_FL_ENABLED);
> +	if (is_svideo)
> +		dev_dbg_lvl(sd->dev, 1, debug,
> +			    "link setup '%s':%d->'%s':%d[%d]",
> +			    remote->entity->name, remote->index,
> +			    other_tvp5150_pad->entity->name,
> +			    other_tvp5150_pad->index,
> +			    flags & MEDIA_LNK_FL_ENABLED);
> +
> +	/*
> +	 * The TVP5150 has an internal mux which allows the following setup:
> +	 *
> +	 * comp-connector1  --\
> +	 *		       |---> AIP1A
> +	 *		      /
> +	 * svideo-connector -|
> +	 *		      \
> +	 *		       |---> AIP1B
> +	 * comp-connector2  --/
> +	 *
> +	 * We can't rely on user space that the current connector gets disabled
> +	 * first before enabling the new connector. Disable all active
> +	 * connector links to be on the safe side.
> +	 */
> +	err = tvp5150_disable_all_input_links(decoder);

Does this imply when you enable a link to comp-connector2 the existing
link on comp-connector1 gets disabled? Is this desirable? Shouldn't
you do this only when dealing with s-video ?

> +	if (err)
> +		return err;
> +
> +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> +			  TVP5150_BLACK_SCREEN, 0);
> +
> +	if (flags & MEDIA_LNK_FL_ENABLED) {

nit: you could check for is_video here.

> +		/*
> +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> +		 * Both links must be enabled in one-shot regardless which link
> +		 * the user requests.
> +		 */
> +		if (is_svideo) {
> +			err = tvp5150_set_link((struct media_pad *) remote,
> +					       other_tvp5150_pad, flags);
> +			if (err)
> +				return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct media_entity_operations tvp5150_sd_media_ops = {
> +	.link_setup = tvp5150_link_setup,
> +};
> +#endif
>  /****************************************************************************
>  			I2C Command
>   ****************************************************************************/
> @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
>  	return 0;
>  }
>
> +static int tvp5150_registered(struct v4l2_subdev *sd)
> +{
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int i;
> +	int ret;
> +
> +	/*
> +	 * Setup connector pads and links. Enable the link to the first
> +	 * available connector per default.
> +	 */
> +	for (i = 0; i < decoder->connectors_num; i++) {
> +		struct media_entity *con = &decoder->connectors[i].ent;
> +		struct media_pad *pad = &decoder->connectors[i].pad;
> +		unsigned int port = decoder->connectors[i].base.remote_port;
> +		bool is_svideo =
> +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> +
> +		pad->flags = MEDIA_PAD_FL_SOURCE;
> +		ret = media_entity_pads_init(con, 1, pad);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> +		if (ret < 0) {
> +			media_device_unregister_entity(con);
> +			return ret;
> +		}
> +
> +		if (is_svideo) {
> +			/* svideo links to both aip1a and aip1b */
> +			ret = media_create_pad_link(con, 0, &sd->entity,
> +						    port + 1, flags);
> +			if (ret < 0) {
> +				media_device_unregister_entity(con);
> +				return ret;
> +			}
> +		}
> +
> +		/* enable default input */
> +		if (flags == MEDIA_LNK_FL_ENABLED) {
> +			decoder->input =
> +				is_svideo ? TVP5150_SVIDEO :
> +				port == 0 ? TVP5150_COMPOSITE0 :
> +				TVP5150_COMPOSITE1;
> +
> +			tvp5150_selmux(sd);
> +		}
> +	}
> +#endif

Additional blank linke maybe?

> +	return 0;
> +}
> +

Double empty line.

> +
>  /* ----------------------------------------------------------------------- */
>
>  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
>  	.pad = &tvp5150_pad_ops,
>  };
>
> +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> +	.registered = tvp5150_registered,
> +};
> +
>  /****************************************************************************
>  			I2C Client & Driver
>   ****************************************************************************/
> @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
>  	return 0;
>  }
>
> -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
>  {
> -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> -	struct device_node *ep;
> -	unsigned int flags;
> -	int ret = 0;
> +	struct device *dev = decoder->sd.dev;
> +	struct tvp5150_connector *connectors;
> +	unsigned int connectors_num = decoder->connectors_num;
> +	int i, ret;

i can be unsigned, and as noted below, you can remove ret.

>
> -	ep = of_graph_get_next_endpoint(np, NULL);
> -	if (!ep)
> -		return -EINVAL;
> +	/*
> +	 * Only add of_connectors if device really is a OF device since
> +	 * the driver is used by usb devices e.g. em28xx and embedded
> +	 * devices.
> +	 */
> +	if (!decoder->connectors_num)
> +		return 0;
>
> -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> -	if (ret)
> -		goto err;
> +	/* Allocate and initialize all available input connectors */
> +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> +				  GFP_KERNEL);
> +	if (!connectors)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < connectors_num; i++) {
> +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> +
> +		ret = v4l2_fwnode_parse_connector(
> +				   of_fwnode_handle(decoder->endpoints[i]), c);

You never use ret, drop it or check for the return value.

> +
> +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> +		connectors[i].ent.name = c->label;
> +	}
> +
> +	decoder->connectors = connectors;
> +
> +	return 0;
> +}
> +
> +static int tvp5150_mc_init(struct tvp5150 *decoder)
> +{
> +	struct v4l2_subdev *sd = &decoder->sd;
> +	unsigned int i;
> +
> +	sd->entity.ops = &tvp5150_sd_media_ops;
> +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> +
> +	/* Initialize all TVP5150 pads */
> +	for (i = 0; i < TVP5150_NUM_PADS; i++) {

Nit:
I would loop up to NUM_PADS - 1 and initialize the only source pad
separately. Up to you.

> +		if (i < TVP5150_NUM_PADS - 1) {
> +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> +		} else {
> +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> +		}
> +	}
> +
> +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> +				      decoder->pads);
> +}
> +
> +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> +
> +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> +{
> +	return 0;
> +}
>
> -	flags = bus_cfg.bus.parallel.flags;
> +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> +{
> +	return 0;
> +}
> +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
>
> -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> +{
> +	struct device *dev = decoder->sd.dev;
> +	struct device_node *ep_np;
> +	unsigned int i = 0, in = 0;
> +	int ret;
> +	bool found = false;
> +
> +	/* at least 1 output and 1 input */
> +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
>  		ret = -EINVAL;
>  		goto err;
>  	}
>
> -	decoder->mbus_type = bus_cfg.bus_type;
> +	for_each_endpoint_of_node(np, ep_np) {
> +		struct v4l2_fwnode_endpoint bus_cfg = {
> +			.bus_type = V4L2_MBUS_UNKNOWN
> +		};

Could you declare this inside the case block that actually uses it?

> +		struct v4l2_fwnode_connector c;

Same here

> +		struct of_endpoint ep;
> +		unsigned int flags;
> +
> +		of_graph_parse_endpoint(ep_np, &ep);
> +		switch (ep.port) {
> +		case TVP5150_PAD_AIP1A:
> +			/* fall through */
> +		case TVP5150_PAD_AIP1B:
> +			ret = v4l2_fwnode_parse_connector(
> +						   of_fwnode_handle(ep_np), &c);
> +			if (c.type != V4L2_CON_COMPOSITE &&
> +			    c.type != V4L2_CON_SVIDEO) {
> +				dev_err(dev,
> +					"Invalid endpoint %d on port %d\n",
> +					c.remote_id, c.remote_port);
> +				ret = -EINVAL;
> +				goto err;
> +			}
> +			in++;

Couldn't you increment decoder->num_connectors here?

Also, I really think you should not re-parse the connctor with a
separate tvp5150_add_of_connectors() call later. You can have up to
two connectors, I would say just allocate both of them and use the
appropriate ones.

It would save you the need to keep track of the endpoints in
'decoder->endpoints[]' which now you have to manually free at a later time
with a call to dt_cleanup(). You would also save parsing the connector
twice.

I would say this is up to you, this is not wrong, just harder to
follow.

With the minor issues reported above fixed:
Reviewed-by: Jacopo Mondi <jacopo+renesas@jmondi.org>

Thanks
  j

> +			break;
> +		case TVP5150_PAD_VID_OUT:
> +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> +							 &bus_cfg);
> +			if (ret)
> +				goto err;
> +
> +			flags = bus_cfg.bus.parallel.flags;
> +
> +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> +				ret = -EINVAL;
> +				goto err;
> +			}
> +
> +			decoder->mbus_type = bus_cfg.bus_type;
> +			break;
> +		default:
> +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> +				ep.port, ep.local_node);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		of_node_get(ep_np);
> +		decoder->endpoints[i] = ep_np;
> +		i++;
> +
> +		found = true;
> +	}
>
> +	decoder->connectors_num = in;
> +	return found ? 0 : -ENODEV;
>  err:
> -	of_node_put(ep);
>  	return ret;
>  }
>
> +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> +		of_node_put(decoder->endpoints[i]);
> +}
> +
>  static const char * const tvp5150_test_patterns[2] = {
>  	"Disabled",
>  	"Black screen"
> @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
>  		res = tvp5150_parse_dt(core, np);
>  		if (res) {
>  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> -			return res;
> +			goto err_cleanup_dt;
>  		}
>  	} else {
>  		/* Default to BT.656 embedded sync */
> @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
>  	}
>
>  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> +	sd->internal_ops = &tvp5150_internal_ops;
>  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>
> -#if defined(CONFIG_MEDIA_CONTROLLER)
> -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> -
> -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> -
> -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> -	if (res < 0)
> -		return res;
> +	res = tvp5150_mc_init(core);
> +	if (res)
> +		goto err_cleanup_dt;
>
> -#endif
> +	res = tvp5150_add_of_connectors(core);
> +	if (res)
> +		goto err_cleanup_dt;
>
>  	res = tvp5150_detect_version(core);
>  	if (res < 0)
> -		return res;
> +		goto err_cleanup_dt;
>
>  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
>  	core->detected_norm = V4L2_STD_UNKNOWN;
> @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
>  	sd->ctrl_handler = &core->hdl;
>  	if (core->hdl.error) {
>  		res = core->hdl.error;
> -		goto err;
> +		goto err_free_v4l2_ctrls;
>  	}
>
>  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
>  						tvp5150_isr, IRQF_TRIGGER_HIGH |
>  						IRQF_ONESHOT, "tvp5150", core);
>  		if (res)
> -			goto err;
> +			goto err_free_v4l2_ctrls;
>  	}
>
>  	res = v4l2_async_register_subdev(sd);
>  	if (res < 0)
> -		goto err;
> +		goto err_free_v4l2_ctrls;
>
>  	if (debug > 1)
>  		tvp5150_log_status(sd);
> +
>  	return 0;
>
> -err:
> +err_free_v4l2_ctrls:
>  	v4l2_ctrl_handler_free(&core->hdl);
> +err_cleanup_dt:
> +	if (IS_ENABLED(CONFIG_OF) && np)
> +		tvp5150_dt_cleanup(core);
> +
>  	return res;
>  }
>
> --
> 2.20.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-04-15 12:44 ` [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
@ 2019-05-06 10:10   ` Hans Verkuil
  2019-05-14 18:20     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 70+ messages in thread
From: Hans Verkuil @ 2019-05-06 10:10 UTC (permalink / raw)
  To: Marco Felsch, mchehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt
  Cc: laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi

On 4/15/19 2:44 PM, Marco Felsch wrote:
> The patch adds the initial connector parsing code, so we can move from a
> driver specific parsing code to a generic one. Currently only the
> generic fields and the analog-connector specific fields are parsed. Parsing
> the other connector specific fields can be added by a simple callbacks.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v6:
> - use 'unsigned int' count var
> - fix comment and style issues
> - place '/* fall through */' to correct places
> - fix error handling and cleanup by releasing fwnode
> - drop vga and dvi parsing support as those connectors are rarely used
>   these days
> 
> v5:
> - s/strlcpy/strscpy/
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
>  include/media/v4l2-fwnode.h           |  16 ++++
>  2 files changed, 127 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 20571846e636..f1cca95c8fef 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
>  
> +static const struct v4l2_fwnode_connector_conv {
> +	enum v4l2_connector_type type;
> +	const char *name;
> +} connectors[] = {
> +	{
> +		.type = V4L2_CON_COMPOSITE,
> +		.name = "composite-video-connector",
> +	}, {
> +		.type = V4L2_CON_SVIDEO,
> +		.name = "svideo-connector",
> +	}, {
> +		.type = V4L2_CON_HDMI,
> +		.name = "hdmi-connector",
> +	},
> +};
> +
> +static enum v4l2_connector_type
> +v4l2_fwnode_string_to_connector_type(const char *con_str)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> +		if (!strcmp(con_str, connectors[i].name))
> +			return connectors[i].type;
> +
> +	/* no valid connector found */
> +	return V4L2_CON_UNKNOWN;
> +}
> +
> +static int
> +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> +				   struct v4l2_fwnode_connector *vc)
> +{
> +	u32 tvnorms;
> +	int ret;
> +
> +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> +
> +	/* tvnorms is optional */
> +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> +
> +	return 0;
> +}
> +
> +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> +				struct v4l2_fwnode_connector *connector)
> +{
> +	struct fwnode_handle *fwnode;
> +	struct fwnode_endpoint __ep;
> +	const char *c_type_str, *label;
> +	int ret;
> +
> +	memset(connector, 0, sizeof(*connector));
> +
> +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> +	if (!fwnode)
> +		return -EINVAL;
> +
> +	/* parse all common properties first */
> +	/* connector-type is stored within the compatible string */
> +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> +	if (ret) {
> +		fwnode_handle_put(fwnode);
> +		return -EINVAL;
> +	}
> +
> +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> +
> +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> +	connector->remote_port = __ep.port;
> +	connector->remote_id = __ep.id;
> +
> +	ret = fwnode_property_read_string(fwnode, "label", &label);
> +	if (!ret) {
> +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> +	} else {
> +		/*
> +		 * labels are optional, if none is given create one:
> +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> +		 */
> +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> +			 connector->remote_id);
> +	}
> +
> +	/* now parse the connector specific properties */
> +	switch (connector->type) {
> +	case V4L2_CON_COMPOSITE:
> +		/* fall through */
> +	case V4L2_CON_SVIDEO:
> +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> +		break;
> +	case V4L2_CON_HDMI:
> +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> +			c_type_str);

Why warn? Just drop this.

> +		ret = 0;
> +		break;
> +	case V4L2_CON_UNKNOWN:
> +		/* fall through */
> +	default:
> +		pr_err("Unknown connector type\n");
> +		ret = -EINVAL;
> +	};
> +
> +	fwnode_handle_put(fwnode);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> +
>  static int
>  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
>  					  struct v4l2_async_notifier *notifier,
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index f4df1b95c5ef..e072f2915ddb 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
>   */
>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>  
> +/**
> + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> + *          connected to
> + * @connector: pointer to the V4L2 fwnode connector data structure
> + *
> + * Fill the connector data structure with the connector type, label and the
> + * endpoint id and port where the connector belongs to. If no label is present
> + * a unique one will be created. Labels with more than 40 characters are cut.
> + *
> + * Return: %0 on success or a negative error code on failure:
> + *	   %-EINVAL on parsing failure
> + */
> +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> +				struct v4l2_fwnode_connector *connector);
> +
>  /**
>   * typedef parse_endpoint_func - Driver's callback function to be called on
>   *	each V4L2 fwnode endpoint.
> 

Regards,

	Hans

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

* Re: [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-04-15 12:44 ` [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
@ 2019-05-06 13:36   ` Jacopo Mondi
  2019-08-09  5:33     ` Marco Felsch
  2019-05-14 18:48   ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 70+ messages in thread
From: Jacopo Mondi @ 2019-05-06 13:36 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 7996 bytes --]

Hi Marco,

On Mon, Apr 15, 2019 at 02:44:07PM +0200, Marco Felsch wrote:
> Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
> the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
> no way to try different selections. The patch adds a helper function to
> select the correct selection memory space (sub-device file handle or
> driver state) which will be set/returned.
>
> The TVP5150 AVID will be updated if the 'which' field is FORMAT_ACTIVE
> and the requested selection rectangle differs from the already set one.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> Changelog:
>
> v5:
>  - handle stub for v4l2_subdev_get_try_crop() internal since commit
>    ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
>    isn't anymore part of this series.
>  - add error handling of __tvp5150_get_pad_crop()
> v4:
>  - fix merge conflict due to rebase on top of media-tree/master
>  - __tvp5150_get_pad_crop(): cosmetic alignment fixes
>
>  drivers/media/i2c/tvp5150.c | 130 ++++++++++++++++++++++++++----------
>  1 file changed, 96 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 4e3228b2ccbc..9331609425bf 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -19,6 +19,7 @@
>  #include <media/v4l2-ctrls.h>
>  #include <media/v4l2-fwnode.h>
>  #include <media/v4l2-mc.h>
> +#include <media/v4l2-rect.h>
>
>  #include "tvp5150_reg.h"
>
> @@ -997,20 +998,48 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
>  		crop->height = TVP5150_V_MAX_OTHERS;
>  }
>
> +static struct v4l2_rect *
> +__tvp5150_get_pad_crop(struct tvp5150 *decoder,
> +		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> +		       enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
> +		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
> +#else
> +		return ERR_PTR(-ENOTTY);
> +#endif
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &decoder->rect;
> +	default:
> +		return NULL;

Do you need this default case? Can you return -EINVAL so that...

> +	}
> +}
> +
>  static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
>  			    struct v4l2_subdev_pad_config *cfg,
>  			    struct v4l2_subdev_format *format)
>  {
>  	struct v4l2_mbus_framefmt *f;
> +	struct v4l2_rect *__crop;
>  	struct tvp5150 *decoder = to_tvp5150(sd);
>
>  	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
>  		return -EINVAL;
>
>  	f = &format->format;
> +	__crop = __tvp5150_get_pad_crop(decoder, cfg, format->pad,
> +					format->which);
> +	if (IS_ERR_OR_NULL(__crop)) {

... here you just need to check if (IS_ERR()) and return it?

> +		if (!__crop)
> +			return -EINVAL;
> +		else
> +			return PTR_ERR(__crop);
> +	}
>
> -	f->width = decoder->rect.width;
> -	f->height = decoder->rect.height / 2;
> +	f->width = __crop->width;
> +	f->height = __crop->height / 2;
>
>  	f->code = TVP5150_MBUS_FMT;
>  	f->field = TVP5150_FIELD;
> @@ -1021,17 +1050,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
>  	return 0;
>  }
>
> +unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	v4l2_std_id std;
> +
> +	/* Calculate height based on current standard */
> +	if (decoder->norm == V4L2_STD_ALL)
> +		std = tvp5150_read_std(sd);
> +	else
> +		std = decoder->norm;
> +
> +	return (std & V4L2_STD_525_60) ?
> +		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
> +}
> +
> +static inline void
> +__tvp5150_set_selection(struct v4l2_subdev *sd, struct v4l2_rect rect)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int hmax = tvp5150_get_hmax(sd);
> +
> +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> +		     rect.top + rect.height - hmax);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> +		     rect.left >> TVP5150_CROP_SHIFT);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> +		     rect.left | (1 << TVP5150_CROP_SHIFT));
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> +		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> +		     TVP5150_CROP_SHIFT);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> +		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> +}
> +
>  static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  				 struct v4l2_subdev_pad_config *cfg,
>  				 struct v4l2_subdev_selection *sel)
>  {
>  	struct tvp5150 *decoder = to_tvp5150(sd);
>  	struct v4l2_rect rect = sel->r;
> -	v4l2_std_id std;
> -	int hmax;
> +	struct v4l2_rect *__crop;
> +	unsigned int hmax;
>
> -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
> -	    sel->target != V4L2_SEL_TGT_CROP)
> +	if (sel->target != V4L2_SEL_TGT_CROP)
>  		return -EINVAL;
>
>  	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
> @@ -1040,17 +1103,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  	/* tvp5150 has some special limits */
>  	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
>  	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
> -
> -	/* Calculate height based on current standard */
> -	if (decoder->norm == V4L2_STD_ALL)
> -		std = tvp5150_read_std(sd);
> -	else
> -		std = decoder->norm;
> -
> -	if (std & V4L2_STD_525_60)
> -		hmax = TVP5150_V_MAX_525_60;
> -	else
> -		hmax = TVP5150_V_MAX_OTHERS;
> +	hmax = tvp5150_get_hmax(sd);
>
>  	/*
>  	 * alignments:
> @@ -1063,20 +1116,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
>  			      hmax - rect.top, 0, 0);
>
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> -		     rect.top + rect.height - hmax);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> -		     rect.left >> TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> -		     rect.left | (1 << TVP5150_CROP_SHIFT));
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> -		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> -		     TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> -		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> +	__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
> +	if (IS_ERR_OR_NULL(__crop)) {
> +		if (!__crop)
> +			return -EINVAL;
> +		else
> +			return PTR_ERR(__crop);

here too

> +	}
> +
> +	/*
> +	 * Update output image size if the selection (crop) rectangle size or
> +	 * position has been modified.
> +	 */
> +	if (!v4l2_rect_equal(&rect, __crop))
> +		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)

Can this be a single condition?
Or maybe you could check if the rects are equal and this is a TRY and
return here.

> +			__tvp5150_set_selection(sd, rect);
>
> -	decoder->rect = rect;
> +	*__crop = rect;
>
>  	return 0;
>  }
> @@ -1086,11 +1142,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
>  				 struct v4l2_subdev_selection *sel)
>  {
>  	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
> +	struct v4l2_rect *__crop;
>  	v4l2_std_id std;
>
> -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> -		return -EINVAL;
> -
>  	switch (sel->target) {
>  	case V4L2_SEL_TGT_CROP_BOUNDS:
>  		sel->r.left = 0;
> @@ -1108,7 +1162,15 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
>  			sel->r.height = TVP5150_V_MAX_OTHERS;
>  		return 0;
>  	case V4L2_SEL_TGT_CROP:
> -		sel->r = decoder->rect;
> +		__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad,
> +						sel->which);
> +		if (IS_ERR_OR_NULL(__crop)) {
> +			if (!__crop)
> +				return -EINVAL;
> +			else
> +				return PTR_ERR(__crop);
> +		}
> +		sel->r = *__crop;
>  		return 0;
>  	default:
>  		return -EINVAL;
> --
> 2.20.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v6 13/13] media: tvp5150: make debug output more readable
  2019-04-15 12:44 ` [PATCH v6 13/13] media: tvp5150: make debug output more readable Marco Felsch
@ 2019-05-06 13:39   ` Jacopo Mondi
  2019-05-14 20:18     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 70+ messages in thread
From: Jacopo Mondi @ 2019-05-06 13:39 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 1610 bytes --]

Hi Marco,
  thanks

Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

On Mon, Apr 15, 2019 at 02:44:13PM +0200, Marco Felsch wrote:
> The debug output for tvp5150_selmux() isn't really intuitive. Register
> values are printed decimal formatted and the input/output driver states
> are printed as enum. Even more the "normal" output enum mapps to zero so
> a active output will printing output=0 and a inactive output=1.
>
> Change this by brinting the register values hex formatted and the states
> as more readable string.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  drivers/media/i2c/tvp5150.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index c0ee08546643..13ee6d781efb 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -302,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
>  		break;
>  	}
>
> -	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
> -			decoder->input, decoder->output,
> -			input, opmode);
> +	dev_dbg_lvl(sd->dev, 1, debug,
> +		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
> +		    decoder->input == 0 ? "aip1a" :
> +		    decoder->input == 2 ? "aip1b" : "svideo",
> +		    decoder->output == 0 ? "normal" : "black-frame-gen",
> +		    input, opmode);
>
>  	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
>  	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
> --
> 2.20.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v6 00/13] TVP5150 new features
  2019-05-06  5:47 ` [PATCH v6 00/13] TVP5150 new features Marco Felsch
@ 2019-05-14 17:18   ` Mauro Carvalho Chehab
  2019-05-14 20:20     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 17:18 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt, devicetree,
	laurent.pinchart, kernel, linux-media

Em Mon, 6 May 2019 07:47:13 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> Hi Mauro,
> 
> I know you are busy but can you have a look on it?

You should really trust on the sub-maintainers for such kind of
reviews :-)

I'll take a look today.

> 
> Regards,
>   Marco
> 
> On 19-04-15 14:44, Marco Felsch wrote:
> > Hi,
> > 
> > many thanks to Hans and Jacopo for the feedack :) this v6 address the
> > comments both made on my v5 [1].
> > 
> > In short this is round fixes just some minor issues rather than major
> > ones so the diff to the v5 is really small. The changed patches contain
> > the changelog so I omit it here.
> > 
> > I've tested it on a custom hardware but I can't test the em28xx usb
> > use-case since I haven't such a device. So other testers are welcome :)
> > 
> > Looking forward for your feedack,
> > 
> > 	Marco
> > 
> > [1] https://patchwork.kernel.org/cover/10886903/
> > 
> > Javier Martinez Canillas (1):
> >   partial revert of "[media] tvp5150: add HW input connectors support"
> > 
> > Marco Felsch (11):
> >   dt-bindings: connector: analog: add tv norms property
> >   media: v4l2-fwnode: add v4l2_fwnode_connector
> >   media: v4l2-fwnode: add initial connector parsing support
> >   media: tvp5150: add input source selection of_graph support
> >   media: dt-bindings: tvp5150: Add input port connectors DT bindings
> >   media: tvp5150: add FORMAT_TRY support for get/set selection handlers
> >   media: tvp5150: add s_power callback
> >   media: dt-bindings: tvp5150: cleanup bindings stlye
> >   media: dt-bindings: tvp5150: add optional tvnorms documentation
> >   media: tvp5150: add support to limit tv norms on connector
> >   media: tvp5150: make debug output more readable
> > 
> > Michael Tretter (1):
> >   media: tvp5150: initialize subdev before parsing device tree
> > 
> >  .../display/connector/analog-tv-connector.txt |   4 +
> >  .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
> >  drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
> >  drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
> >  include/dt-bindings/media/tvnorms.h           |  56 ++
> >  include/dt-bindings/media/tvp5150.h           |   2 -
> >  include/media/v4l2-connector.h                |  30 +
> >  include/media/v4l2-fwnode.h                   |  49 ++
> >  8 files changed, 859 insertions(+), 190 deletions(-)
> >  create mode 100644 include/dt-bindings/media/tvnorms.h
> >  create mode 100644 include/media/v4l2-connector.h
> > 
> > -- 
> > 2.20.1
> > 
> > 
> >   
> 



Thanks,
Mauro

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-05-06 10:01   ` Hans Verkuil
  2019-05-06 10:06     ` Hans Verkuil
@ 2019-05-14 18:11     ` Mauro Carvalho Chehab
  2019-08-09  6:00       ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:11 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Marco Felsch, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel,
	Rob Herring

Em Mon, 6 May 2019 12:01:06 +0200
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 4/15/19 2:44 PM, Marco Felsch wrote:
> > Some connectors no matter if in- or output supports only a limited
> > range of tv norms. It doesn't matter if the hardware behind that
> > connector supports more than the listed formats since the users are
> > restriced by a label e.g. to plug only a camera into this connector
> > which uses the PAL format.  
> 
> For S-Video and Composite connectors there are really just two formats
> to consider: 50 and 60 Hz. I.e. there is no difference between PAL
> and SECAM. Only for tuners/modulators does this matter.
> 
> So it is a good idea to add TVNORM_525_60, TVNORM_625_50 to tvnorms.h.
> 
> In the various bindings examples I would recommend that you use
> TVNORM_525_60 or TVNORM_625_50 rather than e.g. PAL_M since that's what
> you would use in practice for Composite/S-Video.

Hans, that could be true for component video, but for S-Video and
Composite, you need to tell the demod how the color sub-carrier is
encoded, and what's its frequency, or otherwise it won't work.

There are plenty of equipments in Brazil that have both NTSC/M and
PAL/M (and a few with PAL/N') output. All those formats are 60Hz.

Colors are only decoded by tvp5150 and other demods if it is set
to the right color format (PAL or NTSC) and to the right line 
frequency (60Hz) [1]. Also, some decoders are very sensitive to the
chroma sub-carrier frequency. That's the case of tvp5150.

[1] Or - when supported by the hardware - if the demod is set to
    automatic mode.

    Automatic mode usually doesn't work well with PAL/M and PAL/N'.

    The problem is related to the sub-carrier frequency: both 
    PAL/N' (used only on Paraguay) and NTSC/M have the same 
    frequency; PAL/M has a close but different frequency for the
    color sub-carrier.

    Most decoders use the frequency of the chroma sub-carrier in
    order to switch between NTSC/M nd PAL/M. So, auto-detection
    usually fails with PAL/N', as such detectors understand it
    as NTSC.

    Worse than that, it is not uncommon to have pseudo-PAL-M devices
    that were made for the US market, and received a conversion
    to PAL, with envolves adding a small board with a NTSC->PAL converter.
    As most TV sets used in this part of the world are designed to
    work both with PAL/M and PAL/N' (by using a broader notch filter),
    to make the hardware cheaper, lots of manufacturers just
    change the modulation on encoders, while keeping the NTSC XTAL.
    So, in practice, such devices, sold as "PAL/M" are actually PAL/N'.
    A significant amount of old VCRs and DVD devices found in Brazil
    are actually PAL/N'. The same applies to game consoles.

    Btw, the main reason for having analog video streams here nowadays
    is to copy old videos from VCRs and encode them digitally or to
    record games from game consoles.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > This patch adds the capability to describe such limitation within the
> > firmware. There are no format restrictions if the property isn't
> > present, so it's completely backward compatible.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - tvnorms.h: use tabs instead of spaces
> > - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  .../display/connector/analog-tv-connector.txt |  4 ++
> >  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> >  2 files changed, 60 insertions(+)
> >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > 
> > diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > index 0c0970c210ab..346f8937a0b7 100644
> > --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > @@ -6,6 +6,9 @@ Required properties:
> >  
> >  Optional properties:
> >  - label: a symbolic name for the connector
> > +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > +           all tv norms are allowed. Possible video standards are defined in
> > +           include/dt-bindings/media/tvnorms.h.
> >  
> >  Required nodes:
> >  - Video port for TV input
> > @@ -16,6 +19,7 @@ Example
> >  tv: connector {
> >  	compatible = "composite-video-connector";
> >  	label = "tv";
> > +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> >  
> >  	port {
> >  		tv_connector_in: endpoint {
> > diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > new file mode 100644
> > index 000000000000..058ab8414145
> > --- /dev/null
> > +++ b/include/dt-bindings/media/tvnorms.h
> > @@ -0,0 +1,56 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > +/*
> > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > + */
> > +
> > +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > +
> > +/* one bit for each */
> > +#define TVNORM_PAL_B		0x00000001
> > +#define TVNORM_PAL_B1		0x00000002
> > +#define TVNORM_PAL_G		0x00000004
> > +#define TVNORM_PAL_H		0x00000008
> > +#define TVNORM_PAL_I		0x00000010
> > +#define TVNORM_PAL_D		0x00000020
> > +#define TVNORM_PAL_D1		0x00000040
> > +#define TVNORM_PAL_K		0x00000080
> > +
> > +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > +				 TVNORM_PAL_B1 | \
> > +				 TVNORM_PAL_G  | \
> > +				 TVNORM_PAL_H  | \
> > +				 TVNORM_PAL_I  | \
> > +				 TVNORM_PAL_D  | \
> > +				 TVNORM_PAL_D1 | \
> > +				 TVNORM_PAL_K)
> > +
> > +#define TVNORM_PAL_M		0x00000100
> > +#define TVNORM_PAL_N		0x00000200
> > +#define TVNORM_PAL_Nc		0x00000400
> > +#define TVNORM_PAL_60		0x00000800
> > +
> > +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > +#define TVNORM_NTSC_443		0x00004000
> > +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > +
> > +#define TVNORM_SECAM_B		0x00010000
> > +#define TVNORM_SECAM_D		0x00020000
> > +#define TVNORM_SECAM_G		0x00040000
> > +#define TVNORM_SECAM_H		0x00080000
> > +#define TVNORM_SECAM_K		0x00100000
> > +#define TVNORM_SECAM_K1		0x00200000
> > +#define TVNORM_SECAM_L		0x00400000
> > +#define TVNORM_SECAM_LC		0x00800000
> > +
> > +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > +				 TVNORM_SECAM_D  | \
> > +				 TVNORM_SECAM_G  | \
> > +				 TVNORM_SECAM_H  | \
> > +				 TVNORM_SECAM_K  | \
> > +				 TVNORM_SECAM_K1 | \
> > +				 TVNORM_SECAM_L  | \
> > +				 TVNORM_SECAM_LC)
> > +
> > +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */

Patch looks good to me.

Thanks,
Mauro

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-05-06  9:50   ` Hans Verkuil
@ 2019-05-14 18:17     ` Mauro Carvalho Chehab
  2019-08-09  7:20     ` Marco Felsch
  1 sibling, 0 replies; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:17 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Marco Felsch, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel,
	Jacopo Mondi

Em Mon, 6 May 2019 11:50:20 +0200
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 4/15/19 2:44 PM, Marco Felsch wrote:
> > Currently every driver needs to parse the connector endpoints by it self.
> > This is the initial work to make this generic. The generic connector has
> > some common fields and some connector specific parts. The generic one
> > includes:
> >   - type
> >   - label
> >   - remote_port (the port where the connector is connected to)
> >   - remote_id   (the endpoint where the connector is connected to)
> > 
> > The specific fields are within a union, since only one of them can be
> > available at the time. Since this is the initial support the patch adds
> > only the analog-connector specific ones.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - fix some spelling and style issues
> > - rm unnecessary comments
> > - drop vga and dvi connector
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> >  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 63 insertions(+)
> >  create mode 100644 include/media/v4l2-connector.h
> > 
> > diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > new file mode 100644
> > index 000000000000..3a951c54f50e
> > --- /dev/null
> > +++ b/include/media/v4l2-connector.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * v4l2-connector.h
> > + *
> > + * V4L2 connector types.
> > + *
> > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > + */
> > +
> > +#ifndef V4L2_CONNECTOR_H
> > +#define V4L2_CONNECTOR_H
> > +
> > +#define V4L2_CONNECTOR_MAX_LABEL 41  
> 
> Where does 41 come from? It's a weird number...
> 
> > +
> > +/**
> > + * enum v4l2_connector_type - connector type
> > + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration  
> 
> typo: connetor -> connector
> 
> > + * @V4L2_CON_COMPOSITE: analog composite connector
> > + * @V4L2_CON_SVIDEO:    analog svideo connector
> > + * @V4L2_CON_HDMI:      digital hdmi connector
> > + */
> > +enum v4l2_connector_type {
> > +	V4L2_CON_UNKNOWN,
> > +	V4L2_CON_COMPOSITE,
> > +	V4L2_CON_SVIDEO,
> > +	V4L2_CON_HDMI,
> > +};
> > +
> > +#endif /* V4L2_CONNECTOR_H */
> > +  
> 
> Is there a reason to create a new header for this? I think it is perfectly OK to
> add this define + enum for v4l2-fwnode.h.
> 
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 6c07825e18b9..f4df1b95c5ef 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -22,6 +22,7 @@
> >  #include <linux/list.h>
> >  #include <linux/types.h>
> >  
> > +#include <media/v4l2-connector.h>
> >  #include <media/v4l2-mediabus.h>
> >  #include <media/v4l2-subdev.h>
> >  
> > @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> >  	unsigned int remote_port;
> >  };
> >  
> > +/**
> > + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > + *                     if no restrictions are specified.
> > + */
> > +struct v4l2_fwnode_connector_analog {
> > +	v4l2_std_id supported_tvnorms;
> > +};
> > +
> > +/**
> > + * struct v4l2_fwnode_connector - the connector data structure
> > + * @remote_port: identifier of the remote endpoint port the connector connects
> > + *		 to
> > + * @remote_id: identifier of the remote endpoint the connector connects to
> > + * @label: connetor label  
> 
> Same typo. It's probably a good idea to grep for this typo in this patch series :-)

Except for the points that Hans underlined, patch looks ok to me.

> 
> > + * @type: connector type
> > + * @connector: connector configuration
> > + * @connector.analog: analog connector configuration
> > + *                    &struct v4l2_fwnode_connector_analog
> > + */
> > +struct v4l2_fwnode_connector {
> > +	unsigned int remote_port;
> > +	unsigned int remote_id;
> > +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > +	enum v4l2_connector_type type;
> > +
> > +	union {
> > +		struct v4l2_fwnode_connector_analog analog;
> > +		/* future connectors */
> > +	} connector;
> > +};
> > +
> >  /**
> >   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> >   * @fwnode: pointer to the endpoint's fwnode handle
> >   
> 
> Regards,
> 
> 	Hans



Thanks,
Mauro

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-05-06 10:10   ` Hans Verkuil
@ 2019-05-14 18:20     ` Mauro Carvalho Chehab
  2019-05-16 16:51       ` Laurent Pinchart
  2019-08-09  8:59       ` Marco Felsch
  0 siblings, 2 replies; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:20 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Marco Felsch, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel,
	Jacopo Mondi

Em Mon, 6 May 2019 12:10:41 +0200
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 4/15/19 2:44 PM, Marco Felsch wrote:
> > The patch adds the initial connector parsing code, so we can move from a
> > driver specific parsing code to a generic one. Currently only the
> > generic fields and the analog-connector specific fields are parsed. Parsing
> > the other connector specific fields can be added by a simple callbacks.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - use 'unsigned int' count var
> > - fix comment and style issues
> > - place '/* fall through */' to correct places
> > - fix error handling and cleanup by releasing fwnode
> > - drop vga and dvi parsing support as those connectors are rarely used
> >   these days
> > 
> > v5:
> > - s/strlcpy/strscpy/
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> >  include/media/v4l2-fwnode.h           |  16 ++++
> >  2 files changed, 127 insertions(+)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index 20571846e636..f1cca95c8fef 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> >  }
> >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> >  
> > +static const struct v4l2_fwnode_connector_conv {
> > +	enum v4l2_connector_type type;
> > +	const char *name;
> > +} connectors[] = {
> > +	{
> > +		.type = V4L2_CON_COMPOSITE,
> > +		.name = "composite-video-connector",
> > +	}, {
> > +		.type = V4L2_CON_SVIDEO,
> > +		.name = "svideo-connector",
> > +	}, {
> > +		.type = V4L2_CON_HDMI,
> > +		.name = "hdmi-connector",
> > +	},
> > +};
> > +
> > +static enum v4l2_connector_type
> > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > +		if (!strcmp(con_str, connectors[i].name))
> > +			return connectors[i].type;
> > +
> > +	/* no valid connector found */
> > +	return V4L2_CON_UNKNOWN;
> > +}
> > +
> > +static int
> > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > +				   struct v4l2_fwnode_connector *vc)
> > +{
> > +	u32 tvnorms;
> > +	int ret;
> > +
> > +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > +
> > +	/* tvnorms is optional */
> > +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > +
> > +	return 0;
> > +}
> > +
> > +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > +				struct v4l2_fwnode_connector *connector)
> > +{
> > +	struct fwnode_handle *fwnode;
> > +	struct fwnode_endpoint __ep;
> > +	const char *c_type_str, *label;
> > +	int ret;
> > +
> > +	memset(connector, 0, sizeof(*connector));
> > +
> > +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> > +	if (!fwnode)
> > +		return -EINVAL;
> > +
> > +	/* parse all common properties first */
> > +	/* connector-type is stored within the compatible string */
> > +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> > +	if (ret) {
> > +		fwnode_handle_put(fwnode);
> > +		return -EINVAL;
> > +	}
> > +
> > +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > +
> > +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > +	connector->remote_port = __ep.port;
> > +	connector->remote_id = __ep.id;
> > +
> > +	ret = fwnode_property_read_string(fwnode, "label", &label);
> > +	if (!ret) {
> > +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > +	} else {
> > +		/*
> > +		 * labels are optional, if none is given create one:
> > +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > +		 */
> > +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > +			 connector->remote_id);
> > +	}
> > +
> > +	/* now parse the connector specific properties */
> > +	switch (connector->type) {
> > +	case V4L2_CON_COMPOSITE:
> > +		/* fall through */
> > +	case V4L2_CON_SVIDEO:
> > +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > +		break;
> > +	case V4L2_CON_HDMI:
> > +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> > +			c_type_str);  
> 
> Why warn? Just drop this.

good point. I would prefer to have some warning here, in order to warn a
developer that might be using it that this part of the code would require 
some change.

perhaps pr_warn_once()?

> 
> > +		ret = 0;
> > +		break;
> > +	case V4L2_CON_UNKNOWN:
> > +		/* fall through */
> > +	default:
> > +		pr_err("Unknown connector type\n");
> > +		ret = -EINVAL;
> > +	};
> > +
> > +	fwnode_handle_put(fwnode);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > +
> >  static int
> >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> >  					  struct v4l2_async_notifier *notifier,
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index f4df1b95c5ef..e072f2915ddb 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> >   */
> >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> >  
> > +/**
> > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > + *          connected to
> > + * @connector: pointer to the V4L2 fwnode connector data structure
> > + *
> > + * Fill the connector data structure with the connector type, label and the
> > + * endpoint id and port where the connector belongs to. If no label is present
> > + * a unique one will be created. Labels with more than 40 characters are cut.
> > + *
> > + * Return: %0 on success or a negative error code on failure:
> > + *	   %-EINVAL on parsing failure
> > + */
> > +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > +				struct v4l2_fwnode_connector *connector);
> > +
> >  /**
> >   * typedef parse_endpoint_func - Driver's callback function to be called on
> >   *	each V4L2 fwnode endpoint.
> >   
> 
> Regards,
> 
> 	Hans



Thanks,
Mauro

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-04-15 12:44 ` [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support Marco Felsch
  2019-05-06 10:09   ` Jacopo Mondi
@ 2019-05-14 18:25   ` Mauro Carvalho Chehab
  2019-05-16 18:03     ` Laurent Pinchart
  1 sibling, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:25 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Em Mon, 15 Apr 2019 14:44:05 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> This patch adds the of_graph support to describe the tvp connections.
> Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> connector must be conneted to port@0/endpoint@1, look at the Documentation
> for more information. Since the TVP5150 is a converter the device-tree
> must contain at least 1-input and 1-output port. The mc-connectors and
> mc-links are only created if the device-tree contains the corresponding
> connector nodes. If more than one connector is available the
> media_entity_operations.link_setup() callback ensures that only one
> connector is active.
> 
> [1] https://www.spinics.net/lists/linux-media/msg138545.html
> [2] https://www.spinics.net/lists/linux-media/msg138546.html
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> Changelog:
> 
> [1] https://patchwork.kernel.org/cover/10794703/
> [2] https://patchwork.kernel.org/cover/10786553/
> 
> v6:
> - fix misspelled comments
> - use 'unsigned int' where it's possible
> - cleanup ifdef part-2:
>   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
>     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
>   internal function do this.
> - tvp5150_add_of_connectors: call within probe() to make it cleaner
> - tvp5150_parse_dt: move local loop vars within the loop.
> 
> v5:
> - Fixing build deps:
>   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
>   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
>     includes. This leads into to complex deps for futher development.
>   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
>   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
>   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> 
> - Simplify link_setup routine:
>   - use generic connector parsing since both series [1,2] are squashed into
>     one
>   - struct tvp5150: drop pads_state and modify_second_link property
>     due to link_setup() rework.
>   - tvp5150_link_setup: add more comments
>   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
>     link directly within the driver instead of a recursive media-framework
>     call (__media_entity_setup_link). This improves the readability and
>     shrinks the driver code.
>   - tvp5150_link_setup: disable all active links in case user switches
>     connectors without disable it first.
>   - tvp5150_registered: simplify default link enable path due to link_setup()
>     rework.
> 
> - General cleanups
>   - tvp5150_parse_dt: drop unecessary test
>   - tvp5150_parse_dt: add err message due to misconfiguration
>   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
>   - s/dev_dbg/dev_dbg_lvl
> 
> v4:
>  - rebase on top of media_tree/master, fix merge conflict due to commit
>    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
>    to zero")
> 
> v3:
> - probe(): s/err/err_free_v4l2_ctrls
> - drop MC dependency for tvp5150_pads
> 
> v2:
> - adapt commit message
> - unify ifdef switches
> - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> - mc: use 2-input and 1-output pad
> - mc: link svideo connector to both input pads
> - mc: enable/disable svideo links in one go
> - mc: change link_setup() behaviour, switch the input src don't require a
>       explicite disable before.
> - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> - mc: enable link to the first available connector and set the
>       corresponding tvp5150 input src per default during registered()
> - mc/of: factor out oftree connector allocation
> - of: drop svideo dt port
> - of: move svideo connector to port@0/endpoint@1
> - of: require at least 1-in and 1-out endpoint
> 
>  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
>  1 file changed, 370 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 89da921c8886..4e3228b2ccbc 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
>  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
>  
>  enum tvp5150_pads {
> -	TVP5150_PAD_IF_INPUT,
> +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> +	TVP5150_PAD_AIP1B,
>  	TVP5150_PAD_VID_OUT,
>  	TVP5150_NUM_PADS
>  };
>  
> +struct tvp5150_connector {
> +	struct v4l2_fwnode_connector base;
> +	struct media_entity ent;
> +	struct media_pad pad;
> +};
> +
>  struct tvp5150 {
>  	struct v4l2_subdev sd;
> -#ifdef CONFIG_MEDIA_CONTROLLER
> +	/* additional endpoint for the svideo connector */
> +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> +	unsigned int endpoints_num;
> +
> +	/* media-ctl properties */
>  	struct media_pad pads[TVP5150_NUM_PADS];
> -#endif
> +	struct tvp5150_connector *connectors;
> +	int connectors_num;
> +
>  	struct v4l2_ctrl_handler hdl;
>  	struct v4l2_rect rect;
>  	struct regmap *regmap;
> @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> +/****************************************************************************
> + *			Media entity ops
> + ****************************************************************************/
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +static int tvp5150_set_link(struct media_pad *connector_pad,
> +			    struct media_pad *tvp5150_pad, u32 flags)
> +{
> +	struct media_link *link;
> +
> +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> +	if (!link)
> +		return -EINVAL;
> +
> +	link->flags = flags;
> +	link->reverse->flags = link->flags;
> +
> +	return 0;
> +}
> +
> +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> +{
> +	struct media_pad *connector_pad;
> +	unsigned int i;
> +	int err;
> +
> +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> +		if (!connector_pad)
> +			continue;
> +
> +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> +			     u32 config);
> +
> +static int tvp5150_link_setup(struct media_entity *entity,
> +			      const struct media_pad *tvp5150_pad,
> +			      const struct media_pad *remote, u32 flags)
> +{
> +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct media_pad *other_tvp5150_pad =
> +		&decoder->pads[tvp5150_pad->index ^ 1];
> +	bool is_svideo = false;
> +	unsigned int i;
> +	int err;
> +
> +	/*
> +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> +	 * Enabling or disabling the source pad link has no effect.
> +	 */
> +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> +		return 0;
> +
> +	/* Check if the svideo connector should be enabled */
> +	for (i = 0; i < decoder->connectors_num; i++) {
> +		if (remote->entity == &decoder->connectors[i].ent) {

> +			is_svideo =
> +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;

Nitpick:

I would actually prefer to keep this on a single line. Ok, it will violate
the 80-columns, but it would be better than the above (IMHO).

> +			break;
> +		}
> +	}
> +
> +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> +		    remote->entity->name, remote->index,
> +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> +		    flags & MEDIA_LNK_FL_ENABLED);
> +	if (is_svideo)
> +		dev_dbg_lvl(sd->dev, 1, debug,
> +			    "link setup '%s':%d->'%s':%d[%d]",
> +			    remote->entity->name, remote->index,
> +			    other_tvp5150_pad->entity->name,
> +			    other_tvp5150_pad->index,
> +			    flags & MEDIA_LNK_FL_ENABLED);
> +
> +	/*
> +	 * The TVP5150 has an internal mux which allows the following setup:
> +	 *
> +	 * comp-connector1  --\
> +	 *		       |---> AIP1A
> +	 *		      /
> +	 * svideo-connector -|
> +	 *		      \
> +	 *		       |---> AIP1B
> +	 * comp-connector2  --/
> +	 *
> +	 * We can't rely on user space that the current connector gets disabled
> +	 * first before enabling the new connector. Disable all active
> +	 * connector links to be on the safe side.
> +	 */
> +	err = tvp5150_disable_all_input_links(decoder);
> +	if (err)
> +		return err;
> +
> +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> +			  TVP5150_BLACK_SCREEN, 0);
> +
> +	if (flags & MEDIA_LNK_FL_ENABLED) {
> +		/*
> +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> +		 * Both links must be enabled in one-shot regardless which link
> +		 * the user requests.
> +		 */
> +		if (is_svideo) {
> +			err = tvp5150_set_link((struct media_pad *) remote,
> +					       other_tvp5150_pad, flags);
> +			if (err)
> +				return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct media_entity_operations tvp5150_sd_media_ops = {
> +	.link_setup = tvp5150_link_setup,
> +};
> +#endif
>  /****************************************************************************
>  			I2C Command
>   ****************************************************************************/
> @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
>  	return 0;
>  }
>  
> +static int tvp5150_registered(struct v4l2_subdev *sd)
> +{
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int i;
> +	int ret;
> +
> +	/*
> +	 * Setup connector pads and links. Enable the link to the first
> +	 * available connector per default.
> +	 */
> +	for (i = 0; i < decoder->connectors_num; i++) {
> +		struct media_entity *con = &decoder->connectors[i].ent;
> +		struct media_pad *pad = &decoder->connectors[i].pad;
> +		unsigned int port = decoder->connectors[i].base.remote_port;
> +		bool is_svideo =
> +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> +
> +		pad->flags = MEDIA_PAD_FL_SOURCE;
> +		ret = media_entity_pads_init(con, 1, pad);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> +		if (ret < 0) {
> +			media_device_unregister_entity(con);
> +			return ret;
> +		}
> +
> +		if (is_svideo) {
> +			/* svideo links to both aip1a and aip1b */
> +			ret = media_create_pad_link(con, 0, &sd->entity,
> +						    port + 1, flags);
> +			if (ret < 0) {
> +				media_device_unregister_entity(con);
> +				return ret;
> +			}
> +		}
> +
> +		/* enable default input */
> +		if (flags == MEDIA_LNK_FL_ENABLED) {
> +			decoder->input =
> +				is_svideo ? TVP5150_SVIDEO :
> +				port == 0 ? TVP5150_COMPOSITE0 :
> +				TVP5150_COMPOSITE1;
> +
> +			tvp5150_selmux(sd);
> +		}
> +	}
> +#endif
> +	return 0;
> +}
> +
> +
>  /* ----------------------------------------------------------------------- */
>  
>  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
>  	.pad = &tvp5150_pad_ops,
>  };
>  
> +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> +	.registered = tvp5150_registered,
> +};
> +
>  /****************************************************************************
>  			I2C Client & Driver
>   ****************************************************************************/
> @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
>  	return 0;
>  }
>  
> -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
>  {
> -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> -	struct device_node *ep;
> -	unsigned int flags;
> -	int ret = 0;
> +	struct device *dev = decoder->sd.dev;
> +	struct tvp5150_connector *connectors;
> +	unsigned int connectors_num = decoder->connectors_num;
> +	int i, ret;
>  
> -	ep = of_graph_get_next_endpoint(np, NULL);
> -	if (!ep)
> -		return -EINVAL;
> +	/*
> +	 * Only add of_connectors if device really is a OF device since
> +	 * the driver is used by usb devices e.g. em28xx and embedded
> +	 * devices.
> +	 */
> +	if (!decoder->connectors_num)
> +		return 0;
>  
> -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> -	if (ret)
> -		goto err;
> +	/* Allocate and initialize all available input connectors */
> +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> +				  GFP_KERNEL);
> +	if (!connectors)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < connectors_num; i++) {
> +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> +
> +		ret = v4l2_fwnode_parse_connector(
> +				   of_fwnode_handle(decoder->endpoints[i]), c);
> +
> +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> +		connectors[i].ent.name = c->label;
> +	}
> +
> +	decoder->connectors = connectors;
> +
> +	return 0;
> +}
> +
> +static int tvp5150_mc_init(struct tvp5150 *decoder)
> +{
> +	struct v4l2_subdev *sd = &decoder->sd;
> +	unsigned int i;
> +
> +	sd->entity.ops = &tvp5150_sd_media_ops;
> +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> +
> +	/* Initialize all TVP5150 pads */
> +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> +		if (i < TVP5150_NUM_PADS - 1) {
> +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> +		} else {
> +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> +		}
> +	}
> +
> +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> +				      decoder->pads);
> +}
> +
> +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> +
> +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> +{
> +	return 0;
> +}
>  
> -	flags = bus_cfg.bus.parallel.flags;
> +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> +{
> +	return 0;
> +}
> +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
>  
> -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> +{
> +	struct device *dev = decoder->sd.dev;
> +	struct device_node *ep_np;
> +	unsigned int i = 0, in = 0;
> +	int ret;
> +	bool found = false;
> +
> +	/* at least 1 output and 1 input */
> +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
>  		ret = -EINVAL;
>  		goto err;
>  	}
>  
> -	decoder->mbus_type = bus_cfg.bus_type;
> +	for_each_endpoint_of_node(np, ep_np) {
> +		struct v4l2_fwnode_endpoint bus_cfg = {
> +			.bus_type = V4L2_MBUS_UNKNOWN
> +		};
> +		struct v4l2_fwnode_connector c;
> +		struct of_endpoint ep;
> +		unsigned int flags;
> +
> +		of_graph_parse_endpoint(ep_np, &ep);
> +		switch (ep.port) {
> +		case TVP5150_PAD_AIP1A:
> +			/* fall through */
> +		case TVP5150_PAD_AIP1B:
> +			ret = v4l2_fwnode_parse_connector(
> +						   of_fwnode_handle(ep_np), &c);
> +			if (c.type != V4L2_CON_COMPOSITE &&
> +			    c.type != V4L2_CON_SVIDEO) {
> +				dev_err(dev,
> +					"Invalid endpoint %d on port %d\n",
> +					c.remote_id, c.remote_port);
> +				ret = -EINVAL;
> +				goto err;
> +			}
> +			in++;
> +			break;
> +		case TVP5150_PAD_VID_OUT:
> +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> +							 &bus_cfg);
> +			if (ret)
> +				goto err;
> +
> +			flags = bus_cfg.bus.parallel.flags;
> +
> +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> +				ret = -EINVAL;
> +				goto err;
> +			}
> +
> +			decoder->mbus_type = bus_cfg.bus_type;
> +			break;
> +		default:
> +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> +				ep.port, ep.local_node);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		of_node_get(ep_np);
> +		decoder->endpoints[i] = ep_np;
> +		i++;
> +
> +		found = true;
> +	}
>  
> +	decoder->connectors_num = in;
> +	return found ? 0 : -ENODEV;
>  err:
> -	of_node_put(ep);
>  	return ret;
>  }
>  
> +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> +		of_node_put(decoder->endpoints[i]);
> +}
> +
>  static const char * const tvp5150_test_patterns[2] = {
>  	"Disabled",
>  	"Black screen"
> @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
>  		res = tvp5150_parse_dt(core, np);
>  		if (res) {
>  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> -			return res;
> +			goto err_cleanup_dt;
>  		}
>  	} else {
>  		/* Default to BT.656 embedded sync */
> @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
>  	}
>  
>  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> +	sd->internal_ops = &tvp5150_internal_ops;
>  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>  
> -#if defined(CONFIG_MEDIA_CONTROLLER)
> -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> -
> -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> -
> -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> -	if (res < 0)
> -		return res;
> +	res = tvp5150_mc_init(core);
> +	if (res)
> +		goto err_cleanup_dt;
>  
> -#endif
> +	res = tvp5150_add_of_connectors(core);
> +	if (res)
> +		goto err_cleanup_dt;
>  
>  	res = tvp5150_detect_version(core);
>  	if (res < 0)
> -		return res;
> +		goto err_cleanup_dt;
>  
>  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
>  	core->detected_norm = V4L2_STD_UNKNOWN;
> @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
>  	sd->ctrl_handler = &core->hdl;
>  	if (core->hdl.error) {
>  		res = core->hdl.error;
> -		goto err;
> +		goto err_free_v4l2_ctrls;
>  	}
>  
>  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
>  						tvp5150_isr, IRQF_TRIGGER_HIGH |
>  						IRQF_ONESHOT, "tvp5150", core);
>  		if (res)
> -			goto err;
> +			goto err_free_v4l2_ctrls;
>  	}
>  
>  	res = v4l2_async_register_subdev(sd);
>  	if (res < 0)
> -		goto err;
> +		goto err_free_v4l2_ctrls;
>  
>  	if (debug > 1)
>  		tvp5150_log_status(sd);
> +
>  	return 0;
>  
> -err:
> +err_free_v4l2_ctrls:
>  	v4l2_ctrl_handler_free(&core->hdl);
> +err_cleanup_dt:
> +	if (IS_ENABLED(CONFIG_OF) && np)
> +		tvp5150_dt_cleanup(core);
> +
>  	return res;
>  }
>  



Thanks,
Mauro

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

* Re: [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings
  2019-04-15 12:44 ` [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
@ 2019-05-14 18:27   ` Mauro Carvalho Chehab
  2019-05-16 18:05   ` Laurent Pinchart
  1 sibling, 0 replies; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:27 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel, Rob Herring

Em Mon, 15 Apr 2019 14:44:06 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> The TVP5150/1 decoders support different video input sources to their
> AIP1A/B pins.
> 
> Possible configurations are as follows:
>   - Analog Composite signal connected to AIP1A.
>   - Analog Composite signal connected to AIP1B.
>   - Analog S-Video Y (luminance) and C (chrominance)
>     signals connected to AIP1A and AIP1B respectively.
> 
> This patch extends the device tree bindings documentation to describe
> how the input connectors for these devices should be defined in a DT.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Rob Herring <robh@kernel.org>

Looks good to me.

> ---
> Changelog:
> 
> v3:
> - remove examples for one and two inputs
> - replace space by tabs
> 
> v2:
> - adapt port layout in accordance with
>   https://www.spinics.net/lists/linux-media/msg138546.html with the
>   svideo-connector deviation (use only one endpoint)
> 
>  .../devicetree/bindings/media/i2c/tvp5150.txt | 92 +++++++++++++++++--
>  1 file changed, 85 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> index 8c0fc1a26bf0..bdd273d8b44d 100644
> --- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> @@ -12,11 +12,31 @@ Optional Properties:
>  - pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
>  - reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
>  
> -The device node must contain one 'port' child node for its digital output
> -video port, in accordance with the video interface bindings defined in
> -Documentation/devicetree/bindings/media/video-interfaces.txt.
> +The device node must contain one 'port' child node per device physical input
> +and output port, in accordance with the video interface bindings defined in
> +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
> +are numbered as follows
>  
> -Required Endpoint Properties for parallel synchronization:
> +	  Name		Type		Port
> +	--------------------------------------
> +	  AIP1A		sink		0
> +	  AIP1B		sink		1
> +	  Y-OUT		src		2
> +
> +The device node must contain at least one sink port and the src port. Each input
> +port must be linked to an endpoint defined in
> +Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
> +port/connector layout is as follows
> +
> +tvp-5150 port@0 (AIP1A)
> +	endpoint@0 -----------> Comp0-Con  port
> +	endpoint@1 -----------> Svideo-Con port
> +tvp-5150 port@1 (AIP1B)
> +	endpoint   -----------> Comp1-Con  port
> +tvp-5150 port@2
> +	endpoint (video bitstream output at YOUT[0-7] parallel bus)
> +
> +Required Endpoint Properties for parallel synchronization on output port:
>  
>  - hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
>  - vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
> @@ -26,17 +46,75 @@ Required Endpoint Properties for parallel synchronization:
>  If none of hsync-active, vsync-active and field-even-active is specified,
>  the endpoint is assumed to use embedded BT.656 synchronization.
>  
> -Example:
> +Example - three input sources:
> +
> +comp_connector_0 {
> +	compatible = "composite-video-connector";
> +	label = "Composite0";
> +
> +	port {
> +		composite0_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_composite0>;
> +		};
> +	};
> +};
> +
> +comp_connector_1 {
> +	compatible = "composite-video-connector";
> +	label = "Composite1";
> +
> +	port {
> +		composite1_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_composite1>;
> +		};
> +	};
> +};
> +
> +svid_connector {
> +	compatible = "svideo-connector";
> +	label = "S-Video";
> +
> +	port {
> +		svideo_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_svideo>;
> +		};
> +	};
> +};
>  
>  &i2c2 {
> -	...
>  	tvp5150@5c {
>  		compatible = "ti,tvp5150";
>  		reg = <0x5c>;
>  		pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
>  		reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
>  
> -		port {
> +		port@0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +
> +			tvp5150_to_composite0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&composite0_to_tvp5150>;
> +			};
> +
> +			tvp5150_to_svideo: endpoint@1 {
> +				reg = <1>;
> +				remote-endpoint = <&svideo_to_tvp5150>;
> +			};
> +		};
> +
> +		port@1 {
> +			reg = <1>;
> +
> +			tvp5150_to_composite1: endpoint {
> +                                remote-endpoint = <&composite1_to_tvp5150>;
> +			};
> +		};
> +
> +		port@2 {
> +			reg = <2>;
> +
>  			tvp5150_1: endpoint {
>  				remote-endpoint = <&ccdc_ep>;
>  			};



Thanks,
Mauro

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

* Re: [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-04-15 12:44 ` [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
  2019-05-06 13:36   ` Jacopo Mondi
@ 2019-05-14 18:48   ` Mauro Carvalho Chehab
  2019-08-09  5:34     ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 18:48 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Em Mon, 15 Apr 2019 14:44:07 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
> the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
> no way to try different selections. The patch adds a helper function to
> select the correct selection memory space (sub-device file handle or
> driver state) which will be set/returned.
> 
> The TVP5150 AVID will be updated if the 'which' field is FORMAT_ACTIVE
> and the requested selection rectangle differs from the already set one.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> Changelog:
> 
> v5:
>  - handle stub for v4l2_subdev_get_try_crop() internal since commit
>    ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
>    isn't anymore part of this series.
>  - add error handling of __tvp5150_get_pad_crop()
> v4:
>  - fix merge conflict due to rebase on top of media-tree/master
>  - __tvp5150_get_pad_crop(): cosmetic alignment fixes
> 
>  drivers/media/i2c/tvp5150.c | 130 ++++++++++++++++++++++++++----------
>  1 file changed, 96 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 4e3228b2ccbc..9331609425bf 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -19,6 +19,7 @@
>  #include <media/v4l2-ctrls.h>
>  #include <media/v4l2-fwnode.h>
>  #include <media/v4l2-mc.h>
> +#include <media/v4l2-rect.h>
>  
>  #include "tvp5150_reg.h"
>  
> @@ -997,20 +998,48 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
>  		crop->height = TVP5150_V_MAX_OTHERS;
>  }
>  
> +static struct v4l2_rect *
> +__tvp5150_get_pad_crop(struct tvp5150 *decoder,
> +		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> +		       enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
> +		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
> +#else
> +		return ERR_PTR(-ENOTTY);
> +#endif
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &decoder->rect;
> +	default:
> +		return NULL;
> +	}

Same comments as Jacopo: use return ERR_PTR(-EINVAL) instead...

> +}
> +
>  static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
>  			    struct v4l2_subdev_pad_config *cfg,
>  			    struct v4l2_subdev_format *format)
>  {
>  	struct v4l2_mbus_framefmt *f;
> +	struct v4l2_rect *__crop;
>  	struct tvp5150 *decoder = to_tvp5150(sd);
>  
>  	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
>  		return -EINVAL;
>  
>  	f = &format->format;
> +	__crop = __tvp5150_get_pad_crop(decoder, cfg, format->pad,
> +					format->which);
> +	if (IS_ERR_OR_NULL(__crop)) {
> +		if (!__crop)
> +			return -EINVAL;
> +		else
> +			return PTR_ERR(__crop);

And here, return PTR_ERR directly. Same at the similar case below.

> +	}
>  
> -	f->width = decoder->rect.width;
> -	f->height = decoder->rect.height / 2;
> +	f->width = __crop->width;
> +	f->height = __crop->height / 2;
>  
>  	f->code = TVP5150_MBUS_FMT;
>  	f->field = TVP5150_FIELD;
> @@ -1021,17 +1050,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> +unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	v4l2_std_id std;
> +
> +	/* Calculate height based on current standard */
> +	if (decoder->norm == V4L2_STD_ALL)
> +		std = tvp5150_read_std(sd);
> +	else
> +		std = decoder->norm;
> +
> +	return (std & V4L2_STD_525_60) ?
> +		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
> +}
> +
> +static inline void
> +__tvp5150_set_selection(struct v4l2_subdev *sd, struct v4l2_rect rect)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int hmax = tvp5150_get_hmax(sd);
> +
> +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> +		     rect.top + rect.height - hmax);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> +		     rect.left >> TVP5150_CROP_SHIFT);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> +		     rect.left | (1 << TVP5150_CROP_SHIFT));
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> +		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> +		     TVP5150_CROP_SHIFT);
> +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> +		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> +}
> +
>  static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  				 struct v4l2_subdev_pad_config *cfg,
>  				 struct v4l2_subdev_selection *sel)
>  {
>  	struct tvp5150 *decoder = to_tvp5150(sd);
>  	struct v4l2_rect rect = sel->r;
> -	v4l2_std_id std;
> -	int hmax;
> +	struct v4l2_rect *__crop;
> +	unsigned int hmax;
>  
> -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
> -	    sel->target != V4L2_SEL_TGT_CROP)
> +	if (sel->target != V4L2_SEL_TGT_CROP)
>  		return -EINVAL;
>  
>  	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
> @@ -1040,17 +1103,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  	/* tvp5150 has some special limits */
>  	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
>  	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
> -
> -	/* Calculate height based on current standard */
> -	if (decoder->norm == V4L2_STD_ALL)
> -		std = tvp5150_read_std(sd);
> -	else
> -		std = decoder->norm;
> -
> -	if (std & V4L2_STD_525_60)
> -		hmax = TVP5150_V_MAX_525_60;
> -	else
> -		hmax = TVP5150_V_MAX_OTHERS;
> +	hmax = tvp5150_get_hmax(sd);
>  
>  	/*
>  	 * alignments:
> @@ -1063,20 +1116,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
>  			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
>  			      hmax - rect.top, 0, 0);
>  
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> -		     rect.top + rect.height - hmax);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> -		     rect.left >> TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> -		     rect.left | (1 << TVP5150_CROP_SHIFT));
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> -		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> -		     TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> -		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> +	__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
> +	if (IS_ERR_OR_NULL(__crop)) {
> +		if (!__crop)
> +			return -EINVAL;
> +		else
> +			return PTR_ERR(__crop);
> +	}
> +
> +	/*
> +	 * Update output image size if the selection (crop) rectangle size or
> +	 * position has been modified.
> +	 */
> +	if (!v4l2_rect_equal(&rect, __crop))
> +		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> +			__tvp5150_set_selection(sd, rect);
>  
> -	decoder->rect = rect;
> +	*__crop = rect;
>  
>  	return 0;
>  }
> @@ -1086,11 +1142,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
>  				 struct v4l2_subdev_selection *sel)
>  {
>  	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
> +	struct v4l2_rect *__crop;
>  	v4l2_std_id std;
>  
> -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> -		return -EINVAL;
> -
>  	switch (sel->target) {
>  	case V4L2_SEL_TGT_CROP_BOUNDS:
>  		sel->r.left = 0;
> @@ -1108,7 +1162,15 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
>  			sel->r.height = TVP5150_V_MAX_OTHERS;
>  		return 0;
>  	case V4L2_SEL_TGT_CROP:
> -		sel->r = decoder->rect;
> +		__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad,
> +						sel->which);
> +		if (IS_ERR_OR_NULL(__crop)) {
> +			if (!__crop)
> +				return -EINVAL;
> +			else
> +				return PTR_ERR(__crop);
> +		}
> +		sel->r = *__crop;
>  		return 0;
>  	default:
>  		return -EINVAL;



Thanks,
Mauro

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

* Re: [PATCH v6 09/13] media: tvp5150: add s_power callback
  2019-04-15 12:44 ` [PATCH v6 09/13] media: tvp5150: add s_power callback Marco Felsch
@ 2019-05-14 20:13   ` Mauro Carvalho Chehab
  2019-08-09  5:39     ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 20:13 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Em Mon, 15 Apr 2019 14:44:09 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> Don't en-/disable the interrupts during s_stream because someone can
> disable the stream but wants to get informed if the stream is locked
> again. So keep the interrupts enabled the whole time the pipeline is
> opened.

Not testing on any tvp5150 hardware, looks ok to me.

> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 305a5e256b31..cd54715eb641 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -1370,11 +1370,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
>  /****************************************************************************
>  			I2C Command
>   ****************************************************************************/
> +static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int val = 0;
> +
> +	if (on)
> +		val = TVP5150_INT_A_LOCK;
> +
> +	if (decoder->irq)
> +		/* Enable / Disable lock interrupt */
> +		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> +				   TVP5150_INT_A_LOCK, val);
> +
> +	return 0;
> +}
>  
>  static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
>  {
>  	struct tvp5150 *decoder = to_tvp5150(sd);
> -	unsigned int mask, val = 0, int_val = 0;
> +	unsigned int mask, val = 0;
>  
>  	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
>  	       TVP5150_MISC_CTL_CLOCK_OE;
> @@ -1387,15 +1402,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
>  			val = decoder->lock ? decoder->oe : 0;
>  		else
>  			val = decoder->oe;
> -		int_val = TVP5150_INT_A_LOCK;
>  		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
>  	}
>  
>  	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
> -	if (decoder->irq)
> -		/* Enable / Disable lock interrupt */
> -		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> -				   TVP5150_INT_A_LOCK, int_val);
>  
>  	return 0;
>  }
> @@ -1586,6 +1596,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
>  	.g_register = tvp5150_g_register,
>  	.s_register = tvp5150_s_register,
>  #endif
> +	.s_power = tvp5150_s_power,
>  };
>  
>  static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {



Thanks,
Mauro

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

* Re: [PATCH v6 13/13] media: tvp5150: make debug output more readable
  2019-05-06 13:39   ` Jacopo Mondi
@ 2019-05-14 20:18     ` Mauro Carvalho Chehab
  2019-08-09  5:42       ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 20:18 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Marco Felsch, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel

Em Mon, 6 May 2019 15:39:05 +0200
Jacopo Mondi <jacopo@jmondi.org> escreveu:

> Hi Marco,
>   thanks
> 
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Looks ok to me too.

> 
> On Mon, Apr 15, 2019 at 02:44:13PM +0200, Marco Felsch wrote:
> > The debug output for tvp5150_selmux() isn't really intuitive. Register
> > values are printed decimal formatted and the input/output driver states
> > are printed as enum. Even more the "normal" output enum mapps to zero so
> > a active output will printing output=0 and a inactive output=1.
> >
> > Change this by brinting the register values hex formatted and the states
> > as more readable string.
> >
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  drivers/media/i2c/tvp5150.c | 9 ++++++---
> >  1 file changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index c0ee08546643..13ee6d781efb 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -302,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
> >  		break;
> >  	}
> >
> > -	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
> > -			decoder->input, decoder->output,
> > -			input, opmode);
> > +	dev_dbg_lvl(sd->dev, 1, debug,
> > +		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
> > +		    decoder->input == 0 ? "aip1a" :
> > +		    decoder->input == 2 ? "aip1b" : "svideo",
> > +		    decoder->output == 0 ? "normal" : "black-frame-gen",
> > +		    input, opmode);
> >
> >  	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
> >  	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
> > --
> > 2.20.1
> >  



Thanks,
Mauro

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

* Re: [PATCH v6 00/13] TVP5150 new features
  2019-05-14 17:18   ` Mauro Carvalho Chehab
@ 2019-05-14 20:20     ` Mauro Carvalho Chehab
  2019-05-14 20:58       ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 20:20 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt, devicetree,
	laurent.pinchart, kernel, linux-media

Em Tue, 14 May 2019 14:18:24 -0300
Mauro Carvalho Chehab <mchehab@kernel.org> escreveu:

> Em Mon, 6 May 2019 07:47:13 +0200
> Marco Felsch <m.felsch@pengutronix.de> escreveu:
> 
> > Hi Mauro,
> > 
> > I know you are busy but can you have a look on it?  
> 
> You should really trust on the sub-maintainers for such kind of
> reviews :-)
> 
> I'll take a look today.

Done. Please notice that I didn't run any test here.

> 
> > 
> > Regards,
> >   Marco
> > 
> > On 19-04-15 14:44, Marco Felsch wrote:  
> > > Hi,
> > > 
> > > many thanks to Hans and Jacopo for the feedack :) this v6 address the
> > > comments both made on my v5 [1].
> > > 
> > > In short this is round fixes just some minor issues rather than major
> > > ones so the diff to the v5 is really small. The changed patches contain
> > > the changelog so I omit it here.
> > > 
> > > I've tested it on a custom hardware but I can't test the em28xx usb
> > > use-case since I haven't such a device. So other testers are welcome :)
> > > 
> > > Looking forward for your feedack,
> > > 
> > > 	Marco
> > > 
> > > [1] https://patchwork.kernel.org/cover/10886903/
> > > 
> > > Javier Martinez Canillas (1):
> > >   partial revert of "[media] tvp5150: add HW input connectors support"
> > > 
> > > Marco Felsch (11):
> > >   dt-bindings: connector: analog: add tv norms property
> > >   media: v4l2-fwnode: add v4l2_fwnode_connector
> > >   media: v4l2-fwnode: add initial connector parsing support
> > >   media: tvp5150: add input source selection of_graph support
> > >   media: dt-bindings: tvp5150: Add input port connectors DT bindings
> > >   media: tvp5150: add FORMAT_TRY support for get/set selection handlers
> > >   media: tvp5150: add s_power callback
> > >   media: dt-bindings: tvp5150: cleanup bindings stlye
> > >   media: dt-bindings: tvp5150: add optional tvnorms documentation
> > >   media: tvp5150: add support to limit tv norms on connector
> > >   media: tvp5150: make debug output more readable
> > > 
> > > Michael Tretter (1):
> > >   media: tvp5150: initialize subdev before parsing device tree
> > > 
> > >  .../display/connector/analog-tv-connector.txt |   4 +
> > >  .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
> > >  drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
> > >  drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
> > >  include/dt-bindings/media/tvnorms.h           |  56 ++
> > >  include/dt-bindings/media/tvp5150.h           |   2 -
> > >  include/media/v4l2-connector.h                |  30 +
> > >  include/media/v4l2-fwnode.h                   |  49 ++
> > >  8 files changed, 859 insertions(+), 190 deletions(-)
> > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > >  create mode 100644 include/media/v4l2-connector.h
> > > 
> > > -- 
> > > 2.20.1
> > > 
> > > 
> > >     
> >   
> 
> 
> 
> Thanks,
> Mauro



Thanks,
Mauro

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

* Re: [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree
  2019-04-15 12:44 ` [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
@ 2019-05-14 20:20   ` Mauro Carvalho Chehab
  2019-08-09  5:42     ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 20:20 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel,
	Michael Tretter

Em Mon, 15 Apr 2019 14:44:08 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> From: Michael Tretter <m.tretter@pengutronix.de>
> 
> There are several debug prints in the tvp5150_parse_dt() function, which
> do not print the prefix, because the v4l2_subdev is not initialized, yet.
> 
> Initialize the v4l2_subdev before parsing the device tree to fix the
> debug messages.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>

Looks ok to me.

> ---
>  drivers/media/i2c/tvp5150.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 9331609425bf..305a5e256b31 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -1973,6 +1973,9 @@ static int tvp5150_probe(struct i2c_client *c,
>  
>  	core->regmap = map;
>  	sd = &core->sd;
> +	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> +	sd->internal_ops = &tvp5150_internal_ops;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>  
>  	if (IS_ENABLED(CONFIG_OF) && np) {
>  		res = tvp5150_parse_dt(core, np);
> @@ -1985,10 +1988,6 @@ static int tvp5150_probe(struct i2c_client *c,
>  		core->mbus_type = V4L2_MBUS_BT656;
>  	}
>  
> -	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> -	sd->internal_ops = &tvp5150_internal_ops;
> -	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> -
>  	res = tvp5150_mc_init(core);
>  	if (res)
>  		goto err_cleanup_dt;



Thanks,
Mauro

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

* Re: [PATCH v6 00/13] TVP5150 new features
  2019-05-14 20:20     ` Mauro Carvalho Chehab
@ 2019-05-14 20:58       ` Marco Felsch
  2019-05-14 23:41         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-05-14 20:58 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt, devicetree,
	laurent.pinchart, kernel, linux-media

Hi Mauro,

On 19-05-14 17:20, Mauro Carvalho Chehab wrote:
> Em Tue, 14 May 2019 14:18:24 -0300
> Mauro Carvalho Chehab <mchehab@kernel.org> escreveu:
> 
> > Em Mon, 6 May 2019 07:47:13 +0200
> > Marco Felsch <m.felsch@pengutronix.de> escreveu:
> > 
> > > Hi Mauro,
> > > 
> > > I know you are busy but can you have a look on it?  
> > 
> > You should really trust on the sub-maintainers for such kind of
> > reviews :-)

I trust all of them and many thanks to Hans and Jacopo for the reviews
:) I will integrate them this week. The point is that you are the
maintainer and in that case the one who picks the patches.

> > 
> > I'll take a look today.
> 
> Done. Please notice that I didn't run any test here.

Thanks for that will integrate it too and prepare a v7.

Regards,
  Marco

> 
> > 
> > > 
> > > Regards,
> > >   Marco
> > > 
> > > On 19-04-15 14:44, Marco Felsch wrote:  
> > > > Hi,
> > > > 
> > > > many thanks to Hans and Jacopo for the feedack :) this v6 address the
> > > > comments both made on my v5 [1].
> > > > 
> > > > In short this is round fixes just some minor issues rather than major
> > > > ones so the diff to the v5 is really small. The changed patches contain
> > > > the changelog so I omit it here.
> > > > 
> > > > I've tested it on a custom hardware but I can't test the em28xx usb
> > > > use-case since I haven't such a device. So other testers are welcome :)
> > > > 
> > > > Looking forward for your feedack,
> > > > 
> > > > 	Marco
> > > > 
> > > > [1] https://patchwork.kernel.org/cover/10886903/
> > > > 
> > > > Javier Martinez Canillas (1):
> > > >   partial revert of "[media] tvp5150: add HW input connectors support"
> > > > 
> > > > Marco Felsch (11):
> > > >   dt-bindings: connector: analog: add tv norms property
> > > >   media: v4l2-fwnode: add v4l2_fwnode_connector
> > > >   media: v4l2-fwnode: add initial connector parsing support
> > > >   media: tvp5150: add input source selection of_graph support
> > > >   media: dt-bindings: tvp5150: Add input port connectors DT bindings
> > > >   media: tvp5150: add FORMAT_TRY support for get/set selection handlers
> > > >   media: tvp5150: add s_power callback
> > > >   media: dt-bindings: tvp5150: cleanup bindings stlye
> > > >   media: dt-bindings: tvp5150: add optional tvnorms documentation
> > > >   media: tvp5150: add support to limit tv norms on connector
> > > >   media: tvp5150: make debug output more readable
> > > > 
> > > > Michael Tretter (1):
> > > >   media: tvp5150: initialize subdev before parsing device tree
> > > > 
> > > >  .../display/connector/analog-tv-connector.txt |   4 +
> > > >  .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
> > > >  drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
> > > >  drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
> > > >  include/dt-bindings/media/tvnorms.h           |  56 ++
> > > >  include/dt-bindings/media/tvp5150.h           |   2 -
> > > >  include/media/v4l2-connector.h                |  30 +
> > > >  include/media/v4l2-fwnode.h                   |  49 ++
> > > >  8 files changed, 859 insertions(+), 190 deletions(-)
> > > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > > >  create mode 100644 include/media/v4l2-connector.h
> > > > 
> > > > -- 
> > > > 2.20.1
> > > > 
> > > > 
> > > >     
> > >   
> > 
> > 
> > 
> > Thanks,
> > Mauro
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 00/13] TVP5150 new features
  2019-05-14 20:58       ` Marco Felsch
@ 2019-05-14 23:41         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 70+ messages in thread
From: Mauro Carvalho Chehab @ 2019-05-14 23:41 UTC (permalink / raw)
  To: Marco Felsch
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt, devicetree,
	laurent.pinchart, kernel, linux-media

Em Tue, 14 May 2019 22:58:24 +0200
Marco Felsch <m.felsch@pengutronix.de> escreveu:

> Hi Mauro,
> 
> On 19-05-14 17:20, Mauro Carvalho Chehab wrote:
> > Em Tue, 14 May 2019 14:18:24 -0300
> > Mauro Carvalho Chehab <mchehab@kernel.org> escreveu:
> >   
> > > Em Mon, 6 May 2019 07:47:13 +0200
> > > Marco Felsch <m.felsch@pengutronix.de> escreveu:
> > >   
> > > > Hi Mauro,
> > > > 
> > > > I know you are busy but can you have a look on it?    
> > > 
> > > You should really trust on the sub-maintainers for such kind of
> > > reviews :-)  
> 
> I trust all of them and many thanks to Hans and Jacopo for the reviews
> :) I will integrate them this week. The point is that you are the
> maintainer and in that case the one who picks the patches.

Actually, Hans is the one that usually picks V4L2 patches after reviewing.
I pull from his tree and from other media maintainers.

> 
> > > 
> > > I'll take a look today.  
> > 
> > Done. Please notice that I didn't run any test here.  
> 
> Thanks for that will integrate it too and prepare a v7.

Thanks!
Mauro
> 
> Regards,
>   Marco
> 
> >   
> > >   
> > > > 
> > > > Regards,
> > > >   Marco
> > > > 
> > > > On 19-04-15 14:44, Marco Felsch wrote:    
> > > > > Hi,
> > > > > 
> > > > > many thanks to Hans and Jacopo for the feedack :) this v6 address the
> > > > > comments both made on my v5 [1].
> > > > > 
> > > > > In short this is round fixes just some minor issues rather than major
> > > > > ones so the diff to the v5 is really small. The changed patches contain
> > > > > the changelog so I omit it here.
> > > > > 
> > > > > I've tested it on a custom hardware but I can't test the em28xx usb
> > > > > use-case since I haven't such a device. So other testers are welcome :)
> > > > > 
> > > > > Looking forward for your feedack,
> > > > > 
> > > > > 	Marco
> > > > > 
> > > > > [1] https://patchwork.kernel.org/cover/10886903/
> > > > > 
> > > > > Javier Martinez Canillas (1):
> > > > >   partial revert of "[media] tvp5150: add HW input connectors support"
> > > > > 
> > > > > Marco Felsch (11):
> > > > >   dt-bindings: connector: analog: add tv norms property
> > > > >   media: v4l2-fwnode: add v4l2_fwnode_connector
> > > > >   media: v4l2-fwnode: add initial connector parsing support
> > > > >   media: tvp5150: add input source selection of_graph support
> > > > >   media: dt-bindings: tvp5150: Add input port connectors DT bindings
> > > > >   media: tvp5150: add FORMAT_TRY support for get/set selection handlers
> > > > >   media: tvp5150: add s_power callback
> > > > >   media: dt-bindings: tvp5150: cleanup bindings stlye
> > > > >   media: dt-bindings: tvp5150: add optional tvnorms documentation
> > > > >   media: tvp5150: add support to limit tv norms on connector
> > > > >   media: tvp5150: make debug output more readable
> > > > > 
> > > > > Michael Tretter (1):
> > > > >   media: tvp5150: initialize subdev before parsing device tree
> > > > > 
> > > > >  .../display/connector/analog-tv-connector.txt |   4 +
> > > > >  .../devicetree/bindings/media/i2c/tvp5150.txt | 125 +++-
> > > > >  drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
> > > > >  drivers/media/v4l2-core/v4l2-fwnode.c         | 111 +++
> > > > >  include/dt-bindings/media/tvnorms.h           |  56 ++
> > > > >  include/dt-bindings/media/tvp5150.h           |   2 -
> > > > >  include/media/v4l2-connector.h                |  30 +
> > > > >  include/media/v4l2-fwnode.h                   |  49 ++
> > > > >  8 files changed, 859 insertions(+), 190 deletions(-)
> > > > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > > > >  create mode 100644 include/media/v4l2-connector.h
> > > > > 
> > > > > -- 
> > > > > 2.20.1
> > > > > 
> > > > > 
> > > > >       
> > > >     
> > > 
> > > 
> > > 
> > > Thanks,
> > > Mauro  
> > 
> > 
> > 
> > Thanks,
> > Mauro
> >   
> 



Thanks,
Mauro

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
  2019-05-06 10:01   ` Hans Verkuil
@ 2019-05-16 16:27   ` Laurent Pinchart
  2019-08-09  5:58     ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 16:27 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Marco,

Thank you for the patch.

On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> Some connectors no matter if in- or output supports only a limited
> range of tv norms. It doesn't matter if the hardware behind that
> connector supports more than the listed formats since the users are
> restriced by a label e.g. to plug only a camera into this connector
> which uses the PAL format.
> 
> This patch adds the capability to describe such limitation within the
> firmware. There are no format restrictions if the property isn't
> present, so it's completely backward compatible.

Why is this needed ? It's not really a hardware property, is it ? What's
the use case ?

> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v6:
> - tvnorms.h: use tabs instead of spaces
> - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  .../display/connector/analog-tv-connector.txt |  4 ++
>  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
>  2 files changed, 60 insertions(+)
>  create mode 100644 include/dt-bindings/media/tvnorms.h
> 
> diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> index 0c0970c210ab..346f8937a0b7 100644
> --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> @@ -6,6 +6,9 @@ Required properties:
>  
>  Optional properties:
>  - label: a symbolic name for the connector
> +- tvnorms: limit the supported tv norms on a connector to the given ones else
> +           all tv norms are allowed. Possible video standards are defined in
> +           include/dt-bindings/media/tvnorms.h.
>  
>  Required nodes:
>  - Video port for TV input
> @@ -16,6 +19,7 @@ Example
>  tv: connector {
>  	compatible = "composite-video-connector";
>  	label = "tv";
> +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
>  
>  	port {
>  		tv_connector_in: endpoint {
> diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> new file mode 100644
> index 000000000000..058ab8414145
> --- /dev/null
> +++ b/include/dt-bindings/media/tvnorms.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> +/*
> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> + */
> +
> +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> +
> +/* one bit for each */
> +#define TVNORM_PAL_B		0x00000001
> +#define TVNORM_PAL_B1		0x00000002
> +#define TVNORM_PAL_G		0x00000004
> +#define TVNORM_PAL_H		0x00000008
> +#define TVNORM_PAL_I		0x00000010
> +#define TVNORM_PAL_D		0x00000020
> +#define TVNORM_PAL_D1		0x00000040
> +#define TVNORM_PAL_K		0x00000080
> +
> +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> +				 TVNORM_PAL_B1 | \
> +				 TVNORM_PAL_G  | \
> +				 TVNORM_PAL_H  | \
> +				 TVNORM_PAL_I  | \
> +				 TVNORM_PAL_D  | \
> +				 TVNORM_PAL_D1 | \
> +				 TVNORM_PAL_K)
> +
> +#define TVNORM_PAL_M		0x00000100
> +#define TVNORM_PAL_N		0x00000200
> +#define TVNORM_PAL_Nc		0x00000400
> +#define TVNORM_PAL_60		0x00000800
> +
> +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> +#define TVNORM_NTSC_443		0x00004000
> +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> +
> +#define TVNORM_SECAM_B		0x00010000
> +#define TVNORM_SECAM_D		0x00020000
> +#define TVNORM_SECAM_G		0x00040000
> +#define TVNORM_SECAM_H		0x00080000
> +#define TVNORM_SECAM_K		0x00100000
> +#define TVNORM_SECAM_K1		0x00200000
> +#define TVNORM_SECAM_L		0x00400000
> +#define TVNORM_SECAM_LC		0x00800000
> +
> +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> +				 TVNORM_SECAM_D  | \
> +				 TVNORM_SECAM_G  | \
> +				 TVNORM_SECAM_H  | \
> +				 TVNORM_SECAM_K  | \
> +				 TVNORM_SECAM_K1 | \
> +				 TVNORM_SECAM_L  | \
> +				 TVNORM_SECAM_LC)
> +
> +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-04-15 12:44 ` [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
  2019-05-06  9:50   ` Hans Verkuil
@ 2019-05-16 16:36   ` Laurent Pinchart
  2019-08-09  7:55     ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 16:36 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Marco,

Thank you for the patch.

On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> Currently every driver needs to parse the connector endpoints by it self.

s/it self/itself/

> This is the initial work to make this generic. The generic connector has
> some common fields and some connector specific parts. The generic one
> includes:
>   - type
>   - label
>   - remote_port (the port where the connector is connected to)
>   - remote_id   (the endpoint where the connector is connected to)

This assumes a single connection between a connector and a remote port,
and a single port on the connector side. Is this guaranteed ? For the
mini-DIN-4 connectors (often used for S-Video) for instance, I recall
from the extensive discussions we had in the past that they should be
modeled with two pins, one for the Y component and one for C components.
The rationale for this is to support systems where such a connector
could be used to carry S-Video, but also two composite video signals
(usually through an external adapter from 2 RCA female connectors to one
S-Video male connector) that would be routed to two separate video
decoders (or two different inputs of the same video decoder). Other
topologies may be possible too.

> The specific fields are within a union, since only one of them can be
> available at the time. Since this is the initial support the patch adds
> only the analog-connector specific ones.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v6:
> - fix some spelling and style issues
> - rm unnecessary comments
> - drop vga and dvi connector
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
>  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 include/media/v4l2-connector.h
> 
> diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> new file mode 100644
> index 000000000000..3a951c54f50e
> --- /dev/null
> +++ b/include/media/v4l2-connector.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * v4l2-connector.h
> + *
> + * V4L2 connector types.
> + *
> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> + */
> +
> +#ifndef V4L2_CONNECTOR_H
> +#define V4L2_CONNECTOR_H
> +
> +#define V4L2_CONNECTOR_MAX_LABEL 41

Hans pointed out this was a weird number. Should you turn the label
field into a pointer to make this more generic (with a
v4l2_fwnode_connector_cleanup() function then) ?

> +
> +/**
> + * enum v4l2_connector_type - connector type
> + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> + * @V4L2_CON_COMPOSITE: analog composite connector
> + * @V4L2_CON_SVIDEO:    analog svideo connector
> + * @V4L2_CON_HDMI:      digital hdmi connector
> + */
> +enum v4l2_connector_type {
> +	V4L2_CON_UNKNOWN,
> +	V4L2_CON_COMPOSITE,
> +	V4L2_CON_SVIDEO,
> +	V4L2_CON_HDMI,
> +};
> +
> +#endif /* V4L2_CONNECTOR_H */
> +
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 6c07825e18b9..f4df1b95c5ef 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -22,6 +22,7 @@
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> +#include <media/v4l2-connector.h>
>  #include <media/v4l2-mediabus.h>
>  #include <media/v4l2-subdev.h>
>  
> @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
>  	unsigned int remote_port;
>  };
>  
> +/**
> + * struct v4l2_fwnode_connector_analog - analog connector data structure
> + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> + *                     if no restrictions are specified.
> + */
> +struct v4l2_fwnode_connector_analog {
> +	v4l2_std_id supported_tvnorms;
> +};
> +
> +/**
> + * struct v4l2_fwnode_connector - the connector data structure
> + * @remote_port: identifier of the remote endpoint port the connector connects
> + *		 to
> + * @remote_id: identifier of the remote endpoint the connector connects to
> + * @label: connetor label
> + * @type: connector type
> + * @connector: connector configuration
> + * @connector.analog: analog connector configuration
> + *                    &struct v4l2_fwnode_connector_analog
> + */
> +struct v4l2_fwnode_connector {
> +	unsigned int remote_port;
> +	unsigned int remote_id;
> +	char label[V4L2_CONNECTOR_MAX_LABEL];
> +	enum v4l2_connector_type type;
> +
> +	union {
> +		struct v4l2_fwnode_connector_analog analog;
> +		/* future connectors */
> +	} connector;
> +};
> +
>  /**
>   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
>   * @fwnode: pointer to the endpoint's fwnode handle

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-05-14 18:20     ` Mauro Carvalho Chehab
@ 2019-05-16 16:51       ` Laurent Pinchart
  2019-08-09 12:16         ` Marco Felsch
  2019-08-09  8:59       ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 16:51 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Hans Verkuil, Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel,
	Jacopo Mondi

Hello Marco,

Thank you for the patch.

On Tue, May 14, 2019 at 03:20:04PM -0300, Mauro Carvalho Chehab wrote:
> Em Mon, 6 May 2019 12:10:41 +0200 Hans Verkuil escreveu:
> > On 4/15/19 2:44 PM, Marco Felsch wrote:
> > > The patch adds the initial connector parsing code, so we can move from a
> > > driver specific parsing code to a generic one. Currently only the
> > > generic fields and the analog-connector specific fields are parsed. Parsing
> > > the other connector specific fields can be added by a simple callbacks.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v6:
> > > - use 'unsigned int' count var
> > > - fix comment and style issues
> > > - place '/* fall through */' to correct places
> > > - fix error handling and cleanup by releasing fwnode
> > > - drop vga and dvi parsing support as those connectors are rarely used
> > >   these days
> > > 
> > > v5:
> > > - s/strlcpy/strscpy/
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> > >  include/media/v4l2-fwnode.h           |  16 ++++
> > >  2 files changed, 127 insertions(+)
> > > 
> > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > index 20571846e636..f1cca95c8fef 100644
> > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > >  }
> > >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > >  
> > > +static const struct v4l2_fwnode_connector_conv {
> > > +	enum v4l2_connector_type type;
> > > +	const char *name;

Maybe compatible instead of name ?

> > > +} connectors[] = {
> > > +	{
> > > +		.type = V4L2_CON_COMPOSITE,
> > > +		.name = "composite-video-connector",
> > > +	}, {
> > > +		.type = V4L2_CON_SVIDEO,
> > > +		.name = "svideo-connector",
> > > +	}, {
> > > +		.type = V4L2_CON_HDMI,
> > > +		.name = "hdmi-connector",
> > > +	},
> > > +};
> > > +
> > > +static enum v4l2_connector_type
> > > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > > +{
> > > +	unsigned int i;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > > +		if (!strcmp(con_str, connectors[i].name))
> > > +			return connectors[i].type;
> > > +
> > > +	/* no valid connector found */

The usual comment style in this file is to start with a capital letter
and end sentences with a period. I would however drop this comment, it's
not very useful. The other comments should be updated accordingly.

> > > +	return V4L2_CON_UNKNOWN;
> > > +}
> > > +
> > > +static int
> > > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > > +				   struct v4l2_fwnode_connector *vc)
> > > +{
> > > +	u32 tvnorms;
> > > +	int ret;
> > > +
> > > +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > > +
> > > +	/* tvnorms is optional */
> > > +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > > +
> > > +	return 0;
> > > +}
> > > +

Please document all exported functions with kerneldoc.

> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > > +				struct v4l2_fwnode_connector *connector)
> > > +{
> > > +	struct fwnode_handle *fwnode;
> > > +	struct fwnode_endpoint __ep;
> > > +	const char *c_type_str, *label;
> > > +	int ret;
> > > +
> > > +	memset(connector, 0, sizeof(*connector));
> > > +
> > > +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);

I would rename the argument __fwnode to fwnode, and rename the fwnode
variable to remote (or similar) to make this clearer.

> > > +	if (!fwnode)
> > > +		return -EINVAL;

Is EINVAL the right error here ? Wouldn't it be useful for the caller to
differentiate between unconnected connector nodes and invalid ones ?

> > > +
> > > +	/* parse all common properties first */
> > > +	/* connector-type is stored within the compatible string */
> > > +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);

Prefixing or postfixing names with types is usually frowned upon. You
could rename this to type_name for instance.

> > > +	if (ret) {
> > > +		fwnode_handle_put(fwnode);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > > +
> > > +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > > +	connector->remote_port = __ep.port;
> > > +	connector->remote_id = __ep.id;
> > > +
> > > +	ret = fwnode_property_read_string(fwnode, "label", &label);
> > > +	if (!ret) {
> > > +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > > +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > > +	} else {
> > > +		/*
> > > +		 * labels are optional, if none is given create one:
> > > +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > > +		 */
> > > +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > > +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > > +			 connector->remote_id);

Should we really try to create labels when none is available ? If so
this needs much more careful thoughts, we need to think about what the
label will be used for, and create a good naming scheme accordingly. If
the label will be displayed to the end-user I don't think the above name
would be very useful, it would be best to leave it empty and let
applications create a name based on the connector type and other
information they have at their disposal.

> > > +	}
> > > +
> > > +	/* now parse the connector specific properties */
> > > +	switch (connector->type) {
> > > +	case V4L2_CON_COMPOSITE:
> > > +		/* fall through */

I don't think you need a fall-through comment when the two cases are
adjacent with no line in-between.

> > > +	case V4L2_CON_SVIDEO:
> > > +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > > +		break;
> > > +	case V4L2_CON_HDMI:
> > > +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> > > +			c_type_str);  
> > 
> > Why warn? Just drop this.
> 
> good point. I would prefer to have some warning here, in order to warn a
> developer that might be using it that this part of the code would require 
> some change.
> 
> perhaps pr_warn_once()?
>
> > > +		ret = 0;
> > > +		break;

If it's not supported we should warn and return an error. Otherwise we
should be silent and return success. Combining a warning with success
isn't a good idea, this is either a normal case or an error, not both.

> > > +	case V4L2_CON_UNKNOWN:
> > > +		/* fall through */
> > > +	default:
> > > +		pr_err("Unknown connector type\n");
> > > +		ret = -EINVAL;
> > > +	};
> > > +
> > > +	fwnode_handle_put(fwnode);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > > +
> > >  static int
> > >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > >  					  struct v4l2_async_notifier *notifier,
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index f4df1b95c5ef..e072f2915ddb 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > >   */
> > >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > >  

And I see here that the function is documented. One more reason to move
kerneldoc to the .c files...

> > > +/**
> > > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > > + *          connected to

This is very unclear, I would interpret that as the remote endpoint, not
the local endpoint. Could you please try to clarify the documentation ?

> > > + * @connector: pointer to the V4L2 fwnode connector data structure
> > > + *
> > > + * Fill the connector data structure with the connector type, label and the
> > > + * endpoint id and port where the connector belongs to. If no label is present
> > > + * a unique one will be created. Labels with more than 40 characters are cut.
> > > + *
> > > + * Return: %0 on success or a negative error code on failure:
> > > + *	   %-EINVAL on parsing failure
> > > + */
> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > > +				struct v4l2_fwnode_connector *connector);
> > > +
> > >  /**
> > >   * typedef parse_endpoint_func - Driver's callback function to be called on
> > >   *	each V4L2 fwnode endpoint.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-05-14 18:25   ` Mauro Carvalho Chehab
@ 2019-05-16 18:03     ` Laurent Pinchart
  2019-08-13  8:54       ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 18:03 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel

Hello Marco,

Thank you for the patch.

On Tue, May 14, 2019 at 03:25:45PM -0300, Mauro Carvalho Chehab wrote:
> Em Mon, 15 Apr 2019 14:44:05 +0200 Marco Felsch escreveu:
> 
> > This patch adds the of_graph support to describe the tvp connections.
> > Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> > of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> > connector must be conneted to port@0/endpoint@1, look at the Documentation

According to [2], it must be connected to port port@0 and port@1, not
just port@0.

> > for more information. Since the TVP5150 is a converter the device-tree
> > must contain at least 1-input and 1-output port. The mc-connectors and
> > mc-links are only created if the device-tree contains the corresponding
> > connector nodes. If more than one connector is available the
> > media_entity_operations.link_setup() callback ensures that only one
> > connector is active.
> > 
> > [1] https://www.spinics.net/lists/linux-media/msg138545.html
> > [2] https://www.spinics.net/lists/linux-media/msg138546.html
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > Changelog:
> > 
> > [1] https://patchwork.kernel.org/cover/10794703/
> > [2] https://patchwork.kernel.org/cover/10786553/
> > 
> > v6:
> > - fix misspelled comments
> > - use 'unsigned int' where it's possible
> > - cleanup ifdef part-2:
> >   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
> >     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> > - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
> >   internal function do this.
> > - tvp5150_add_of_connectors: call within probe() to make it cleaner
> > - tvp5150_parse_dt: move local loop vars within the loop.
> > 
> > v5:
> > - Fixing build deps:
> >   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
> >   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
> >     includes. This leads into to complex deps for futher development.
> >   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
> >   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
> >   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> > 
> > - Simplify link_setup routine:
> >   - use generic connector parsing since both series [1,2] are squashed into
> >     one
> >   - struct tvp5150: drop pads_state and modify_second_link property
> >     due to link_setup() rework.
> >   - tvp5150_link_setup: add more comments
> >   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
> >     link directly within the driver instead of a recursive media-framework
> >     call (__media_entity_setup_link). This improves the readability and
> >     shrinks the driver code.
> >   - tvp5150_link_setup: disable all active links in case user switches
> >     connectors without disable it first.
> >   - tvp5150_registered: simplify default link enable path due to link_setup()
> >     rework.
> > 
> > - General cleanups
> >   - tvp5150_parse_dt: drop unecessary test
> >   - tvp5150_parse_dt: add err message due to misconfiguration
> >   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
> >   - s/dev_dbg/dev_dbg_lvl
> > 
> > v4:
> >  - rebase on top of media_tree/master, fix merge conflict due to commit
> >    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
> >    to zero")
> > 
> > v3:
> > - probe(): s/err/err_free_v4l2_ctrls
> > - drop MC dependency for tvp5150_pads
> > 
> > v2:
> > - adapt commit message
> > - unify ifdef switches
> > - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> > - mc: use 2-input and 1-output pad
> > - mc: link svideo connector to both input pads
> > - mc: enable/disable svideo links in one go
> > - mc: change link_setup() behaviour, switch the input src don't require a
> >       explicite disable before.
> > - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> > - mc: enable link to the first available connector and set the
> >       corresponding tvp5150 input src per default during registered()
> > - mc/of: factor out oftree connector allocation
> > - of: drop svideo dt port
> > - of: move svideo connector to port@0/endpoint@1
> > - of: require at least 1-in and 1-out endpoint
> > 
> >  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
> >  1 file changed, 370 insertions(+), 39 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index 89da921c8886..4e3228b2ccbc 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
> >  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
> >  
> >  enum tvp5150_pads {
> > -	TVP5150_PAD_IF_INPUT,
> > +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> > +	TVP5150_PAD_AIP1B,
> >  	TVP5150_PAD_VID_OUT,
> >  	TVP5150_NUM_PADS
> >  };
> >  
> > +struct tvp5150_connector {
> > +	struct v4l2_fwnode_connector base;
> > +	struct media_entity ent;
> > +	struct media_pad pad;
> > +};
> > +
> >  struct tvp5150 {
> >  	struct v4l2_subdev sd;
> > -#ifdef CONFIG_MEDIA_CONTROLLER
> > +	/* additional endpoint for the svideo connector */

Could you please capitalize the first word of all comments to match the
driver style ?

> > +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];

As the endpoints are only used at probe time, I would declare this as a
local variable in the probe function and pass it to both
tvp5150_add_of_connectors() and tvp5150_parse_dt(). If you order the
calls correctly it should simplify the probe error handling.

> > +	unsigned int endpoints_num;
> > +
> > +	/* media-ctl properties */

media-ctl makes me think about the userspace application, maybe "Media
controller properties" ?

> >  	struct media_pad pads[TVP5150_NUM_PADS];
> > -#endif
> > +	struct tvp5150_connector *connectors;
> > +	int connectors_num;

unsigned int ?

> > +
> >  	struct v4l2_ctrl_handler hdl;
> >  	struct v4l2_rect rect;
> >  	struct regmap *regmap;
> > @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> >  	return 0;
> >  }
> >  
> > +/****************************************************************************
> > + *			Media entity ops
> > + ****************************************************************************/
> > +#if defined(CONFIG_MEDIA_CONTROLLER)

Should we depend on CONFIG_MEDIA_CONTROLLER instead, especially since
you remove the similar conditional in the struct tvp5150 definition and
in the probe function ?

> > +static int tvp5150_set_link(struct media_pad *connector_pad,
> > +			    struct media_pad *tvp5150_pad, u32 flags)
> > +{
> > +	struct media_link *link;
> > +
> > +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> > +	if (!link)
> > +		return -EINVAL;
> > +
> > +	link->flags = flags;
> > +	link->reverse->flags = link->flags;
> > +
> > +	return 0;
> > +}
> > +
> > +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> > +{
> > +	struct media_pad *connector_pad;
> > +	unsigned int i;
> > +	int err;
> > +
> > +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> > +		if (!connector_pad)
> > +			continue;
> > +
> > +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> > +		if (err)
> > +			return err;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> > +			     u32 config);
> > +
> > +static int tvp5150_link_setup(struct media_entity *entity,
> > +			      const struct media_pad *tvp5150_pad,
> > +			      const struct media_pad *remote, u32 flags)
> > +{
> > +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	struct media_pad *other_tvp5150_pad =
> > +		&decoder->pads[tvp5150_pad->index ^ 1];
> > +	bool is_svideo = false;
> > +	unsigned int i;
> > +	int err;
> > +
> > +	/*
> > +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> > +	 * Enabling or disabling the source pad link has no effect.
> > +	 */
> > +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> > +		return 0;
> > +
> > +	/* Check if the svideo connector should be enabled */
> > +	for (i = 0; i < decoder->connectors_num; i++) {
> > +		if (remote->entity == &decoder->connectors[i].ent) {
> 
> > +			is_svideo =
> > +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> 
> Nitpick:
> 
> I would actually prefer to keep this on a single line. Ok, it will violate
> the 80-columns, but it would be better than the above (IMHO).
> 
> > +			break;
> > +		}
> > +	}
> > +
> > +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> > +		    remote->entity->name, remote->index,
> > +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> > +		    flags & MEDIA_LNK_FL_ENABLED);
> > +	if (is_svideo)
> > +		dev_dbg_lvl(sd->dev, 1, debug,
> > +			    "link setup '%s':%d->'%s':%d[%d]",
> > +			    remote->entity->name, remote->index,
> > +			    other_tvp5150_pad->entity->name,
> > +			    other_tvp5150_pad->index,
> > +			    flags & MEDIA_LNK_FL_ENABLED);
> > +
> > +	/*
> > +	 * The TVP5150 has an internal mux which allows the following setup:
> > +	 *
> > +	 * comp-connector1  --\
> > +	 *		       |---> AIP1A
> > +	 *		      /
> > +	 * svideo-connector -|
> > +	 *		      \
> > +	 *		       |---> AIP1B
> > +	 * comp-connector2  --/
> > +	 *
> > +	 * We can't rely on user space that the current connector gets disabled
> > +	 * first before enabling the new connector. Disable all active
> > +	 * connector links to be on the safe side.
> > +	 */
> > +	err = tvp5150_disable_all_input_links(decoder);
> > +	if (err)
> > +		return err;
> > +
> > +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> > +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> > +			  TVP5150_BLACK_SCREEN, 0);
> > +
> > +	if (flags & MEDIA_LNK_FL_ENABLED) {
> > +		/*
> > +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > +		 * Both links must be enabled in one-shot regardless which link
> > +		 * the user requests.
> > +		 */

This is a very grey area, I don't think the MC API explicitly allows
doing this. As changing links during streaming is disallowed, wouldn't
it be easier to handle the routing configuration at stream start ? You
wouldn't have to deal with this issue then, you could just return an
error if only one link is enabled. Furthermore, it would allow
supporting a configuration where a composite signal is connected to the
Y pin of the mini-DIN connector.

> > +		if (is_svideo) {
> > +			err = tvp5150_set_link((struct media_pad *) remote,
> > +					       other_tvp5150_pad, flags);
> > +			if (err)
> > +				return err;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct media_entity_operations tvp5150_sd_media_ops = {
> > +	.link_setup = tvp5150_link_setup,
> > +};
> > +#endif
> >  /****************************************************************************
> >  			I2C Command
> >   ****************************************************************************/
> > @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> >  	return 0;
> >  }
> >  
> > +static int tvp5150_registered(struct v4l2_subdev *sd)
> > +{
> > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	/*
> > +	 * Setup connector pads and links. Enable the link to the first
> > +	 * available connector per default.
> > +	 */
> > +	for (i = 0; i < decoder->connectors_num; i++) {
> > +		struct media_entity *con = &decoder->connectors[i].ent;
> > +		struct media_pad *pad = &decoder->connectors[i].pad;
> > +		unsigned int port = decoder->connectors[i].base.remote_port;
> > +		bool is_svideo =
> > +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;

The flags passed to media_create_pad_link() are unsigned.

> > +
> > +		pad->flags = MEDIA_PAD_FL_SOURCE;
> > +		ret = media_entity_pads_init(con, 1, pad);
> > +		if (ret < 0)
> > +			return ret;
> > +
> > +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> > +		if (ret < 0)
> > +			return ret;
> > +
> > +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> > +		if (ret < 0) {
> > +			media_device_unregister_entity(con);
> > +			return ret;
> > +		}

Will the other registered media entities be unregistered correctly ?

> > +
> > +		if (is_svideo) {
> > +			/* svideo links to both aip1a and aip1b */
> > +			ret = media_create_pad_link(con, 0, &sd->entity,
> > +						    port + 1, flags);

Does the TVP5150 support both connecting Y to AIP1A and C to AIP1B, and
Y to AIP1B and C to AIP1A ? If so the port + 1 won't always work.

> > +			if (ret < 0) {
> > +				media_device_unregister_entity(con);
> > +				return ret;
> > +			}
> > +		}
> > +
> > +		/* enable default input */
> > +		if (flags == MEDIA_LNK_FL_ENABLED) {
> > +			decoder->input =
> > +				is_svideo ? TVP5150_SVIDEO :
> > +				port == 0 ? TVP5150_COMPOSITE0 :
> > +				TVP5150_COMPOSITE1;
> > +
> > +			tvp5150_selmux(sd);
> > +		}

You could move this after the loop and operation on
decoder->connectors[0]. Hopefully you could then use if's instead of
nested ? : operators, as the above isn't very readable.

> > +	}
> > +#endif
> > +	return 0;
> > +}
> > +
> > +

One blank line is enough.

> >  /* ----------------------------------------------------------------------- */
> >  
> >  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> > @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
> >  	.pad = &tvp5150_pad_ops,
> >  };
> >  
> > +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> > +	.registered = tvp5150_registered,
> > +};
> > +
> >  /****************************************************************************
> >  			I2C Client & Driver
> >   ****************************************************************************/
> > @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
> >  	return 0;
> >  }
> >  
> > -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> >  {
> > -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> > -	struct device_node *ep;
> > -	unsigned int flags;
> > -	int ret = 0;
> > +	struct device *dev = decoder->sd.dev;

You use dev in a singla location, I think you could use decoder->sd.dev
directly.

> > +	struct tvp5150_connector *connectors;
> > +	unsigned int connectors_num = decoder->connectors_num;
> > +	int i, ret;

i is never negative, you can make it an unsiged int.

> >  
> > -	ep = of_graph_get_next_endpoint(np, NULL);
> > -	if (!ep)
> > -		return -EINVAL;
> > +	/*
> > +	 * Only add of_connectors if device really is a OF device since
> > +	 * the driver is used by usb devices e.g. em28xx and embedded
> > +	 * devices.
> > +	 */
> > +	if (!decoder->connectors_num)

Maybe if (!connectors_num) ?

> > +		return 0;
> >  
> > -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> > -	if (ret)
> > -		goto err;
> > +	/* Allocate and initialize all available input connectors */
> > +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> > +				  GFP_KERNEL);
> > +	if (!connectors)
> > +		return -ENOMEM;
> > +
> > +	for (i = 0; i < connectors_num; i++) {
> > +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> > +
> > +		ret = v4l2_fwnode_parse_connector(
> > +				   of_fwnode_handle(decoder->endpoints[i]), c);

I think you should handle errors here.

> > +
> > +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> > +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> > +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> > +		connectors[i].ent.name = c->label;

I don't think using the label as the entity name is a good idea, as we
require entity names to be unique, and labels offer no such guarantee.

> > +	}
> > +
> > +	decoder->connectors = connectors;
> > +
> > +	return 0;
> > +}
> > +
> > +static int tvp5150_mc_init(struct tvp5150 *decoder)
> > +{
> > +	struct v4l2_subdev *sd = &decoder->sd;
> > +	unsigned int i;
> > +
> > +	sd->entity.ops = &tvp5150_sd_media_ops;
> > +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > +
> > +	/* Initialize all TVP5150 pads */
> > +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> > +		if (i < TVP5150_NUM_PADS - 1) {
> > +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > +		} else {
> > +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> > +		}
> > +	}

You can simplify this to

	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
	}

	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
	decoder->pads[i].sig_type = PAD_SIGNAL_DV;

> > +
> > +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> > +				      decoder->pads);
> > +}
> > +
> > +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> > +
> > +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > +{
> > +	return 0;
> > +}
> >  
> > -	flags = bus_cfg.bus.parallel.flags;
> > +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> > +{
> > +	return 0;
> > +}
> > +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
> >  
> > -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > +{
> > +	struct device *dev = decoder->sd.dev;
> > +	struct device_node *ep_np;
> > +	unsigned int i = 0, in = 0;

Let's rename in to num_inputs or num_connectors.

> > +	int ret;
> > +	bool found = false;
> > +
> > +	/* at least 1 output and 1 input */
> > +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> > +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> > +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
> >  		ret = -EINVAL;
> >  		goto err;
> >  	}
> >  
> > -	decoder->mbus_type = bus_cfg.bus_type;
> > +	for_each_endpoint_of_node(np, ep_np) {
> > +		struct v4l2_fwnode_endpoint bus_cfg = {
> > +			.bus_type = V4L2_MBUS_UNKNOWN
> > +		};
> > +		struct v4l2_fwnode_connector c;
> > +		struct of_endpoint ep;
> > +		unsigned int flags;
> > +
> > +		of_graph_parse_endpoint(ep_np, &ep);
> > +		switch (ep.port) {
> > +		case TVP5150_PAD_AIP1A:
> > +			/* fall through */

I don't think you need this comment.

> > +		case TVP5150_PAD_AIP1B:
> > +			ret = v4l2_fwnode_parse_connector(
> > +						   of_fwnode_handle(ep_np), &c);

You use of_fwnode_handle(ep_np) twice, you could move it outside of the
switch () to keep lines shorter.

> > +			if (c.type != V4L2_CON_COMPOSITE &&
> > +			    c.type != V4L2_CON_SVIDEO) {
> > +				dev_err(dev,
> > +					"Invalid endpoint %d on port %d\n",

The correct format specifier for unsigned int is %u.

Should the error message be more explicit ? "Invalid connector type for
port@%u/endpoint@%u" ?


> > +					c.remote_id, c.remote_port);
> > +				ret = -EINVAL;
> > +				goto err;

If you break out of the loop you need an of_node_put(ep_np).
Alternatively, you could store ep_np in the endpoints array right before
of_graph_parse_endpoint() and call of_node_put() right after
of_graph_parse_endpoint().

> > +			}
> > +			in++;
> > +			break;
> > +		case TVP5150_PAD_VID_OUT:
> > +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> > +							 &bus_cfg);
> > +			if (ret)
> > +				goto err;
> > +
> > +			flags = bus_cfg.bus.parallel.flags;
> > +
> > +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > +				ret = -EINVAL;
> > +				goto err;
> > +			}
> > +
> > +			decoder->mbus_type = bus_cfg.bus_type;
> > +			break;
> > +		default:
> > +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",

%u here too.

> > +				ep.port, ep.local_node);
> > +			ret = -EINVAL;
> > +			goto err;
> > +		}
> > +
> > +		of_node_get(ep_np);
> > +		decoder->endpoints[i] = ep_np;
> > +		i++;
> > +
> > +		found = true;
> > +	}
> >  
> > +	decoder->connectors_num = in;
> > +	return found ? 0 : -ENODEV;
> >  err:
> > -	of_node_put(ep);
> >  	return ret;

You can remove the err label and return ret directly.

> >  }
> >  
> > +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> > +		of_node_put(decoder->endpoints[i]);
> > +}
> > +
> >  static const char * const tvp5150_test_patterns[2] = {
> >  	"Disabled",
> >  	"Black screen"
> > @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
> >  		res = tvp5150_parse_dt(core, np);
> >  		if (res) {
> >  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> > -			return res;
> > +			goto err_cleanup_dt;
> >  		}
> >  	} else {
> >  		/* Default to BT.656 embedded sync */
> > @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
> >  	}
> >  
> >  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > +	sd->internal_ops = &tvp5150_internal_ops;
> >  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> >  
> > -#if defined(CONFIG_MEDIA_CONTROLLER)
> > -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> > -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> > -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> > -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> > -
> > -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > -
> > -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> > -	if (res < 0)
> > -		return res;
> > +	res = tvp5150_mc_init(core);
> > +	if (res)
> > +		goto err_cleanup_dt;
> >  
> > -#endif
> > +	res = tvp5150_add_of_connectors(core);
> > +	if (res)
> > +		goto err_cleanup_dt;
> >  
> >  	res = tvp5150_detect_version(core);
> >  	if (res < 0)
> > -		return res;
> > +		goto err_cleanup_dt;
> >  
> >  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
> >  	sd->ctrl_handler = &core->hdl;
> >  	if (core->hdl.error) {
> >  		res = core->hdl.error;
> > -		goto err;
> > +		goto err_free_v4l2_ctrls;
> >  	}
> >  
> >  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> > @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
> >  						tvp5150_isr, IRQF_TRIGGER_HIGH |
> >  						IRQF_ONESHOT, "tvp5150", core);
> >  		if (res)
> > -			goto err;
> > +			goto err_free_v4l2_ctrls;
> >  	}
> >  
> >  	res = v4l2_async_register_subdev(sd);
> >  	if (res < 0)
> > -		goto err;
> > +		goto err_free_v4l2_ctrls;
> >  
> >  	if (debug > 1)
> >  		tvp5150_log_status(sd);
> > +
> >  	return 0;
> >  
> > -err:
> > +err_free_v4l2_ctrls:
> >  	v4l2_ctrl_handler_free(&core->hdl);
> > +err_cleanup_dt:
> > +	if (IS_ENABLED(CONFIG_OF) && np)
> > +		tvp5150_dt_cleanup(core);
> > +
> >  	return res;
> >  }
> >  

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings
  2019-04-15 12:44 ` [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
  2019-05-14 18:27   ` Mauro Carvalho Chehab
@ 2019-05-16 18:05   ` Laurent Pinchart
  2019-08-13  8:56     ` Marco Felsch
  1 sibling, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 18:05 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Marco,

Thank you for the patch.

On Mon, Apr 15, 2019 at 02:44:06PM +0200, Marco Felsch wrote:
> The TVP5150/1 decoders support different video input sources to their
> AIP1A/B pins.
> 
> Possible configurations are as follows:
>   - Analog Composite signal connected to AIP1A.
>   - Analog Composite signal connected to AIP1B.
>   - Analog S-Video Y (luminance) and C (chrominance)
>     signals connected to AIP1A and AIP1B respectively.
> 
> This patch extends the device tree bindings documentation to describe
> how the input connectors for these devices should be defined in a DT.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> Changelog:
> 
> v3:
> - remove examples for one and two inputs
> - replace space by tabs
> 
> v2:
> - adapt port layout in accordance with
>   https://www.spinics.net/lists/linux-media/msg138546.html with the
>   svideo-connector deviation (use only one endpoint)

As far as I understand the above link, you need two endpoints.

tvp-5150 port@0 (AIP1A)
	endpoint@0 -----------> Comp0-Con  port
	endpoint@1 -----+-----> Svideo-Con port
tvp-5150 port@1	(AIP1B) |
	endpoint@1 -----+
	endpoint@0 -----------> Comp1-Con  port
tvp-5150 port@2
	endpoint (video bitstream output at YOUT[0-7] parallel bus)

The configuration below isn't accepted.

>  .../devicetree/bindings/media/i2c/tvp5150.txt | 92 +++++++++++++++++--
>  1 file changed, 85 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> index 8c0fc1a26bf0..bdd273d8b44d 100644
> --- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> @@ -12,11 +12,31 @@ Optional Properties:
>  - pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
>  - reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
>  
> -The device node must contain one 'port' child node for its digital output
> -video port, in accordance with the video interface bindings defined in
> -Documentation/devicetree/bindings/media/video-interfaces.txt.
> +The device node must contain one 'port' child node per device physical input
> +and output port, in accordance with the video interface bindings defined in
> +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
> +are numbered as follows
>  
> -Required Endpoint Properties for parallel synchronization:
> +	  Name		Type		Port
> +	--------------------------------------
> +	  AIP1A		sink		0
> +	  AIP1B		sink		1
> +	  Y-OUT		src		2
> +
> +The device node must contain at least one sink port and the src port. Each input
> +port must be linked to an endpoint defined in
> +Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
> +port/connector layout is as follows
> +
> +tvp-5150 port@0 (AIP1A)
> +	endpoint@0 -----------> Comp0-Con  port
> +	endpoint@1 -----------> Svideo-Con port
> +tvp-5150 port@1 (AIP1B)
> +	endpoint   -----------> Comp1-Con  port
> +tvp-5150 port@2
> +	endpoint (video bitstream output at YOUT[0-7] parallel bus)
> +
> +Required Endpoint Properties for parallel synchronization on output port:
>  
>  - hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
>  - vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
> @@ -26,17 +46,75 @@ Required Endpoint Properties for parallel synchronization:
>  If none of hsync-active, vsync-active and field-even-active is specified,
>  the endpoint is assumed to use embedded BT.656 synchronization.
>  
> -Example:
> +Example - three input sources:
> +
> +comp_connector_0 {
> +	compatible = "composite-video-connector";
> +	label = "Composite0";
> +
> +	port {
> +		composite0_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_composite0>;
> +		};
> +	};
> +};
> +
> +comp_connector_1 {
> +	compatible = "composite-video-connector";
> +	label = "Composite1";
> +
> +	port {
> +		composite1_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_composite1>;
> +		};
> +	};
> +};
> +
> +svid_connector {
> +	compatible = "svideo-connector";
> +	label = "S-Video";
> +
> +	port {
> +		svideo_to_tvp5150: endpoint {
> +			remote-endpoint = <&tvp5150_to_svideo>;
> +		};
> +	};
> +};
>  
>  &i2c2 {
> -	...
>  	tvp5150@5c {
>  		compatible = "ti,tvp5150";
>  		reg = <0x5c>;
>  		pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
>  		reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
>  
> -		port {
> +		port@0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +
> +			tvp5150_to_composite0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&composite0_to_tvp5150>;
> +			};
> +
> +			tvp5150_to_svideo: endpoint@1 {
> +				reg = <1>;
> +				remote-endpoint = <&svideo_to_tvp5150>;
> +			};
> +		};
> +
> +		port@1 {
> +			reg = <1>;
> +
> +			tvp5150_to_composite1: endpoint {
> +                                remote-endpoint = <&composite1_to_tvp5150>;
> +			};
> +		};
> +
> +		port@2 {
> +			reg = <2>;
> +
>  			tvp5150_1: endpoint {
>  				remote-endpoint = <&ccdc_ep>;
>  			};

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector
  2019-04-15 12:44 ` [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector Marco Felsch
@ 2019-05-16 18:07   ` Laurent Pinchart
  2019-08-13  9:10     ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-05-16 18:07 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel

Hi Marco,

Thank you for the patch.

On Mon, Apr 15, 2019 at 02:44:12PM +0200, Marco Felsch wrote:
> The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
> data and is able to auto-detect the input signal. The auto-detection
> does not work if the connector does not receive an input signal and the
> tvp5150 might not be configured correctly. This misconfiguration leads
> into wrong decoded video streams if the tvp5150 gets powered on before
> the video signal is present.
> 
> Limit the supported tv norms according to the actual selected connector
> to avoid a misconfiguration.

This seems a bit of a hack to me. In particular, on what grounds would
you specify a particular configuration in DT ? Also, this issue affects
non-DT systems, and should be solved globally.

> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v5:
> - probe() initialize supported tv-norms according the given connectors
>   if they are available.
> - check if media-controller is used. Don't limit the norm if it isn't
>   used.
> - add more logic to be smarter during connector changing so it is
>   intuitiver for the user space.
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> 
>  drivers/media/i2c/tvp5150.c | 69 +++++++++++++++++++++++++++++++++++--
>  1 file changed, 67 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index cd54715eb641..c0ee08546643 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -32,6 +32,13 @@
>  #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
>  #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
>  #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
> +#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
> +				 V4L2_STD_NTSC_443 | \
> +				 V4L2_STD_PAL      | \
> +				 V4L2_STD_PAL_M    | \
> +				 V4L2_STD_PAL_N    | \
> +				 V4L2_STD_PAL_Nc   | \
> +				 V4L2_STD_SECAM)
>  
>  MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
>  MODULE_AUTHOR("Mauro Carvalho Chehab");
> @@ -66,6 +73,7 @@ struct tvp5150 {
>  	/* media-ctl properties */
>  	struct media_pad pads[TVP5150_NUM_PADS];
>  	struct tvp5150_connector *connectors;
> +	struct tvp5150_connector *cur_connector;
>  	int connectors_num;
>  
>  	struct v4l2_ctrl_handler hdl;
> @@ -785,17 +793,28 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
>  static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
>  {
>  	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct tvp5150_connector *cur_con = decoder->cur_connector;
> +	v4l2_std_id supported_norms = cur_con ?
> +		cur_con->base.connector.analog.supported_tvnorms : V4L2_STD_ALL;
>  
>  	if (decoder->norm == std)
>  		return 0;
>  
> +	/*
> +	 * check if requested std or group of std's is/are supported by the
> +	 * connector
> +	 */
> +	if ((supported_norms & std) == 0)
> +		return -EINVAL;
> +
>  	/* Change cropping height limits */
>  	if (std & V4L2_STD_525_60)
>  		decoder->rect.height = TVP5150_V_MAX_525_60;
>  	else
>  		decoder->rect.height = TVP5150_V_MAX_OTHERS;
>  
> -	decoder->norm = std;
> +	/* set only the specific supported std in case of group of std's */
> +	decoder->norm = supported_norms & std;
>  
>  	return tvp5150_set_std(sd, std);
>  }
> @@ -1347,6 +1366,8 @@ static int tvp5150_link_setup(struct media_entity *entity,
>  			  TVP5150_BLACK_SCREEN, 0);
>  
>  	if (flags & MEDIA_LNK_FL_ENABLED) {
> +		u32 new_norm;
> +
>  		/*
>  		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
>  		 * Both links must be enabled in one-shot regardless which link
> @@ -1358,6 +1379,26 @@ static int tvp5150_link_setup(struct media_entity *entity,
>  			if (err)
>  				return err;
>  		}
> +
> +		/* Update the current connector */
> +		decoder->cur_connector =
> +			container_of(remote, struct tvp5150_connector, pad);
> +
> +		/*
> +		 * Do nothing if the new connector supports the same tv-norms as
> +		 * the old one.
> +		 */
> +		new_norm = decoder->norm &
> +			decoder->cur_connector->base.connector.analog.supported_tvnorms;
> +		if (decoder->norm == new_norm)
> +			return 0;
> +
> +		/*
> +		 * Fallback to the new connector tv-norms if we can't find any
> +		 * common between the current tv-norm and the new one.
> +		 */
> +		tvp5150_s_std(sd, new_norm ? new_norm :
> +			decoder->cur_connector->base.connector.analog.supported_tvnorms);
>  	}
>  
>  	return 0;
> @@ -1576,6 +1617,9 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
>  				TVP5150_COMPOSITE1;
>  
>  			tvp5150_selmux(sd);
> +			decoder->cur_connector = &decoder->connectors[i];
> +			tvp5150_s_std(sd,
> +				decoder->connectors[i].base.connector.analog.supported_tvnorms);
>  		}
>  	}
>  #endif
> @@ -1903,6 +1947,11 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
>  				ret = -EINVAL;
>  				goto err;
>  			}
> +			if (!(c.connector.analog.supported_tvnorms &
> +			    TVP5150_STD_MASK))
> +				dev_warn(dev,
> +					"Unsupported tv-norm on connector %s.\n",
> +					c.label);
>  			in++;
>  			break;
>  		case TVP5150_PAD_VID_OUT:
> @@ -2011,7 +2060,23 @@ static int tvp5150_probe(struct i2c_client *c,
>  	if (res < 0)
>  		goto err_cleanup_dt;
>  
> -	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> +	/*
> +	 * Iterate over all available connectors in case they are supported and
> +	 * successfully parsed. Fallback to default autodetect in case they
> +	 * aren't supported.
> +	 */
> +	if (core->connectors) {
> +		struct v4l2_fwnode_connector *con;
> +		int i;
> +
> +		for (i = 0; i < core->connectors_num; i++) {
> +			con = &core->connectors[i].base;
> +			core->norm |= con->connector.analog.supported_tvnorms;
> +		}
> +	} else {
> +		core->norm = V4L2_STD_ALL;
> +	}
> +
>  	core->detected_norm = V4L2_STD_UNKNOWN;
>  	core->input = TVP5150_COMPOSITE1;
>  	core->enable = true;
> -- 
> 2.20.1
> 

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-05-06 13:36   ` Jacopo Mondi
@ 2019-08-09  5:33     ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:33 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Hi Jacopo,

On 19-05-06 15:36, Jacopo Mondi wrote:
> Hi Marco,

Sorry for the long time absence of this topic...

> On Mon, Apr 15, 2019 at 02:44:07PM +0200, Marco Felsch wrote:
> > Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
> > the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
> > no way to try different selections. The patch adds a helper function to
> > select the correct selection memory space (sub-device file handle or
> > driver state) which will be set/returned.
> >
> > The TVP5150 AVID will be updated if the 'which' field is FORMAT_ACTIVE
> > and the requested selection rectangle differs from the already set one.
> >
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > Changelog:
> >
> > v5:
> >  - handle stub for v4l2_subdev_get_try_crop() internal since commit
> >    ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
> >    isn't anymore part of this series.
> >  - add error handling of __tvp5150_get_pad_crop()
> > v4:
> >  - fix merge conflict due to rebase on top of media-tree/master
> >  - __tvp5150_get_pad_crop(): cosmetic alignment fixes
> >
> >  drivers/media/i2c/tvp5150.c | 130 ++++++++++++++++++++++++++----------
> >  1 file changed, 96 insertions(+), 34 deletions(-)
> >
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index 4e3228b2ccbc..9331609425bf 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -19,6 +19,7 @@
> >  #include <media/v4l2-ctrls.h>
> >  #include <media/v4l2-fwnode.h>
> >  #include <media/v4l2-mc.h>
> > +#include <media/v4l2-rect.h>
> >
> >  #include "tvp5150_reg.h"
> >
> > @@ -997,20 +998,48 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
> >  		crop->height = TVP5150_V_MAX_OTHERS;
> >  }
> >
> > +static struct v4l2_rect *
> > +__tvp5150_get_pad_crop(struct tvp5150 *decoder,
> > +		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> > +		       enum v4l2_subdev_format_whence which)
> > +{
> > +	switch (which) {
> > +	case V4L2_SUBDEV_FORMAT_TRY:
> > +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
> > +		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
> > +#else
> > +		return ERR_PTR(-ENOTTY);
> > +#endif
> > +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> > +		return &decoder->rect;
> > +	default:
> > +		return NULL;
> 
> Do you need this default case? Can you return -EINVAL so that...

I will change that, thanks.

> 
> > +	}
> > +}
> > +
> >  static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
> >  			    struct v4l2_subdev_pad_config *cfg,
> >  			    struct v4l2_subdev_format *format)
> >  {
> >  	struct v4l2_mbus_framefmt *f;
> > +	struct v4l2_rect *__crop;
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> >
> >  	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
> >  		return -EINVAL;
> >
> >  	f = &format->format;
> > +	__crop = __tvp5150_get_pad_crop(decoder, cfg, format->pad,
> > +					format->which);
> > +	if (IS_ERR_OR_NULL(__crop)) {
> 
> ... here you just need to check if (IS_ERR()) and return it?
> 
> > +		if (!__crop)
> > +			return -EINVAL;
> > +		else
> > +			return PTR_ERR(__crop);
> > +	}
> >
> > -	f->width = decoder->rect.width;
> > -	f->height = decoder->rect.height / 2;
> > +	f->width = __crop->width;
> > +	f->height = __crop->height / 2;
> >
> >  	f->code = TVP5150_MBUS_FMT;
> >  	f->field = TVP5150_FIELD;
> > @@ -1021,17 +1050,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
> >  	return 0;
> >  }
> >
> > +unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	v4l2_std_id std;
> > +
> > +	/* Calculate height based on current standard */
> > +	if (decoder->norm == V4L2_STD_ALL)
> > +		std = tvp5150_read_std(sd);
> > +	else
> > +		std = decoder->norm;
> > +
> > +	return (std & V4L2_STD_525_60) ?
> > +		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
> > +}
> > +
> > +static inline void
> > +__tvp5150_set_selection(struct v4l2_subdev *sd, struct v4l2_rect rect)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	unsigned int hmax = tvp5150_get_hmax(sd);
> > +
> > +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> > +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> > +		     rect.top + rect.height - hmax);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> > +		     rect.left >> TVP5150_CROP_SHIFT);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> > +		     rect.left | (1 << TVP5150_CROP_SHIFT));
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> > +		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> > +		     TVP5150_CROP_SHIFT);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> > +		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> > +}
> > +
> >  static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  				 struct v4l2_subdev_pad_config *cfg,
> >  				 struct v4l2_subdev_selection *sel)
> >  {
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> >  	struct v4l2_rect rect = sel->r;
> > -	v4l2_std_id std;
> > -	int hmax;
> > +	struct v4l2_rect *__crop;
> > +	unsigned int hmax;
> >
> > -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
> > -	    sel->target != V4L2_SEL_TGT_CROP)
> > +	if (sel->target != V4L2_SEL_TGT_CROP)
> >  		return -EINVAL;
> >
> >  	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
> > @@ -1040,17 +1103,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  	/* tvp5150 has some special limits */
> >  	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
> >  	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
> > -
> > -	/* Calculate height based on current standard */
> > -	if (decoder->norm == V4L2_STD_ALL)
> > -		std = tvp5150_read_std(sd);
> > -	else
> > -		std = decoder->norm;
> > -
> > -	if (std & V4L2_STD_525_60)
> > -		hmax = TVP5150_V_MAX_525_60;
> > -	else
> > -		hmax = TVP5150_V_MAX_OTHERS;
> > +	hmax = tvp5150_get_hmax(sd);
> >
> >  	/*
> >  	 * alignments:
> > @@ -1063,20 +1116,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
> >  			      hmax - rect.top, 0, 0);
> >
> > -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> > -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> > -		     rect.top + rect.height - hmax);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> > -		     rect.left >> TVP5150_CROP_SHIFT);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> > -		     rect.left | (1 << TVP5150_CROP_SHIFT));
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> > -		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> > -		     TVP5150_CROP_SHIFT);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> > -		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> > +	__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
> > +	if (IS_ERR_OR_NULL(__crop)) {
> > +		if (!__crop)
> > +			return -EINVAL;
> > +		else
> > +			return PTR_ERR(__crop);
> 
> here too

Simplified both thanks.

> 
> > +	}
> > +
> > +	/*
> > +	 * Update output image size if the selection (crop) rectangle size or
> > +	 * position has been modified.
> > +	 */
> > +	if (!v4l2_rect_equal(&rect, __crop))
> > +		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> 
> Can this be a single condition?
> Or maybe you could check if the rects are equal and this is a TRY and
> return here.

I squashed it into a single condition because your second approach won't
cover the case if it is TRY and the rect changed. In that case the rect
would be applied to the hw.

> 
> > +			__tvp5150_set_selection(sd, rect);
> >
> > -	decoder->rect = rect;
> > +	*__crop = rect;
> >
> >  	return 0;
> >  }
> > @@ -1086,11 +1142,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
> >  				 struct v4l2_subdev_selection *sel)
> >  {
> >  	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
> > +	struct v4l2_rect *__crop;
> >  	v4l2_std_id std;
> >
> > -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> > -		return -EINVAL;
> > -
> >  	switch (sel->target) {
> >  	case V4L2_SEL_TGT_CROP_BOUNDS:
> >  		sel->r.left = 0;
> > @@ -1108,7 +1162,15 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
> >  			sel->r.height = TVP5150_V_MAX_OTHERS;
> >  		return 0;
> >  	case V4L2_SEL_TGT_CROP:
> > -		sel->r = decoder->rect;
> > +		__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad,
> > +						sel->which);
> > +		if (IS_ERR_OR_NULL(__crop)) {
> > +			if (!__crop)
> > +				return -EINVAL;
> > +			else
> > +				return PTR_ERR(__crop);
> > +		}

This one as well.

Thanks for the review.

Regards,
  Marco

> > +		sel->r = *__crop;
> >  		return 0;
> >  	default:
> >  		return -EINVAL;
> > --
> > 2.20.1
> >



-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-05-14 18:48   ` Mauro Carvalho Chehab
@ 2019-08-09  5:34     ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:34 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Hi Mauro,

On 19-05-14 15:48, Mauro Carvalho Chehab wrote:
> Em Mon, 15 Apr 2019 14:44:07 +0200
> Marco Felsch <m.felsch@pengutronix.de> escreveu:
> 
> > Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
> > the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
> > no way to try different selections. The patch adds a helper function to
> > select the correct selection memory space (sub-device file handle or
> > driver state) which will be set/returned.
> > 
> > The TVP5150 AVID will be updated if the 'which' field is FORMAT_ACTIVE
> > and the requested selection rectangle differs from the already set one.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > Changelog:
> > 
> > v5:
> >  - handle stub for v4l2_subdev_get_try_crop() internal since commit
> >    ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
> >    isn't anymore part of this series.
> >  - add error handling of __tvp5150_get_pad_crop()
> > v4:
> >  - fix merge conflict due to rebase on top of media-tree/master
> >  - __tvp5150_get_pad_crop(): cosmetic alignment fixes
> > 
> >  drivers/media/i2c/tvp5150.c | 130 ++++++++++++++++++++++++++----------
> >  1 file changed, 96 insertions(+), 34 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index 4e3228b2ccbc..9331609425bf 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -19,6 +19,7 @@
> >  #include <media/v4l2-ctrls.h>
> >  #include <media/v4l2-fwnode.h>
> >  #include <media/v4l2-mc.h>
> > +#include <media/v4l2-rect.h>
> >  
> >  #include "tvp5150_reg.h"
> >  
> > @@ -997,20 +998,48 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
> >  		crop->height = TVP5150_V_MAX_OTHERS;
> >  }
> >  
> > +static struct v4l2_rect *
> > +__tvp5150_get_pad_crop(struct tvp5150 *decoder,
> > +		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> > +		       enum v4l2_subdev_format_whence which)
> > +{
> > +	switch (which) {
> > +	case V4L2_SUBDEV_FORMAT_TRY:
> > +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
> > +		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
> > +#else
> > +		return ERR_PTR(-ENOTTY);
> > +#endif
> > +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> > +		return &decoder->rect;
> > +	default:
> > +		return NULL;
> > +	}
> 
> Same comments as Jacopo: use return ERR_PTR(-EINVAL) instead...

I applied all comments from Jacopo.

Thanks for the review.

Regards,
  Marco

> 
> > +}
> > +
> >  static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
> >  			    struct v4l2_subdev_pad_config *cfg,
> >  			    struct v4l2_subdev_format *format)
> >  {
> >  	struct v4l2_mbus_framefmt *f;
> > +	struct v4l2_rect *__crop;
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> >  
> >  	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
> >  		return -EINVAL;
> >  
> >  	f = &format->format;
> > +	__crop = __tvp5150_get_pad_crop(decoder, cfg, format->pad,
> > +					format->which);
> > +	if (IS_ERR_OR_NULL(__crop)) {
> > +		if (!__crop)
> > +			return -EINVAL;
> > +		else
> > +			return PTR_ERR(__crop);
> 
> And here, return PTR_ERR directly. Same at the similar case below.
> 
> > +	}
> >  
> > -	f->width = decoder->rect.width;
> > -	f->height = decoder->rect.height / 2;
> > +	f->width = __crop->width;
> > +	f->height = __crop->height / 2;
> >  
> >  	f->code = TVP5150_MBUS_FMT;
> >  	f->field = TVP5150_FIELD;
> > @@ -1021,17 +1050,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
> >  	return 0;
> >  }
> >  
> > +unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	v4l2_std_id std;
> > +
> > +	/* Calculate height based on current standard */
> > +	if (decoder->norm == V4L2_STD_ALL)
> > +		std = tvp5150_read_std(sd);
> > +	else
> > +		std = decoder->norm;
> > +
> > +	return (std & V4L2_STD_525_60) ?
> > +		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
> > +}
> > +
> > +static inline void
> > +__tvp5150_set_selection(struct v4l2_subdev *sd, struct v4l2_rect rect)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	unsigned int hmax = tvp5150_get_hmax(sd);
> > +
> > +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> > +	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> > +		     rect.top + rect.height - hmax);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> > +		     rect.left >> TVP5150_CROP_SHIFT);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> > +		     rect.left | (1 << TVP5150_CROP_SHIFT));
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> > +		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> > +		     TVP5150_CROP_SHIFT);
> > +	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> > +		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> > +}
> > +
> >  static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  				 struct v4l2_subdev_pad_config *cfg,
> >  				 struct v4l2_subdev_selection *sel)
> >  {
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> >  	struct v4l2_rect rect = sel->r;
> > -	v4l2_std_id std;
> > -	int hmax;
> > +	struct v4l2_rect *__crop;
> > +	unsigned int hmax;
> >  
> > -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
> > -	    sel->target != V4L2_SEL_TGT_CROP)
> > +	if (sel->target != V4L2_SEL_TGT_CROP)
> >  		return -EINVAL;
> >  
> >  	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
> > @@ -1040,17 +1103,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  	/* tvp5150 has some special limits */
> >  	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
> >  	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
> > -
> > -	/* Calculate height based on current standard */
> > -	if (decoder->norm == V4L2_STD_ALL)
> > -		std = tvp5150_read_std(sd);
> > -	else
> > -		std = decoder->norm;
> > -
> > -	if (std & V4L2_STD_525_60)
> > -		hmax = TVP5150_V_MAX_525_60;
> > -	else
> > -		hmax = TVP5150_V_MAX_OTHERS;
> > +	hmax = tvp5150_get_hmax(sd);
> >  
> >  	/*
> >  	 * alignments:
> > @@ -1063,20 +1116,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
> >  			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
> >  			      hmax - rect.top, 0, 0);
> >  
> > -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> > -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> > -		     rect.top + rect.height - hmax);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> > -		     rect.left >> TVP5150_CROP_SHIFT);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> > -		     rect.left | (1 << TVP5150_CROP_SHIFT));
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> > -		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> > -		     TVP5150_CROP_SHIFT);
> > -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> > -		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> > +	__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
> > +	if (IS_ERR_OR_NULL(__crop)) {
> > +		if (!__crop)
> > +			return -EINVAL;
> > +		else
> > +			return PTR_ERR(__crop);
> > +	}
> > +
> > +	/*
> > +	 * Update output image size if the selection (crop) rectangle size or
> > +	 * position has been modified.
> > +	 */
> > +	if (!v4l2_rect_equal(&rect, __crop))
> > +		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> > +			__tvp5150_set_selection(sd, rect);
> >  
> > -	decoder->rect = rect;
> > +	*__crop = rect;
> >  
> >  	return 0;
> >  }
> > @@ -1086,11 +1142,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
> >  				 struct v4l2_subdev_selection *sel)
> >  {
> >  	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
> > +	struct v4l2_rect *__crop;
> >  	v4l2_std_id std;
> >  
> > -	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> > -		return -EINVAL;
> > -
> >  	switch (sel->target) {
> >  	case V4L2_SEL_TGT_CROP_BOUNDS:
> >  		sel->r.left = 0;
> > @@ -1108,7 +1162,15 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
> >  			sel->r.height = TVP5150_V_MAX_OTHERS;
> >  		return 0;
> >  	case V4L2_SEL_TGT_CROP:
> > -		sel->r = decoder->rect;
> > +		__crop = __tvp5150_get_pad_crop(decoder, cfg, sel->pad,
> > +						sel->which);
> > +		if (IS_ERR_OR_NULL(__crop)) {
> > +			if (!__crop)
> > +				return -EINVAL;
> > +			else
> > +				return PTR_ERR(__crop);
> > +		}
> > +		sel->r = *__crop;
> >  		return 0;
> >  	default:
> >  		return -EINVAL;
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 09/13] media: tvp5150: add s_power callback
  2019-05-14 20:13   ` Mauro Carvalho Chehab
@ 2019-08-09  5:39     ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:39 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel

Hi Mauro,

On 19-05-14 17:13, Mauro Carvalho Chehab wrote:
> Em Mon, 15 Apr 2019 14:44:09 +0200
> Marco Felsch <m.felsch@pengutronix.de> escreveu:
> 
> > Don't en-/disable the interrupts during s_stream because someone can
> > disable the stream but wants to get informed if the stream is locked
> > again. So keep the interrupts enabled the whole time the pipeline is
> > opened.
> 
> Not testing on any tvp5150 hardware, looks ok to me.

Means I get your Reviewed-by? :)

Regards,
  Marco

> 
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
> >  1 file changed, 17 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index 305a5e256b31..cd54715eb641 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -1370,11 +1370,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
> >  /****************************************************************************
> >  			I2C Command
> >   ****************************************************************************/
> > +static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	unsigned int val = 0;
> > +
> > +	if (on)
> > +		val = TVP5150_INT_A_LOCK;
> > +
> > +	if (decoder->irq)
> > +		/* Enable / Disable lock interrupt */
> > +		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> > +				   TVP5150_INT_A_LOCK, val);
> > +
> > +	return 0;
> > +}
> >  
> >  static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
> >  {
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> > -	unsigned int mask, val = 0, int_val = 0;
> > +	unsigned int mask, val = 0;
> >  
> >  	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
> >  	       TVP5150_MISC_CTL_CLOCK_OE;
> > @@ -1387,15 +1402,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
> >  			val = decoder->lock ? decoder->oe : 0;
> >  		else
> >  			val = decoder->oe;
> > -		int_val = TVP5150_INT_A_LOCK;
> >  		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
> >  	}
> >  
> >  	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
> > -	if (decoder->irq)
> > -		/* Enable / Disable lock interrupt */
> > -		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> > -				   TVP5150_INT_A_LOCK, int_val);
> >  
> >  	return 0;
> >  }
> > @@ -1586,6 +1596,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
> >  	.g_register = tvp5150_g_register,
> >  	.s_register = tvp5150_s_register,
> >  #endif
> > +	.s_power = tvp5150_s_power,
> >  };
> >  
> >  static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 13/13] media: tvp5150: make debug output more readable
  2019-05-14 20:18     ` Mauro Carvalho Chehab
@ 2019-08-09  5:42       ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:42 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Jacopo Mondi, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel

Hi Mauro,

On 19-05-14 17:18, Mauro Carvalho Chehab wrote:
> Em Mon, 6 May 2019 15:39:05 +0200
> Jacopo Mondi <jacopo@jmondi.org> escreveu:
> 
> > Hi Marco,
> >   thanks
> > 
> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> Looks ok to me too.

Same here, can I add your Reviewed-by tag too?

Regards,
  Marco

> > 
> > On Mon, Apr 15, 2019 at 02:44:13PM +0200, Marco Felsch wrote:
> > > The debug output for tvp5150_selmux() isn't really intuitive. Register
> > > values are printed decimal formatted and the input/output driver states
> > > are printed as enum. Even more the "normal" output enum mapps to zero so
> > > a active output will printing output=0 and a inactive output=1.
> > >
> > > Change this by brinting the register values hex formatted and the states
> > > as more readable string.
> > >
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > >  drivers/media/i2c/tvp5150.c | 9 ++++++---
> > >  1 file changed, 6 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > index c0ee08546643..13ee6d781efb 100644
> > > --- a/drivers/media/i2c/tvp5150.c
> > > +++ b/drivers/media/i2c/tvp5150.c
> > > @@ -302,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
> > >  		break;
> > >  	}
> > >
> > > -	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
> > > -			decoder->input, decoder->output,
> > > -			input, opmode);
> > > +	dev_dbg_lvl(sd->dev, 1, debug,
> > > +		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
> > > +		    decoder->input == 0 ? "aip1a" :
> > > +		    decoder->input == 2 ? "aip1b" : "svideo",
> > > +		    decoder->output == 0 ? "normal" : "black-frame-gen",
> > > +		    input, opmode);
> > >
> > >  	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
> > >  	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
> > > --
> > > 2.20.1
> > >  
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree
  2019-05-14 20:20   ` Mauro Carvalho Chehab
@ 2019-08-09  5:42     ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:42 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel,
	Michael Tretter

Hi Mauro,

On 19-05-14 17:20, Mauro Carvalho Chehab wrote:
> Em Mon, 15 Apr 2019 14:44:08 +0200
> Marco Felsch <m.felsch@pengutronix.de> escreveu:
> 
> > From: Michael Tretter <m.tretter@pengutronix.de>
> > 
> > There are several debug prints in the tvp5150_parse_dt() function, which
> > do not print the prefix, because the v4l2_subdev is not initialized, yet.
> > 
> > Initialize the v4l2_subdev before parsing the device tree to fix the
> > debug messages.
> > 
> > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> 
> Looks ok to me.

Can I add you Reviewed-by tag here?

Regards,
  Marco

> 
> > ---
> >  drivers/media/i2c/tvp5150.c | 7 +++----
> >  1 file changed, 3 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index 9331609425bf..305a5e256b31 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -1973,6 +1973,9 @@ static int tvp5150_probe(struct i2c_client *c,
> >  
> >  	core->regmap = map;
> >  	sd = &core->sd;
> > +	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > +	sd->internal_ops = &tvp5150_internal_ops;
> > +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> >  
> >  	if (IS_ENABLED(CONFIG_OF) && np) {
> >  		res = tvp5150_parse_dt(core, np);
> > @@ -1985,10 +1988,6 @@ static int tvp5150_probe(struct i2c_client *c,
> >  		core->mbus_type = V4L2_MBUS_BT656;
> >  	}
> >  
> > -	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > -	sd->internal_ops = &tvp5150_internal_ops;
> > -	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > -
> >  	res = tvp5150_mc_init(core);
> >  	if (res)
> >  		goto err_cleanup_dt;
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-05-16 16:27   ` Laurent Pinchart
@ 2019-08-09  5:58     ` Marco Felsch
  2019-08-15 12:33       ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  5:58 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Laurent,

On 19-05-16 19:27, Laurent Pinchart wrote:
> Hi Marco,
> 
> Thank you for the patch.
> 
> On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> > Some connectors no matter if in- or output supports only a limited
> > range of tv norms. It doesn't matter if the hardware behind that
> > connector supports more than the listed formats since the users are
> > restriced by a label e.g. to plug only a camera into this connector
> > which uses the PAL format.
> > 
> > This patch adds the capability to describe such limitation within the
> > firmware. There are no format restrictions if the property isn't
> > present, so it's completely backward compatible.
> 
> Why is this needed ? It's not really a hardware property, is it ? What's
> the use case ?

Cause some hardware only support a limited range of formats to that
connector. Of course it is a hardware property. For example if a
customer wants to limit a connector to a specifc norm because the
hardware behind that connector only supports that format or is
restricted to that format.

Regards,
  Marco

> 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - tvnorms.h: use tabs instead of spaces
> > - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  .../display/connector/analog-tv-connector.txt |  4 ++
> >  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> >  2 files changed, 60 insertions(+)
> >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > 
> > diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > index 0c0970c210ab..346f8937a0b7 100644
> > --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > @@ -6,6 +6,9 @@ Required properties:
> >  
> >  Optional properties:
> >  - label: a symbolic name for the connector
> > +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > +           all tv norms are allowed. Possible video standards are defined in
> > +           include/dt-bindings/media/tvnorms.h.
> >  
> >  Required nodes:
> >  - Video port for TV input
> > @@ -16,6 +19,7 @@ Example
> >  tv: connector {
> >  	compatible = "composite-video-connector";
> >  	label = "tv";
> > +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> >  
> >  	port {
> >  		tv_connector_in: endpoint {
> > diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > new file mode 100644
> > index 000000000000..058ab8414145
> > --- /dev/null
> > +++ b/include/dt-bindings/media/tvnorms.h
> > @@ -0,0 +1,56 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > +/*
> > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > + */
> > +
> > +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > +
> > +/* one bit for each */
> > +#define TVNORM_PAL_B		0x00000001
> > +#define TVNORM_PAL_B1		0x00000002
> > +#define TVNORM_PAL_G		0x00000004
> > +#define TVNORM_PAL_H		0x00000008
> > +#define TVNORM_PAL_I		0x00000010
> > +#define TVNORM_PAL_D		0x00000020
> > +#define TVNORM_PAL_D1		0x00000040
> > +#define TVNORM_PAL_K		0x00000080
> > +
> > +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > +				 TVNORM_PAL_B1 | \
> > +				 TVNORM_PAL_G  | \
> > +				 TVNORM_PAL_H  | \
> > +				 TVNORM_PAL_I  | \
> > +				 TVNORM_PAL_D  | \
> > +				 TVNORM_PAL_D1 | \
> > +				 TVNORM_PAL_K)
> > +
> > +#define TVNORM_PAL_M		0x00000100
> > +#define TVNORM_PAL_N		0x00000200
> > +#define TVNORM_PAL_Nc		0x00000400
> > +#define TVNORM_PAL_60		0x00000800
> > +
> > +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > +#define TVNORM_NTSC_443		0x00004000
> > +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > +
> > +#define TVNORM_SECAM_B		0x00010000
> > +#define TVNORM_SECAM_D		0x00020000
> > +#define TVNORM_SECAM_G		0x00040000
> > +#define TVNORM_SECAM_H		0x00080000
> > +#define TVNORM_SECAM_K		0x00100000
> > +#define TVNORM_SECAM_K1		0x00200000
> > +#define TVNORM_SECAM_L		0x00400000
> > +#define TVNORM_SECAM_LC		0x00800000
> > +
> > +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > +				 TVNORM_SECAM_D  | \
> > +				 TVNORM_SECAM_G  | \
> > +				 TVNORM_SECAM_H  | \
> > +				 TVNORM_SECAM_K  | \
> > +				 TVNORM_SECAM_K1 | \
> > +				 TVNORM_SECAM_L  | \
> > +				 TVNORM_SECAM_LC)
> > +
> > +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-05-14 18:11     ` Mauro Carvalho Chehab
@ 2019-08-09  6:00       ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  6:00 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Hans Verkuil, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel,
	Rob Herring

Hi Mauro, Hans,

thanks for the review.

On 19-05-14 15:11, Mauro Carvalho Chehab wrote:
> Em Mon, 6 May 2019 12:01:06 +0200
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
> > On 4/15/19 2:44 PM, Marco Felsch wrote:
> > > Some connectors no matter if in- or output supports only a limited
> > > range of tv norms. It doesn't matter if the hardware behind that
> > > connector supports more than the listed formats since the users are
> > > restriced by a label e.g. to plug only a camera into this connector
> > > which uses the PAL format.  
> > 
> > For S-Video and Composite connectors there are really just two formats
> > to consider: 50 and 60 Hz. I.e. there is no difference between PAL
> > and SECAM. Only for tuners/modulators does this matter.
> > 
> > So it is a good idea to add TVNORM_525_60, TVNORM_625_50 to tvnorms.h.

Of course I can add this ones. With Mauro's concerns below do you still
think that it is a good idea to adapt the example?

Regards,
  Marco

> > In the various bindings examples I would recommend that you use
> > TVNORM_525_60 or TVNORM_625_50 rather than e.g. PAL_M since that's what
> > you would use in practice for Composite/S-Video.
> 
> Hans, that could be true for component video, but for S-Video and
> Composite, you need to tell the demod how the color sub-carrier is
> encoded, and what's its frequency, or otherwise it won't work.
> 
> There are plenty of equipments in Brazil that have both NTSC/M and
> PAL/M (and a few with PAL/N') output. All those formats are 60Hz.
> 
> Colors are only decoded by tvp5150 and other demods if it is set
> to the right color format (PAL or NTSC) and to the right line 
> frequency (60Hz) [1]. Also, some decoders are very sensitive to the
> chroma sub-carrier frequency. That's the case of tvp5150.
> 
> [1] Or - when supported by the hardware - if the demod is set to
>     automatic mode.
> 
>     Automatic mode usually doesn't work well with PAL/M and PAL/N'.
> 
>     The problem is related to the sub-carrier frequency: both 
>     PAL/N' (used only on Paraguay) and NTSC/M have the same 
>     frequency; PAL/M has a close but different frequency for the
>     color sub-carrier.
> 
>     Most decoders use the frequency of the chroma sub-carrier in
>     order to switch between NTSC/M nd PAL/M. So, auto-detection
>     usually fails with PAL/N', as such detectors understand it
>     as NTSC.
> 
>     Worse than that, it is not uncommon to have pseudo-PAL-M devices
>     that were made for the US market, and received a conversion
>     to PAL, with envolves adding a small board with a NTSC->PAL converter.
>     As most TV sets used in this part of the world are designed to
>     work both with PAL/M and PAL/N' (by using a broader notch filter),
>     to make the hardware cheaper, lots of manufacturers just
>     change the modulation on encoders, while keeping the NTSC XTAL.
>     So, in practice, such devices, sold as "PAL/M" are actually PAL/N'.
>     A significant amount of old VCRs and DVD devices found in Brazil
>     are actually PAL/N'. The same applies to game consoles.
> 
>     Btw, the main reason for having analog video streams here nowadays
>     is to copy old videos from VCRs and encode them digitally or to
>     record games from game consoles.
> 
> > 
> > Regards,
> > 
> > 	Hans
> > 
> > > 
> > > This patch adds the capability to describe such limitation within the
> > > firmware. There are no format restrictions if the property isn't
> > > present, so it's completely backward compatible.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Rob Herring <robh@kernel.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v6:
> > > - tvnorms.h: use tabs instead of spaces
> > > - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > > - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  .../display/connector/analog-tv-connector.txt |  4 ++
> > >  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> > >  2 files changed, 60 insertions(+)
> > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > > 
> > > diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > index 0c0970c210ab..346f8937a0b7 100644
> > > --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > @@ -6,6 +6,9 @@ Required properties:
> > >  
> > >  Optional properties:
> > >  - label: a symbolic name for the connector
> > > +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > > +           all tv norms are allowed. Possible video standards are defined in
> > > +           include/dt-bindings/media/tvnorms.h.
> > >  
> > >  Required nodes:
> > >  - Video port for TV input
> > > @@ -16,6 +19,7 @@ Example
> > >  tv: connector {
> > >  	compatible = "composite-video-connector";
> > >  	label = "tv";
> > > +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> > >  
> > >  	port {
> > >  		tv_connector_in: endpoint {
> > > diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > > new file mode 100644
> > > index 000000000000..058ab8414145
> > > --- /dev/null
> > > +++ b/include/dt-bindings/media/tvnorms.h
> > > @@ -0,0 +1,56 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > > +/*
> > > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > > + */
> > > +
> > > +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > > +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > > +
> > > +/* one bit for each */
> > > +#define TVNORM_PAL_B		0x00000001
> > > +#define TVNORM_PAL_B1		0x00000002
> > > +#define TVNORM_PAL_G		0x00000004
> > > +#define TVNORM_PAL_H		0x00000008
> > > +#define TVNORM_PAL_I		0x00000010
> > > +#define TVNORM_PAL_D		0x00000020
> > > +#define TVNORM_PAL_D1		0x00000040
> > > +#define TVNORM_PAL_K		0x00000080
> > > +
> > > +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > > +				 TVNORM_PAL_B1 | \
> > > +				 TVNORM_PAL_G  | \
> > > +				 TVNORM_PAL_H  | \
> > > +				 TVNORM_PAL_I  | \
> > > +				 TVNORM_PAL_D  | \
> > > +				 TVNORM_PAL_D1 | \
> > > +				 TVNORM_PAL_K)
> > > +
> > > +#define TVNORM_PAL_M		0x00000100
> > > +#define TVNORM_PAL_N		0x00000200
> > > +#define TVNORM_PAL_Nc		0x00000400
> > > +#define TVNORM_PAL_60		0x00000800
> > > +
> > > +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > > +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > > +#define TVNORM_NTSC_443		0x00004000
> > > +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > > +
> > > +#define TVNORM_SECAM_B		0x00010000
> > > +#define TVNORM_SECAM_D		0x00020000
> > > +#define TVNORM_SECAM_G		0x00040000
> > > +#define TVNORM_SECAM_H		0x00080000
> > > +#define TVNORM_SECAM_K		0x00100000
> > > +#define TVNORM_SECAM_K1		0x00200000
> > > +#define TVNORM_SECAM_L		0x00400000
> > > +#define TVNORM_SECAM_LC		0x00800000
> > > +
> > > +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > > +				 TVNORM_SECAM_D  | \
> > > +				 TVNORM_SECAM_G  | \
> > > +				 TVNORM_SECAM_H  | \
> > > +				 TVNORM_SECAM_K  | \
> > > +				 TVNORM_SECAM_K1 | \
> > > +				 TVNORM_SECAM_L  | \
> > > +				 TVNORM_SECAM_LC)
> > > +
> > > +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
> 
> Patch looks good to me.
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-05-06  9:50   ` Hans Verkuil
  2019-05-14 18:17     ` Mauro Carvalho Chehab
@ 2019-08-09  7:20     ` Marco Felsch
  1 sibling, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  7:20 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart, linux-media, devicetree, kernel, Jacopo Mondi

On 19-05-06 11:50, Hans Verkuil wrote:
> On 4/15/19 2:44 PM, Marco Felsch wrote:
> > Currently every driver needs to parse the connector endpoints by it self.
> > This is the initial work to make this generic. The generic connector has
> > some common fields and some connector specific parts. The generic one
> > includes:
> >   - type
> >   - label
> >   - remote_port (the port where the connector is connected to)
> >   - remote_id   (the endpoint where the connector is connected to)
> > 
> > The specific fields are within a union, since only one of them can be
> > available at the time. Since this is the initial support the patch adds
> > only the analog-connector specific ones.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - fix some spelling and style issues
> > - rm unnecessary comments
> > - drop vga and dvi connector
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> >  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 63 insertions(+)
> >  create mode 100644 include/media/v4l2-connector.h
> > 
> > diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > new file mode 100644
> > index 000000000000..3a951c54f50e
> > --- /dev/null
> > +++ b/include/media/v4l2-connector.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * v4l2-connector.h
> > + *
> > + * V4L2 connector types.
> > + *
> > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > + */
> > +
> > +#ifndef V4L2_CONNECTOR_H
> > +#define V4L2_CONNECTOR_H
> > +
> > +#define V4L2_CONNECTOR_MAX_LABEL 41
> 
> Where does 41 come from? It's a weird number...

What would you suggest?

> 
> > +
> > +/**
> > + * enum v4l2_connector_type - connector type
> > + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> 
> typo: connetor -> connector
> 
> > + * @V4L2_CON_COMPOSITE: analog composite connector
> > + * @V4L2_CON_SVIDEO:    analog svideo connector
> > + * @V4L2_CON_HDMI:      digital hdmi connector
> > + */
> > +enum v4l2_connector_type {
> > +	V4L2_CON_UNKNOWN,
> > +	V4L2_CON_COMPOSITE,
> > +	V4L2_CON_SVIDEO,
> > +	V4L2_CON_HDMI,
> > +};
> > +
> > +#endif /* V4L2_CONNECTOR_H */
> > +
> 
> Is there a reason to create a new header for this? I think it is perfectly OK to
> add this define + enum for v4l2-fwnode.h.

Okay, I can squash it.

> 
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 6c07825e18b9..f4df1b95c5ef 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -22,6 +22,7 @@
> >  #include <linux/list.h>
> >  #include <linux/types.h>
> >  
> > +#include <media/v4l2-connector.h>
> >  #include <media/v4l2-mediabus.h>
> >  #include <media/v4l2-subdev.h>
> >  
> > @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> >  	unsigned int remote_port;
> >  };
> >  
> > +/**
> > + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > + *                     if no restrictions are specified.
> > + */
> > +struct v4l2_fwnode_connector_analog {
> > +	v4l2_std_id supported_tvnorms;
> > +};
> > +
> > +/**
> > + * struct v4l2_fwnode_connector - the connector data structure
> > + * @remote_port: identifier of the remote endpoint port the connector connects
> > + *		 to
> > + * @remote_id: identifier of the remote endpoint the connector connects to
> > + * @label: connetor label
> 
> Same typo. It's probably a good idea to grep for this typo in this patch series :-)

I will grep it shortly before I send the new v7 ;-)

Regards,
  Marco

> 
> > + * @type: connector type
> > + * @connector: connector configuration
> > + * @connector.analog: analog connector configuration
> > + *                    &struct v4l2_fwnode_connector_analog
> > + */
> > +struct v4l2_fwnode_connector {
> > +	unsigned int remote_port;
> > +	unsigned int remote_id;
> > +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > +	enum v4l2_connector_type type;
> > +
> > +	union {
> > +		struct v4l2_fwnode_connector_analog analog;
> > +		/* future connectors */
> > +	} connector;
> > +};
> > +
> >  /**
> >   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> >   * @fwnode: pointer to the endpoint's fwnode handle
> > 
> 
> Regards,
> 
> 	Hans
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-05-16 16:36   ` Laurent Pinchart
@ 2019-08-09  7:55     ` Marco Felsch
  2019-08-15 12:38       ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  7:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Laurent,

On 19-05-16 19:36, Laurent Pinchart wrote:
> Hi Marco,
> 
> Thank you for the patch.

Thanks for the review and sorry for the delayed reply.

> On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> > Currently every driver needs to parse the connector endpoints by it self.
> 
> s/it self/itself/
> 
> > This is the initial work to make this generic. The generic connector has
> > some common fields and some connector specific parts. The generic one
> > includes:
> >   - type
> >   - label
> >   - remote_port (the port where the connector is connected to)
> >   - remote_id   (the endpoint where the connector is connected to)
> 
> This assumes a single connection between a connector and a remote port,
> and a single port on the connector side. Is this guaranteed ? For the
> mini-DIN-4 connectors (often used for S-Video) for instance, I recall
> from the extensive discussions we had in the past that they should be
> modeled with two pins, one for the Y component and one for C components.
> The rationale for this is to support systems where such a connector
> could be used to carry S-Video, but also two composite video signals
> (usually through an external adapter from 2 RCA female connectors to one
> S-Video male connector) that would be routed to two separate video
> decoders (or two different inputs of the same video decoder). Other
> topologies may be possible too.

I got your concerns and I also remember the tvp5150 port bindings
myself in the past. Do you know how often such a setup you described
above happens these days? I would rather add more documentation to the
bindings [1] and add a check to v4l2_fwnode_parse_connector() to
guarantee that one port has only one endpoint. Because I don't think
that analog connectors has a bright future these days.

[1] Documentation/devicetree/bindings/display/connector/ \
    analog-tv-connector.txt

> > The specific fields are within a union, since only one of them can be
> > available at the time. Since this is the initial support the patch adds
> > only the analog-connector specific ones.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v6:
> > - fix some spelling and style issues
> > - rm unnecessary comments
> > - drop vga and dvi connector
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> >  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 63 insertions(+)
> >  create mode 100644 include/media/v4l2-connector.h
> > 
> > diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > new file mode 100644
> > index 000000000000..3a951c54f50e
> > --- /dev/null
> > +++ b/include/media/v4l2-connector.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * v4l2-connector.h
> > + *
> > + * V4L2 connector types.
> > + *
> > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > + */
> > +
> > +#ifndef V4L2_CONNECTOR_H
> > +#define V4L2_CONNECTOR_H
> > +
> > +#define V4L2_CONNECTOR_MAX_LABEL 41
> 
> Hans pointed out this was a weird number. Should you turn the label
> field into a pointer to make this more generic (with a
> v4l2_fwnode_connector_cleanup() function then) ?

Yes, that would be the better approach. I will change that.

Regards,
  Marco

> > +
> > +/**
> > + * enum v4l2_connector_type - connector type
> > + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> > + * @V4L2_CON_COMPOSITE: analog composite connector
> > + * @V4L2_CON_SVIDEO:    analog svideo connector
> > + * @V4L2_CON_HDMI:      digital hdmi connector
> > + */
> > +enum v4l2_connector_type {
> > +	V4L2_CON_UNKNOWN,
> > +	V4L2_CON_COMPOSITE,
> > +	V4L2_CON_SVIDEO,
> > +	V4L2_CON_HDMI,
> > +};
> > +
> > +#endif /* V4L2_CONNECTOR_H */
> > +
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 6c07825e18b9..f4df1b95c5ef 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -22,6 +22,7 @@
> >  #include <linux/list.h>
> >  #include <linux/types.h>
> >  
> > +#include <media/v4l2-connector.h>
> >  #include <media/v4l2-mediabus.h>
> >  #include <media/v4l2-subdev.h>
> >  
> > @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> >  	unsigned int remote_port;
> >  };
> >  
> > +/**
> > + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > + *                     if no restrictions are specified.
> > + */
> > +struct v4l2_fwnode_connector_analog {
> > +	v4l2_std_id supported_tvnorms;
> > +};
> > +
> > +/**
> > + * struct v4l2_fwnode_connector - the connector data structure
> > + * @remote_port: identifier of the remote endpoint port the connector connects
> > + *		 to
> > + * @remote_id: identifier of the remote endpoint the connector connects to
> > + * @label: connetor label
> > + * @type: connector type
> > + * @connector: connector configuration
> > + * @connector.analog: analog connector configuration
> > + *                    &struct v4l2_fwnode_connector_analog
> > + */
> > +struct v4l2_fwnode_connector {
> > +	unsigned int remote_port;
> > +	unsigned int remote_id;
> > +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > +	enum v4l2_connector_type type;
> > +
> > +	union {
> > +		struct v4l2_fwnode_connector_analog analog;
> > +		/* future connectors */
> > +	} connector;
> > +};
> > +
> >  /**
> >   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> >   * @fwnode: pointer to the endpoint's fwnode handle
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-05-14 18:20     ` Mauro Carvalho Chehab
  2019-05-16 16:51       ` Laurent Pinchart
@ 2019-08-09  8:59       ` Marco Felsch
  1 sibling, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-09  8:59 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Hans Verkuil, sakari.ailus, hans.verkuil, jacopo+renesas,
	robh+dt, laurent.pinchart, linux-media, devicetree, kernel,
	Jacopo Mondi

Hi Mauro, Hans,

On 19-05-14 15:20, Mauro Carvalho Chehab wrote:
> Em Mon, 6 May 2019 12:10:41 +0200
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
> > On 4/15/19 2:44 PM, Marco Felsch wrote:
> > > The patch adds the initial connector parsing code, so we can move from a
> > > driver specific parsing code to a generic one. Currently only the
> > > generic fields and the analog-connector specific fields are parsed. Parsing
> > > the other connector specific fields can be added by a simple callbacks.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v6:
> > > - use 'unsigned int' count var
> > > - fix comment and style issues
> > > - place '/* fall through */' to correct places
> > > - fix error handling and cleanup by releasing fwnode
> > > - drop vga and dvi parsing support as those connectors are rarely used
> > >   these days
> > > 
> > > v5:
> > > - s/strlcpy/strscpy/
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> > >  include/media/v4l2-fwnode.h           |  16 ++++
> > >  2 files changed, 127 insertions(+)
> > > 
> > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > index 20571846e636..f1cca95c8fef 100644
> > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > >  }
> > >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > >  
> > > +static const struct v4l2_fwnode_connector_conv {
> > > +	enum v4l2_connector_type type;
> > > +	const char *name;
> > > +} connectors[] = {
> > > +	{
> > > +		.type = V4L2_CON_COMPOSITE,
> > > +		.name = "composite-video-connector",
> > > +	}, {
> > > +		.type = V4L2_CON_SVIDEO,
> > > +		.name = "svideo-connector",
> > > +	}, {
> > > +		.type = V4L2_CON_HDMI,
> > > +		.name = "hdmi-connector",
> > > +	},
> > > +};
> > > +
> > > +static enum v4l2_connector_type
> > > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > > +{
> > > +	unsigned int i;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > > +		if (!strcmp(con_str, connectors[i].name))
> > > +			return connectors[i].type;
> > > +
> > > +	/* no valid connector found */
> > > +	return V4L2_CON_UNKNOWN;
> > > +}
> > > +
> > > +static int
> > > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > > +				   struct v4l2_fwnode_connector *vc)
> > > +{
> > > +	u32 tvnorms;
> > > +	int ret;
> > > +
> > > +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > > +
> > > +	/* tvnorms is optional */
> > > +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > > +				struct v4l2_fwnode_connector *connector)
> > > +{
> > > +	struct fwnode_handle *fwnode;
> > > +	struct fwnode_endpoint __ep;
> > > +	const char *c_type_str, *label;
> > > +	int ret;
> > > +
> > > +	memset(connector, 0, sizeof(*connector));
> > > +
> > > +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> > > +	if (!fwnode)
> > > +		return -EINVAL;
> > > +
> > > +	/* parse all common properties first */
> > > +	/* connector-type is stored within the compatible string */
> > > +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> > > +	if (ret) {
> > > +		fwnode_handle_put(fwnode);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > > +
> > > +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > > +	connector->remote_port = __ep.port;
> > > +	connector->remote_id = __ep.id;
> > > +
> > > +	ret = fwnode_property_read_string(fwnode, "label", &label);
> > > +	if (!ret) {
> > > +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > > +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > > +	} else {
> > > +		/*
> > > +		 * labels are optional, if none is given create one:
> > > +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > > +		 */
> > > +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > > +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > > +			 connector->remote_id);
> > > +	}
> > > +
> > > +	/* now parse the connector specific properties */
> > > +	switch (connector->type) {
> > > +	case V4L2_CON_COMPOSITE:
> > > +		/* fall through */
> > > +	case V4L2_CON_SVIDEO:
> > > +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > > +		break;
> > > +	case V4L2_CON_HDMI:
> > > +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> > > +			c_type_str);  
> > 
> > Why warn? Just drop this.

Wanted to cache all cases here without adding hdmi handling.

> good point. I would prefer to have some warning here, in order to warn a
> developer that might be using it that this part of the code would require 
> some change.
> 
> perhaps pr_warn_once()?

Okay, I will change it to pr_warn_once().

Regards,
  Marco

> > 
> > > +		ret = 0;
> > > +		break;
> > > +	case V4L2_CON_UNKNOWN:
> > > +		/* fall through */
> > > +	default:
> > > +		pr_err("Unknown connector type\n");
> > > +		ret = -EINVAL;
> > > +	};
> > > +
> > > +	fwnode_handle_put(fwnode);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > > +
> > >  static int
> > >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > >  					  struct v4l2_async_notifier *notifier,
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index f4df1b95c5ef..e072f2915ddb 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > >   */
> > >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > >  
> > > +/**
> > > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > > + *          connected to
> > > + * @connector: pointer to the V4L2 fwnode connector data structure
> > > + *
> > > + * Fill the connector data structure with the connector type, label and the
> > > + * endpoint id and port where the connector belongs to. If no label is present
> > > + * a unique one will be created. Labels with more than 40 characters are cut.
> > > + *
> > > + * Return: %0 on success or a negative error code on failure:
> > > + *	   %-EINVAL on parsing failure
> > > + */
> > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > > +				struct v4l2_fwnode_connector *connector);
> > > +
> > >  /**
> > >   * typedef parse_endpoint_func - Driver's callback function to be called on
> > >   *	each V4L2 fwnode endpoint.
> > >   
> > 
> > Regards,
> > 
> > 	Hans
> 
> 
> 
> Thanks,
> Mauro
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-05-16 16:51       ` Laurent Pinchart
@ 2019-08-09 12:16         ` Marco Felsch
  2019-08-15 12:48           ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-09 12:16 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel,
	Jacopo Mondi

Hi Laurent,

On 19-05-16 19:51, Laurent Pinchart wrote:
> Hello Marco,
> 
> Thank you for the patch.

Thanks for the review.

> 
> On Tue, May 14, 2019 at 03:20:04PM -0300, Mauro Carvalho Chehab wrote:
> > Em Mon, 6 May 2019 12:10:41 +0200 Hans Verkuil escreveu:
> > > On 4/15/19 2:44 PM, Marco Felsch wrote:
> > > > The patch adds the initial connector parsing code, so we can move from a
> > > > driver specific parsing code to a generic one. Currently only the
> > > > generic fields and the analog-connector specific fields are parsed. Parsing
> > > > the other connector specific fields can be added by a simple callbacks.
> > > > 
> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > ---
> > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > 
> > > > v6:
> > > > - use 'unsigned int' count var
> > > > - fix comment and style issues
> > > > - place '/* fall through */' to correct places
> > > > - fix error handling and cleanup by releasing fwnode
> > > > - drop vga and dvi parsing support as those connectors are rarely used
> > > >   these days
> > > > 
> > > > v5:
> > > > - s/strlcpy/strscpy/
> > > > 
> > > > v2-v4:
> > > > - nothing since the patch was squashed from series [1] into this
> > > >   series.
> > > > 
> > > >  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> > > >  include/media/v4l2-fwnode.h           |  16 ++++
> > > >  2 files changed, 127 insertions(+)
> > > > 
> > > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > > index 20571846e636..f1cca95c8fef 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > > @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > > >  
> > > > +static const struct v4l2_fwnode_connector_conv {
> > > > +	enum v4l2_connector_type type;
> > > > +	const char *name;
> 
> Maybe compatible instead of name ?

Okay, I can change that.

> > > > +} connectors[] = {
> > > > +	{
> > > > +		.type = V4L2_CON_COMPOSITE,
> > > > +		.name = "composite-video-connector",
> > > > +	}, {
> > > > +		.type = V4L2_CON_SVIDEO,
> > > > +		.name = "svideo-connector",
> > > > +	}, {
> > > > +		.type = V4L2_CON_HDMI,
> > > > +		.name = "hdmi-connector",
> > > > +	},
> > > > +};
> > > > +
> > > > +static enum v4l2_connector_type
> > > > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > > > +{
> > > > +	unsigned int i;
> > > > +
> > > > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > > > +		if (!strcmp(con_str, connectors[i].name))
> > > > +			return connectors[i].type;
> > > > +
> > > > +	/* no valid connector found */
> 
> The usual comment style in this file is to start with a capital letter
> and end sentences with a period. I would however drop this comment, it's
> not very useful. The other comments should be updated accordingly.
> 

I will change my comments and drop this one.

> > > > +	return V4L2_CON_UNKNOWN;
> > > > +}
> > > > +
> > > > +static int
> > > > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > > > +				   struct v4l2_fwnode_connector *vc)
> > > > +{
> > > > +	u32 tvnorms;
> > > > +	int ret;
> > > > +
> > > > +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > > > +
> > > > +	/* tvnorms is optional */
> > > > +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> 
> Please document all exported functions with kerneldoc.

It is documented within the header file. To be aligned with the other
functions I wouldn't change that.

> > > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > > > +				struct v4l2_fwnode_connector *connector)
> > > > +{
> > > > +	struct fwnode_handle *fwnode;
> > > > +	struct fwnode_endpoint __ep;
> > > > +	const char *c_type_str, *label;
> > > > +	int ret;
> > > > +
> > > > +	memset(connector, 0, sizeof(*connector));
> > > > +
> > > > +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> 
> I would rename the argument __fwnode to fwnode, and rename the fwnode
> variable to remote (or similar) to make this clearer.

Okay.

> 
> > > > +	if (!fwnode)
> > > > +		return -EINVAL;
> 
> Is EINVAL the right error here ? Wouldn't it be useful for the caller to
> differentiate between unconnected connector nodes and invalid ones ?

Yes it would. Should I return ENOLINK instead?

> 
> > > > +
> > > > +	/* parse all common properties first */
> > > > +	/* connector-type is stored within the compatible string */
> > > > +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> 
> Prefixing or postfixing names with types is usually frowned upon. You
> could rename this to type_name for instance.

Okay.

> > > > +	if (ret) {
> > > > +		fwnode_handle_put(fwnode);
> > > > +		return -EINVAL;
> > > > +	}
> > > > +
> > > > +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > > > +
> > > > +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > > > +	connector->remote_port = __ep.port;
> > > > +	connector->remote_id = __ep.id;
> > > > +
> > > > +	ret = fwnode_property_read_string(fwnode, "label", &label);
> > > > +	if (!ret) {
> > > > +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > > > +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > > > +	} else {
> > > > +		/*
> > > > +		 * labels are optional, if none is given create one:
> > > > +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > > > +		 */
> > > > +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > > > +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > > > +			 connector->remote_id);
> 
> Should we really try to create labels when none is available ? If so
> this needs much more careful thoughts, we need to think about what the
> label will be used for, and create a good naming scheme accordingly. If
> the label will be displayed to the end-user I don't think the above name
> would be very useful, it would be best to leave it empty and let
> applications create a name based on the connector type and other
> information they have at their disposal.

Hm.. I don't have a strong opinion on that. If the others are with you I
will leave it empty.

> > > > +	}
> > > > +
> > > > +	/* now parse the connector specific properties */
> > > > +	switch (connector->type) {
> > > > +	case V4L2_CON_COMPOSITE:
> > > > +		/* fall through */
> 
> I don't think you need a fall-through comment when the two cases are
> adjacent with no line in-between.

Hm.. I don't know the compiler behaviour. According the official
gcc documentation [1] I would not leave that.

[1] https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

> 
> > > > +	case V4L2_CON_SVIDEO:
> > > > +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > > > +		break;
> > > > +	case V4L2_CON_HDMI:
> > > > +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> > > > +			c_type_str);  
> > > 
> > > Why warn? Just drop this.
> > 
> > good point. I would prefer to have some warning here, in order to warn a
> > developer that might be using it that this part of the code would require 
> > some change.
> > 
> > perhaps pr_warn_once()?
> >
> > > > +		ret = 0;
> > > > +		break;
> 
> If it's not supported we should warn and return an error. Otherwise we
> should be silent and return success. Combining a warning with success
> isn't a good idea, this is either a normal case or an error, not both.

The generic part still applies and is valid. That was the reason why I
did return success.

> > > > +	case V4L2_CON_UNKNOWN:
> > > > +		/* fall through */
> > > > +	default:
> > > > +		pr_err("Unknown connector type\n");
> > > > +		ret = -EINVAL;
> > > > +	};
> > > > +
> > > > +	fwnode_handle_put(fwnode);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > > > +
> > > >  static int
> > > >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > > >  					  struct v4l2_async_notifier *notifier,
> > > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > > index f4df1b95c5ef..e072f2915ddb 100644
> > > > --- a/include/media/v4l2-fwnode.h
> > > > +++ b/include/media/v4l2-fwnode.h
> > > > @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > > >   */
> > > >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > > >  
> 
> And I see here that the function is documented. One more reason to move
> kerneldoc to the .c files...

Please check my comment above.

> > > > +/**
> > > > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > > > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > > > + *          connected to
> 
> This is very unclear, I would interpret that as the remote endpoint, not
> the local endpoint. Could you please try to clarify the documentation ?

Hm.. I have no good idea how I should describe it..

"""
The device (local) endpoint fwnode handle on which the connector is
connected to using the remote-enpoint property.
"""

Regards,
  Marco

> > > > + * @connector: pointer to the V4L2 fwnode connector data structure
> > > > + *
> > > > + * Fill the connector data structure with the connector type, label and the
> > > > + * endpoint id and port where the connector belongs to. If no label is present
> > > > + * a unique one will be created. Labels with more than 40 characters are cut.
> > > > + *
> > > > + * Return: %0 on success or a negative error code on failure:
> > > > + *	   %-EINVAL on parsing failure
> > > > + */
> > > > +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > > > +				struct v4l2_fwnode_connector *connector);
> > > > +
> > > >  /**
> > > >   * typedef parse_endpoint_func - Driver's callback function to be called on
> > > >   *	each V4L2 fwnode endpoint.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-05-16 18:03     ` Laurent Pinchart
@ 2019-08-13  8:54       ` Marco Felsch
  2019-08-15 12:51         ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-13  8:54 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel

Hi Laurent,

On 19-05-16 21:03, Laurent Pinchart wrote:
> Hello Marco,
> 
> Thank you for the patch.
> 
> On Tue, May 14, 2019 at 03:25:45PM -0300, Mauro Carvalho Chehab wrote:
> > Em Mon, 15 Apr 2019 14:44:05 +0200 Marco Felsch escreveu:
> > 
> > > This patch adds the of_graph support to describe the tvp connections.
> > > Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> > > of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> > > connector must be conneted to port@0/endpoint@1, look at the Documentation
> 
> According to [2], it must be connected to port port@0 and port@1, not
> just port@0.

You're right. I missed that.. I will change that for the v7.

> > > for more information. Since the TVP5150 is a converter the device-tree
> > > must contain at least 1-input and 1-output port. The mc-connectors and
> > > mc-links are only created if the device-tree contains the corresponding
> > > connector nodes. If more than one connector is available the
> > > media_entity_operations.link_setup() callback ensures that only one
> > > connector is active.
> > > 
> > > [1] https://www.spinics.net/lists/linux-media/msg138545.html
> > > [2] https://www.spinics.net/lists/linux-media/msg138546.html
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > > Changelog:
> > > 
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > [2] https://patchwork.kernel.org/cover/10786553/
> > > 
> > > v6:
> > > - fix misspelled comments
> > > - use 'unsigned int' where it's possible
> > > - cleanup ifdef part-2:
> > >   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
> > >     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> > > - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
> > >   internal function do this.
> > > - tvp5150_add_of_connectors: call within probe() to make it cleaner
> > > - tvp5150_parse_dt: move local loop vars within the loop.
> > > 
> > > v5:
> > > - Fixing build deps:
> > >   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
> > >   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
> > >     includes. This leads into to complex deps for futher development.
> > >   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
> > >   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
> > >   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> > > 
> > > - Simplify link_setup routine:
> > >   - use generic connector parsing since both series [1,2] are squashed into
> > >     one
> > >   - struct tvp5150: drop pads_state and modify_second_link property
> > >     due to link_setup() rework.
> > >   - tvp5150_link_setup: add more comments
> > >   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
> > >     link directly within the driver instead of a recursive media-framework
> > >     call (__media_entity_setup_link). This improves the readability and
> > >     shrinks the driver code.
> > >   - tvp5150_link_setup: disable all active links in case user switches
> > >     connectors without disable it first.
> > >   - tvp5150_registered: simplify default link enable path due to link_setup()
> > >     rework.
> > > 
> > > - General cleanups
> > >   - tvp5150_parse_dt: drop unecessary test
> > >   - tvp5150_parse_dt: add err message due to misconfiguration
> > >   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
> > >   - s/dev_dbg/dev_dbg_lvl
> > > 
> > > v4:
> > >  - rebase on top of media_tree/master, fix merge conflict due to commit
> > >    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
> > >    to zero")
> > > 
> > > v3:
> > > - probe(): s/err/err_free_v4l2_ctrls
> > > - drop MC dependency for tvp5150_pads
> > > 
> > > v2:
> > > - adapt commit message
> > > - unify ifdef switches
> > > - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> > > - mc: use 2-input and 1-output pad
> > > - mc: link svideo connector to both input pads
> > > - mc: enable/disable svideo links in one go
> > > - mc: change link_setup() behaviour, switch the input src don't require a
> > >       explicite disable before.
> > > - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> > > - mc: enable link to the first available connector and set the
> > >       corresponding tvp5150 input src per default during registered()
> > > - mc/of: factor out oftree connector allocation
> > > - of: drop svideo dt port
> > > - of: move svideo connector to port@0/endpoint@1
> > > - of: require at least 1-in and 1-out endpoint
> > > 
> > >  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
> > >  1 file changed, 370 insertions(+), 39 deletions(-)
> > > 
> > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > index 89da921c8886..4e3228b2ccbc 100644
> > > --- a/drivers/media/i2c/tvp5150.c
> > > +++ b/drivers/media/i2c/tvp5150.c
> > > @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
> > >  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
> > >  
> > >  enum tvp5150_pads {
> > > -	TVP5150_PAD_IF_INPUT,
> > > +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> > > +	TVP5150_PAD_AIP1B,
> > >  	TVP5150_PAD_VID_OUT,
> > >  	TVP5150_NUM_PADS
> > >  };
> > >  
> > > +struct tvp5150_connector {
> > > +	struct v4l2_fwnode_connector base;
> > > +	struct media_entity ent;
> > > +	struct media_pad pad;
> > > +};
> > > +
> > >  struct tvp5150 {
> > >  	struct v4l2_subdev sd;
> > > -#ifdef CONFIG_MEDIA_CONTROLLER
> > > +	/* additional endpoint for the svideo connector */
> 
> Could you please capitalize the first word of all comments to match the
> driver style ?

Okay, I will check it for my v7.

> > > +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> 
> As the endpoints are only used at probe time, I would declare this as a
> local variable in the probe function and pass it to both
> tvp5150_add_of_connectors() and tvp5150_parse_dt(). If you order the
> calls correctly it should simplify the probe error handling.

Yes that could be also a solution. I took Jacopo's comments and
refactored the code so the endpoints no longer needed in my v7.

> > > +	unsigned int endpoints_num;
> > > +
> > > +	/* media-ctl properties */
> 
> media-ctl makes me think about the userspace application, maybe "Media
> controller properties" ?

I've dopped that comment becuase it is to obvious..

> > >  	struct media_pad pads[TVP5150_NUM_PADS];
> > > -#endif
> > > +	struct tvp5150_connector *connectors;
> > > +	int connectors_num;
> 
> unsigned int ?

Of course.

> > > +
> > >  	struct v4l2_ctrl_handler hdl;
> > >  	struct v4l2_rect rect;
> > >  	struct regmap *regmap;
> > > @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> > >  	return 0;
> > >  }
> > >  
> > > +/****************************************************************************
> > > + *			Media entity ops
> > > + ****************************************************************************/
> > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> 
> Should we depend on CONFIG_MEDIA_CONTROLLER instead, especially since
> you remove the similar conditional in the struct tvp5150 definition and
> in the probe function ?

I don't know if we can add the dependency without worries because the
tvp5150 is also used by the usb/em28xx devices which can be build
without CONFIG_MEDIA_CONTROLLER support. During .probe() a stub function
will be called if CONFIG_MEDIA_CONTROLLER isn't enabled.

> > > +static int tvp5150_set_link(struct media_pad *connector_pad,
> > > +			    struct media_pad *tvp5150_pad, u32 flags)
> > > +{
> > > +	struct media_link *link;
> > > +
> > > +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> > > +	if (!link)
> > > +		return -EINVAL;
> > > +
> > > +	link->flags = flags;
> > > +	link->reverse->flags = link->flags;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> > > +{
> > > +	struct media_pad *connector_pad;
> > > +	unsigned int i;
> > > +	int err;
> > > +
> > > +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > > +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> > > +		if (!connector_pad)
> > > +			continue;
> > > +
> > > +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> > > +		if (err)
> > > +			return err;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> > > +			     u32 config);
> > > +
> > > +static int tvp5150_link_setup(struct media_entity *entity,
> > > +			      const struct media_pad *tvp5150_pad,
> > > +			      const struct media_pad *remote, u32 flags)
> > > +{
> > > +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > +	struct media_pad *other_tvp5150_pad =
> > > +		&decoder->pads[tvp5150_pad->index ^ 1];
> > > +	bool is_svideo = false;
> > > +	unsigned int i;
> > > +	int err;
> > > +
> > > +	/*
> > > +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> > > +	 * Enabling or disabling the source pad link has no effect.
> > > +	 */
> > > +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> > > +		return 0;
> > > +
> > > +	/* Check if the svideo connector should be enabled */
> > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > +		if (remote->entity == &decoder->connectors[i].ent) {
> > 
> > > +			is_svideo =
> > > +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > 
> > Nitpick:
> > 
> > I would actually prefer to keep this on a single line. Ok, it will violate
> > the 80-columns, but it would be better than the above (IMHO).
> > 
> > > +			break;
> > > +		}
> > > +	}
> > > +
> > > +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> > > +		    remote->entity->name, remote->index,
> > > +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> > > +		    flags & MEDIA_LNK_FL_ENABLED);
> > > +	if (is_svideo)
> > > +		dev_dbg_lvl(sd->dev, 1, debug,
> > > +			    "link setup '%s':%d->'%s':%d[%d]",
> > > +			    remote->entity->name, remote->index,
> > > +			    other_tvp5150_pad->entity->name,
> > > +			    other_tvp5150_pad->index,
> > > +			    flags & MEDIA_LNK_FL_ENABLED);
> > > +
> > > +	/*
> > > +	 * The TVP5150 has an internal mux which allows the following setup:
> > > +	 *
> > > +	 * comp-connector1  --\
> > > +	 *		       |---> AIP1A
> > > +	 *		      /
> > > +	 * svideo-connector -|
> > > +	 *		      \
> > > +	 *		       |---> AIP1B
> > > +	 * comp-connector2  --/
> > > +	 *
> > > +	 * We can't rely on user space that the current connector gets disabled
> > > +	 * first before enabling the new connector. Disable all active
> > > +	 * connector links to be on the safe side.
> > > +	 */
> > > +	err = tvp5150_disable_all_input_links(decoder);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> > > +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> > > +			  TVP5150_BLACK_SCREEN, 0);
> > > +
> > > +	if (flags & MEDIA_LNK_FL_ENABLED) {
> > > +		/*
> > > +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > > +		 * Both links must be enabled in one-shot regardless which link
> > > +		 * the user requests.
> > > +		 */
> 
> This is a very grey area, I don't think the MC API explicitly allows
> doing this. As changing links during streaming is disallowed, wouldn't
> it be easier to handle the routing configuration at stream start ? You
> wouldn't have to deal with this issue then, you could just return an
> error if only one link is enabled. Furthermore, it would allow
> supporting a configuration where a composite signal is connected to the
> Y pin of the mini-DIN connector.

We discussed this a few series earlier because my first solution what
like this you describe above. I changed that because Mauro had some
concerns about the usability. Now this behaviour is easier to use but
as you pointed out above, such 'special' handling isn't doable anymore.
I would keep this solution since I want to get this series merged ;)
If someone wants such a 'special' configuration he can implement it
later.

> > > +		if (is_svideo) {
> > > +			err = tvp5150_set_link((struct media_pad *) remote,
> > > +					       other_tvp5150_pad, flags);
> > > +			if (err)
> > > +				return err;
> > > +		}
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct media_entity_operations tvp5150_sd_media_ops = {
> > > +	.link_setup = tvp5150_link_setup,
> > > +};
> > > +#endif
> > >  /****************************************************************************
> > >  			I2C Command
> > >   ****************************************************************************/
> > > @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> > >  	return 0;
> > >  }
> > >  
> > > +static int tvp5150_registered(struct v4l2_subdev *sd)
> > > +{
> > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > +	unsigned int i;
> > > +	int ret;
> > > +
> > > +	/*
> > > +	 * Setup connector pads and links. Enable the link to the first
> > > +	 * available connector per default.
> > > +	 */
> > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > +		struct media_entity *con = &decoder->connectors[i].ent;
> > > +		struct media_pad *pad = &decoder->connectors[i].pad;
> > > +		unsigned int port = decoder->connectors[i].base.remote_port;
> > > +		bool is_svideo =
> > > +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > > +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> 
> The flags passed to media_create_pad_link() are unsigned.

You are right, changed that.

> > > +
> > > +		pad->flags = MEDIA_PAD_FL_SOURCE;
> > > +		ret = media_entity_pads_init(con, 1, pad);
> > > +		if (ret < 0)
> > > +			return ret;
> > > +
> > > +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> > > +		if (ret < 0)
> > > +			return ret;
> > > +
> > > +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> > > +		if (ret < 0) {
> > > +			media_device_unregister_entity(con);
> > > +			return ret;
> > > +		}
> 
> Will the other registered media entities be unregistered correctly ?

Good point. I add a seperate error handling to ensure all registered
entities gets unregistered.

> > > +
> > > +		if (is_svideo) {
> > > +			/* svideo links to both aip1a and aip1b */
> > > +			ret = media_create_pad_link(con, 0, &sd->entity,
> > > +						    port + 1, flags);
> 
> Does the TVP5150 support both connecting Y to AIP1A and C to AIP1B, and
> Y to AIP1B and C to AIP1A ? If so the port + 1 won't always work.

No, if I understood the datasheet right Y is always connected to AIP1A
and C to AIP1B. Since I improved the struct v4l2_fwnode_connector to
hold more connector-port information the 'port+1' logic isn't used
anymore.

> > > +			if (ret < 0) {
> > > +				media_device_unregister_entity(con);
> > > +				return ret;
> > > +			}
> > > +		}
> > > +
> > > +		/* enable default input */
> > > +		if (flags == MEDIA_LNK_FL_ENABLED) {
> > > +			decoder->input =
> > > +				is_svideo ? TVP5150_SVIDEO :
> > > +				port == 0 ? TVP5150_COMPOSITE0 :
> > > +				TVP5150_COMPOSITE1;
> > > +
> > > +			tvp5150_selmux(sd);
> > > +		}
> 
> You could move this after the loop and operation on
> decoder->connectors[0]. Hopefully you could then use if's instead of
> nested ? : operators, as the above isn't very readable.

That's also doable. Mauro which solution do you prefer?

> > > +	}
> > > +#endif
> > > +	return 0;
> > > +}
> > > +
> > > +
> 
> One blank line is enough.

Fixed.

> > >  /* ----------------------------------------------------------------------- */
> > >  
> > >  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> > > @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
> > >  	.pad = &tvp5150_pad_ops,
> > >  };
> > >  
> > > +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> > > +	.registered = tvp5150_registered,
> > > +};
> > > +
> > >  /****************************************************************************
> > >  			I2C Client & Driver
> > >   ****************************************************************************/
> > > @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
> > >  	return 0;
> > >  }
> > >  
> > > -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > >  {
> > > -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> > > -	struct device_node *ep;
> > > -	unsigned int flags;
> > > -	int ret = 0;
> > > +	struct device *dev = decoder->sd.dev;
> 
> You use dev in a singla location, I think you could use decoder->sd.dev
> directly.

This function is no longer used but you're right.

> 
> > > +	struct tvp5150_connector *connectors;
> > > +	unsigned int connectors_num = decoder->connectors_num;
> > > +	int i, ret;
> 
> i is never negative, you can make it an unsiged int.
> 
> > >  
> > > -	ep = of_graph_get_next_endpoint(np, NULL);
> > > -	if (!ep)
> > > -		return -EINVAL;
> > > +	/*
> > > +	 * Only add of_connectors if device really is a OF device since
> > > +	 * the driver is used by usb devices e.g. em28xx and embedded
> > > +	 * devices.
> > > +	 */
> > > +	if (!decoder->connectors_num)
> 
> Maybe if (!connectors_num) ?
> 
> > > +		return 0;
> > >  
> > > -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> > > -	if (ret)
> > > -		goto err;
> > > +	/* Allocate and initialize all available input connectors */
> > > +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> > > +				  GFP_KERNEL);
> > > +	if (!connectors)
> > > +		return -ENOMEM;
> > > +
> > > +	for (i = 0; i < connectors_num; i++) {
> > > +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> > > +
> > > +		ret = v4l2_fwnode_parse_connector(
> > > +				   of_fwnode_handle(decoder->endpoints[i]), c);
> 
> I think you should handle errors here.
> 
> > > +
> > > +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> > > +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> > > +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> > > +		connectors[i].ent.name = c->label;
> 
> I don't think using the label as the entity name is a good idea, as we
> require entity names to be unique, and labels offer no such guarantee.

Good point. What about <connector dt-name>:<label>? The devicetree name
is unique.

> > > +	}
> > > +
> > > +	decoder->connectors = connectors;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int tvp5150_mc_init(struct tvp5150 *decoder)
> > > +{
> > > +	struct v4l2_subdev *sd = &decoder->sd;
> > > +	unsigned int i;
> > > +
> > > +	sd->entity.ops = &tvp5150_sd_media_ops;
> > > +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > +
> > > +	/* Initialize all TVP5150 pads */
> > > +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> > > +		if (i < TVP5150_NUM_PADS - 1) {
> > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > > +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > > +		} else {
> > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > > +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> > > +		}
> > > +	}
> 
> You can simplify this to
> 
> 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> 		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> 		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> 	}
> 
> 	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> 	decoder->pads[i].sig_type = PAD_SIGNAL_DV;

Yes, already done.

> > > +
> > > +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> > > +				      decoder->pads);
> > > +}
> > > +
> > > +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> > > +
> > > +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > > +{
> > > +	return 0;
> > > +}
> > >  
> > > -	flags = bus_cfg.bus.parallel.flags;
> > > +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> > > +{
> > > +	return 0;
> > > +}
> > > +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
> > >  
> > > -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > +{
> > > +	struct device *dev = decoder->sd.dev;
> > > +	struct device_node *ep_np;
> > > +	unsigned int i = 0, in = 0;
> 
> Let's rename in to num_inputs or num_connectors.

I refactored the code, so in is no longer used.

> > > +	int ret;
> > > +	bool found = false;
> > > +
> > > +	/* at least 1 output and 1 input */
> > > +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> > > +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> > > +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
> > >  		ret = -EINVAL;
> > >  		goto err;
> > >  	}
> > >  
> > > -	decoder->mbus_type = bus_cfg.bus_type;
> > > +	for_each_endpoint_of_node(np, ep_np) {
> > > +		struct v4l2_fwnode_endpoint bus_cfg = {
> > > +			.bus_type = V4L2_MBUS_UNKNOWN
> > > +		};
> > > +		struct v4l2_fwnode_connector c;
> > > +		struct of_endpoint ep;
> > > +		unsigned int flags;
> > > +
> > > +		of_graph_parse_endpoint(ep_np, &ep);
> > > +		switch (ep.port) {
> > > +		case TVP5150_PAD_AIP1A:
> > > +			/* fall through */
> 
> I don't think you need this comment.
> 
> > > +		case TVP5150_PAD_AIP1B:
> > > +			ret = v4l2_fwnode_parse_connector(
> > > +						   of_fwnode_handle(ep_np), &c);
> 
> You use of_fwnode_handle(ep_np) twice, you could move it outside of the
> switch () to keep lines shorter.
> 
> > > +			if (c.type != V4L2_CON_COMPOSITE &&
> > > +			    c.type != V4L2_CON_SVIDEO) {
> > > +				dev_err(dev,
> > > +					"Invalid endpoint %d on port %d\n",
> 
> The correct format specifier for unsigned int is %u.
> 
> Should the error message be more explicit ? "Invalid connector type for
> port@%u/endpoint@%u" ?
> 
> 
> > > +					c.remote_id, c.remote_port);
> > > +				ret = -EINVAL;
> > > +				goto err;
> 
> If you break out of the loop you need an of_node_put(ep_np).
> Alternatively, you could store ep_np in the endpoints array right before
> of_graph_parse_endpoint() and call of_node_put() right after
> of_graph_parse_endpoint().
> 
> > > +			}
> > > +			in++;
> > > +			break;
> > > +		case TVP5150_PAD_VID_OUT:
> > > +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> > > +							 &bus_cfg);
> > > +			if (ret)
> > > +				goto err;
> > > +
> > > +			flags = bus_cfg.bus.parallel.flags;
> > > +
> > > +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > +				ret = -EINVAL;
> > > +				goto err;
> > > +			}
> > > +
> > > +			decoder->mbus_type = bus_cfg.bus_type;
> > > +			break;
> > > +		default:
> > > +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> 
> %u here too.
> 
> > > +				ep.port, ep.local_node);
> > > +			ret = -EINVAL;
> > > +			goto err;
> > > +		}
> > > +
> > > +		of_node_get(ep_np);
> > > +		decoder->endpoints[i] = ep_np;
> > > +		i++;
> > > +
> > > +		found = true;
> > > +	}
> > >  
> > > +	decoder->connectors_num = in;
> > > +	return found ? 0 : -ENODEV;
> > >  err:
> > > -	of_node_put(ep);
> > >  	return ret;
> 
> You can remove the err label and return ret directly.

I took your comments into account for the refactored function, thanks.

Regards,
  Marco

> 
> > >  }
> > >  
> > > +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> > > +{
> > > +	unsigned int i;
> > > +
> > > +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> > > +		of_node_put(decoder->endpoints[i]);
> > > +}
> > > +
> > >  static const char * const tvp5150_test_patterns[2] = {
> > >  	"Disabled",
> > >  	"Black screen"
> > > @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > >  		res = tvp5150_parse_dt(core, np);
> > >  		if (res) {
> > >  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> > > -			return res;
> > > +			goto err_cleanup_dt;
> > >  		}
> > >  	} else {
> > >  		/* Default to BT.656 embedded sync */
> > > @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
> > >  	}
> > >  
> > >  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > > +	sd->internal_ops = &tvp5150_internal_ops;
> > >  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > >  
> > > -#if defined(CONFIG_MEDIA_CONTROLLER)
> > > -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> > > -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> > > -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> > > -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> > > -
> > > -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > -
> > > -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> > > -	if (res < 0)
> > > -		return res;
> > > +	res = tvp5150_mc_init(core);
> > > +	if (res)
> > > +		goto err_cleanup_dt;
> > >  
> > > -#endif
> > > +	res = tvp5150_add_of_connectors(core);
> > > +	if (res)
> > > +		goto err_cleanup_dt;
> > >  
> > >  	res = tvp5150_detect_version(core);
> > >  	if (res < 0)
> > > -		return res;
> > > +		goto err_cleanup_dt;
> > >  
> > >  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > > @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > >  	sd->ctrl_handler = &core->hdl;
> > >  	if (core->hdl.error) {
> > >  		res = core->hdl.error;
> > > -		goto err;
> > > +		goto err_free_v4l2_ctrls;
> > >  	}
> > >  
> > >  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> > > @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
> > >  						tvp5150_isr, IRQF_TRIGGER_HIGH |
> > >  						IRQF_ONESHOT, "tvp5150", core);
> > >  		if (res)
> > > -			goto err;
> > > +			goto err_free_v4l2_ctrls;
> > >  	}
> > >  
> > >  	res = v4l2_async_register_subdev(sd);
> > >  	if (res < 0)
> > > -		goto err;
> > > +		goto err_free_v4l2_ctrls;
> > >  
> > >  	if (debug > 1)
> > >  		tvp5150_log_status(sd);
> > > +
> > >  	return 0;
> > >  
> > > -err:
> > > +err_free_v4l2_ctrls:
> > >  	v4l2_ctrl_handler_free(&core->hdl);
> > > +err_cleanup_dt:
> > > +	if (IS_ENABLED(CONFIG_OF) && np)
> > > +		tvp5150_dt_cleanup(core);
> > > +
> > >  	return res;
> > >  }
> > >  
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings
  2019-05-16 18:05   ` Laurent Pinchart
@ 2019-08-13  8:56     ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-13  8:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Laurent,

On 19-05-16 21:05, Laurent Pinchart wrote:
> Hi Marco,
> 
> Thank you for the patch.
> 
> On Mon, Apr 15, 2019 at 02:44:06PM +0200, Marco Felsch wrote:
> > The TVP5150/1 decoders support different video input sources to their
> > AIP1A/B pins.
> > 
> > Possible configurations are as follows:
> >   - Analog Composite signal connected to AIP1A.
> >   - Analog Composite signal connected to AIP1B.
> >   - Analog S-Video Y (luminance) and C (chrominance)
> >     signals connected to AIP1A and AIP1B respectively.
> > 
> > This patch extends the device tree bindings documentation to describe
> > how the input connectors for these devices should be defined in a DT.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > ---
> > Changelog:
> > 
> > v3:
> > - remove examples for one and two inputs
> > - replace space by tabs
> > 
> > v2:
> > - adapt port layout in accordance with
> >   https://www.spinics.net/lists/linux-media/msg138546.html with the
> >   svideo-connector deviation (use only one endpoint)
> 
> As far as I understand the above link, you need two endpoints.
> 
> tvp-5150 port@0 (AIP1A)
> 	endpoint@0 -----------> Comp0-Con  port
> 	endpoint@1 -----+-----> Svideo-Con port
> tvp-5150 port@1	(AIP1B) |
> 	endpoint@1 -----+
> 	endpoint@0 -----------> Comp1-Con  port
> tvp-5150 port@2
> 	endpoint (video bitstream output at YOUT[0-7] parallel bus)
> 
> The configuration below isn't accepted.

You're right. I changed that.

> 
> >  .../devicetree/bindings/media/i2c/tvp5150.txt | 92 +++++++++++++++++--
> >  1 file changed, 85 insertions(+), 7 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> > index 8c0fc1a26bf0..bdd273d8b44d 100644
> > --- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> > +++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
> > @@ -12,11 +12,31 @@ Optional Properties:
> >  - pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
> >  - reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
> >  
> > -The device node must contain one 'port' child node for its digital output
> > -video port, in accordance with the video interface bindings defined in
> > -Documentation/devicetree/bindings/media/video-interfaces.txt.
> > +The device node must contain one 'port' child node per device physical input
> > +and output port, in accordance with the video interface bindings defined in
> > +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
> > +are numbered as follows
> >  
> > -Required Endpoint Properties for parallel synchronization:
> > +	  Name		Type		Port
> > +	--------------------------------------
> > +	  AIP1A		sink		0
> > +	  AIP1B		sink		1
> > +	  Y-OUT		src		2
> > +
> > +The device node must contain at least one sink port and the src port. Each input
> > +port must be linked to an endpoint defined in
> > +Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
> > +port/connector layout is as follows
> > +
> > +tvp-5150 port@0 (AIP1A)
> > +	endpoint@0 -----------> Comp0-Con  port
> > +	endpoint@1 -----------> Svideo-Con port
> > +tvp-5150 port@1 (AIP1B)
> > +	endpoint   -----------> Comp1-Con  port
> > +tvp-5150 port@2
> > +	endpoint (video bitstream output at YOUT[0-7] parallel bus)
> > +
> > +Required Endpoint Properties for parallel synchronization on output port:
> >  
> >  - hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
> >  - vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
> > @@ -26,17 +46,75 @@ Required Endpoint Properties for parallel synchronization:
> >  If none of hsync-active, vsync-active and field-even-active is specified,
> >  the endpoint is assumed to use embedded BT.656 synchronization.
> >  
> > -Example:
> > +Example - three input sources:
> > +
> > +comp_connector_0 {
> > +	compatible = "composite-video-connector";
> > +	label = "Composite0";
> > +
> > +	port {
> > +		composite0_to_tvp5150: endpoint {
> > +			remote-endpoint = <&tvp5150_to_composite0>;
> > +		};
> > +	};
> > +};
> > +
> > +comp_connector_1 {
> > +	compatible = "composite-video-connector";
> > +	label = "Composite1";
> > +
> > +	port {
> > +		composite1_to_tvp5150: endpoint {
> > +			remote-endpoint = <&tvp5150_to_composite1>;
> > +		};
> > +	};
> > +};
> > +
> > +svid_connector {
> > +	compatible = "svideo-connector";
> > +	label = "S-Video";
> > +
> > +	port {
> > +		svideo_to_tvp5150: endpoint {
> > +			remote-endpoint = <&tvp5150_to_svideo>;
> > +		};
> > +	};
> > +};
> >  
> >  &i2c2 {
> > -	...
> >  	tvp5150@5c {
> >  		compatible = "ti,tvp5150";
> >  		reg = <0x5c>;
> >  		pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
> >  		reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
> >  
> > -		port {
> > +		port@0 {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +			reg = <0>;
> > +
> > +			tvp5150_to_composite0: endpoint@0 {
> > +				reg = <0>;
> > +				remote-endpoint = <&composite0_to_tvp5150>;
> > +			};
> > +
> > +			tvp5150_to_svideo: endpoint@1 {
> > +				reg = <1>;
> > +				remote-endpoint = <&svideo_to_tvp5150>;
> > +			};
> > +		};
> > +
> > +		port@1 {
> > +			reg = <1>;
> > +
> > +			tvp5150_to_composite1: endpoint {
> > +                                remote-endpoint = <&composite1_to_tvp5150>;
> > +			};
> > +		};
> > +
> > +		port@2 {
> > +			reg = <2>;
> > +
> >  			tvp5150_1: endpoint {
> >  				remote-endpoint = <&ccdc_ep>;
> >  			};
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector
  2019-05-16 18:07   ` Laurent Pinchart
@ 2019-08-13  9:10     ` Marco Felsch
  2019-08-15 12:53       ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-13  9:10 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel

Hi Laurent,

On 19-05-16 21:07, Laurent Pinchart wrote:
> Hi Marco,
> 
> Thank you for the patch.
> 
> On Mon, Apr 15, 2019 at 02:44:12PM +0200, Marco Felsch wrote:
> > The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
> > data and is able to auto-detect the input signal. The auto-detection
> > does not work if the connector does not receive an input signal and the
> > tvp5150 might not be configured correctly. This misconfiguration leads
> > into wrong decoded video streams if the tvp5150 gets powered on before
> > the video signal is present.
> > 
> > Limit the supported tv norms according to the actual selected connector
> > to avoid a misconfiguration.
> 
> This seems a bit of a hack to me. In particular, on what grounds would
> you specify a particular configuration in DT ? Also, this issue affects
> non-DT systems, and should be solved globally.

Why is this a hack? Imagine a hardware which supports PAL signals only.
Then it should be forbidden for the user space to configure it to SECAM
or any NTSC. Since the hardware makes the limitation it should be
abstracted on DT level.

Regards,
  Marco

> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v5:
> > - probe() initialize supported tv-norms according the given connectors
> >   if they are available.
> > - check if media-controller is used. Don't limit the norm if it isn't
> >   used.
> > - add more logic to be smarter during connector changing so it is
> >   intuitiver for the user space.
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > 
> >  drivers/media/i2c/tvp5150.c | 69 +++++++++++++++++++++++++++++++++++--
> >  1 file changed, 67 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index cd54715eb641..c0ee08546643 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -32,6 +32,13 @@
> >  #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
> >  #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
> >  #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
> > +#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
> > +				 V4L2_STD_NTSC_443 | \
> > +				 V4L2_STD_PAL      | \
> > +				 V4L2_STD_PAL_M    | \
> > +				 V4L2_STD_PAL_N    | \
> > +				 V4L2_STD_PAL_Nc   | \
> > +				 V4L2_STD_SECAM)
> >  
> >  MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
> >  MODULE_AUTHOR("Mauro Carvalho Chehab");
> > @@ -66,6 +73,7 @@ struct tvp5150 {
> >  	/* media-ctl properties */
> >  	struct media_pad pads[TVP5150_NUM_PADS];
> >  	struct tvp5150_connector *connectors;
> > +	struct tvp5150_connector *cur_connector;
> >  	int connectors_num;
> >  
> >  	struct v4l2_ctrl_handler hdl;
> > @@ -785,17 +793,28 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
> >  static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
> >  {
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	struct tvp5150_connector *cur_con = decoder->cur_connector;
> > +	v4l2_std_id supported_norms = cur_con ?
> > +		cur_con->base.connector.analog.supported_tvnorms : V4L2_STD_ALL;
> >  
> >  	if (decoder->norm == std)
> >  		return 0;
> >  
> > +	/*
> > +	 * check if requested std or group of std's is/are supported by the
> > +	 * connector
> > +	 */
> > +	if ((supported_norms & std) == 0)
> > +		return -EINVAL;
> > +
> >  	/* Change cropping height limits */
> >  	if (std & V4L2_STD_525_60)
> >  		decoder->rect.height = TVP5150_V_MAX_525_60;
> >  	else
> >  		decoder->rect.height = TVP5150_V_MAX_OTHERS;
> >  
> > -	decoder->norm = std;
> > +	/* set only the specific supported std in case of group of std's */
> > +	decoder->norm = supported_norms & std;
> >  
> >  	return tvp5150_set_std(sd, std);
> >  }
> > @@ -1347,6 +1366,8 @@ static int tvp5150_link_setup(struct media_entity *entity,
> >  			  TVP5150_BLACK_SCREEN, 0);
> >  
> >  	if (flags & MEDIA_LNK_FL_ENABLED) {
> > +		u32 new_norm;
> > +
> >  		/*
> >  		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> >  		 * Both links must be enabled in one-shot regardless which link
> > @@ -1358,6 +1379,26 @@ static int tvp5150_link_setup(struct media_entity *entity,
> >  			if (err)
> >  				return err;
> >  		}
> > +
> > +		/* Update the current connector */
> > +		decoder->cur_connector =
> > +			container_of(remote, struct tvp5150_connector, pad);
> > +
> > +		/*
> > +		 * Do nothing if the new connector supports the same tv-norms as
> > +		 * the old one.
> > +		 */
> > +		new_norm = decoder->norm &
> > +			decoder->cur_connector->base.connector.analog.supported_tvnorms;
> > +		if (decoder->norm == new_norm)
> > +			return 0;
> > +
> > +		/*
> > +		 * Fallback to the new connector tv-norms if we can't find any
> > +		 * common between the current tv-norm and the new one.
> > +		 */
> > +		tvp5150_s_std(sd, new_norm ? new_norm :
> > +			decoder->cur_connector->base.connector.analog.supported_tvnorms);
> >  	}
> >  
> >  	return 0;
> > @@ -1576,6 +1617,9 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
> >  				TVP5150_COMPOSITE1;
> >  
> >  			tvp5150_selmux(sd);
> > +			decoder->cur_connector = &decoder->connectors[i];
> > +			tvp5150_s_std(sd,
> > +				decoder->connectors[i].base.connector.analog.supported_tvnorms);
> >  		}
> >  	}
> >  #endif
> > @@ -1903,6 +1947,11 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> >  				ret = -EINVAL;
> >  				goto err;
> >  			}
> > +			if (!(c.connector.analog.supported_tvnorms &
> > +			    TVP5150_STD_MASK))
> > +				dev_warn(dev,
> > +					"Unsupported tv-norm on connector %s.\n",
> > +					c.label);
> >  			in++;
> >  			break;
> >  		case TVP5150_PAD_VID_OUT:
> > @@ -2011,7 +2060,23 @@ static int tvp5150_probe(struct i2c_client *c,
> >  	if (res < 0)
> >  		goto err_cleanup_dt;
> >  
> > -	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > +	/*
> > +	 * Iterate over all available connectors in case they are supported and
> > +	 * successfully parsed. Fallback to default autodetect in case they
> > +	 * aren't supported.
> > +	 */
> > +	if (core->connectors) {
> > +		struct v4l2_fwnode_connector *con;
> > +		int i;
> > +
> > +		for (i = 0; i < core->connectors_num; i++) {
> > +			con = &core->connectors[i].base;
> > +			core->norm |= con->connector.analog.supported_tvnorms;
> > +		}
> > +	} else {
> > +		core->norm = V4L2_STD_ALL;
> > +	}
> > +
> >  	core->detected_norm = V4L2_STD_UNKNOWN;
> >  	core->input = TVP5150_COMPOSITE1;
> >  	core->enable = true;
> > -- 
> > 2.20.1
> > 
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-08-09  5:58     ` Marco Felsch
@ 2019-08-15 12:33       ` Laurent Pinchart
  2019-08-15 12:50         ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 12:33 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Marco,

On Fri, Aug 09, 2019 at 07:58:09AM +0200, Marco Felsch wrote:
> On 19-05-16 19:27, Laurent Pinchart wrote:
> > On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> > > Some connectors no matter if in- or output supports only a limited
> > > range of tv norms. It doesn't matter if the hardware behind that
> > > connector supports more than the listed formats since the users are
> > > restriced by a label e.g. to plug only a camera into this connector
> > > which uses the PAL format.
> > > 
> > > This patch adds the capability to describe such limitation within the
> > > firmware. There are no format restrictions if the property isn't
> > > present, so it's completely backward compatible.
> > 
> > Why is this needed ? It's not really a hardware property, is it ? What's
> > the use case ?
> 
> Cause some hardware only support a limited range of formats to that
> connector. Of course it is a hardware property. For example if a
> customer wants to limit a connector to a specifc norm because the
> hardware behind that connector only supports that format or is
> restricted to that format.

Then it should be a DT property of the hardware behind that connector
(or information hardcoded directly into that driver), shouldn't it ?

> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Rob Herring <robh@kernel.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v6:
> > > - tvnorms.h: use tabs instead of spaces
> > > - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > > - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  .../display/connector/analog-tv-connector.txt |  4 ++
> > >  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> > >  2 files changed, 60 insertions(+)
> > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > > 
> > > diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > index 0c0970c210ab..346f8937a0b7 100644
> > > --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > @@ -6,6 +6,9 @@ Required properties:
> > >  
> > >  Optional properties:
> > >  - label: a symbolic name for the connector
> > > +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > > +           all tv norms are allowed. Possible video standards are defined in
> > > +           include/dt-bindings/media/tvnorms.h.
> > >  
> > >  Required nodes:
> > >  - Video port for TV input
> > > @@ -16,6 +19,7 @@ Example
> > >  tv: connector {
> > >  	compatible = "composite-video-connector";
> > >  	label = "tv";
> > > +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> > >  
> > >  	port {
> > >  		tv_connector_in: endpoint {
> > > diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > > new file mode 100644
> > > index 000000000000..058ab8414145
> > > --- /dev/null
> > > +++ b/include/dt-bindings/media/tvnorms.h
> > > @@ -0,0 +1,56 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > > +/*
> > > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > > + */
> > > +
> > > +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > > +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > > +
> > > +/* one bit for each */
> > > +#define TVNORM_PAL_B		0x00000001
> > > +#define TVNORM_PAL_B1		0x00000002
> > > +#define TVNORM_PAL_G		0x00000004
> > > +#define TVNORM_PAL_H		0x00000008
> > > +#define TVNORM_PAL_I		0x00000010
> > > +#define TVNORM_PAL_D		0x00000020
> > > +#define TVNORM_PAL_D1		0x00000040
> > > +#define TVNORM_PAL_K		0x00000080
> > > +
> > > +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > > +				 TVNORM_PAL_B1 | \
> > > +				 TVNORM_PAL_G  | \
> > > +				 TVNORM_PAL_H  | \
> > > +				 TVNORM_PAL_I  | \
> > > +				 TVNORM_PAL_D  | \
> > > +				 TVNORM_PAL_D1 | \
> > > +				 TVNORM_PAL_K)
> > > +
> > > +#define TVNORM_PAL_M		0x00000100
> > > +#define TVNORM_PAL_N		0x00000200
> > > +#define TVNORM_PAL_Nc		0x00000400
> > > +#define TVNORM_PAL_60		0x00000800
> > > +
> > > +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > > +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > > +#define TVNORM_NTSC_443		0x00004000
> > > +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > > +
> > > +#define TVNORM_SECAM_B		0x00010000
> > > +#define TVNORM_SECAM_D		0x00020000
> > > +#define TVNORM_SECAM_G		0x00040000
> > > +#define TVNORM_SECAM_H		0x00080000
> > > +#define TVNORM_SECAM_K		0x00100000
> > > +#define TVNORM_SECAM_K1		0x00200000
> > > +#define TVNORM_SECAM_L		0x00400000
> > > +#define TVNORM_SECAM_LC		0x00800000
> > > +
> > > +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > > +				 TVNORM_SECAM_D  | \
> > > +				 TVNORM_SECAM_G  | \
> > > +				 TVNORM_SECAM_H  | \
> > > +				 TVNORM_SECAM_K  | \
> > > +				 TVNORM_SECAM_K1 | \
> > > +				 TVNORM_SECAM_L  | \
> > > +				 TVNORM_SECAM_LC)
> > > +
> > > +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-08-09  7:55     ` Marco Felsch
@ 2019-08-15 12:38       ` Laurent Pinchart
  2019-08-15 13:04         ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 12:38 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Marco,

On Fri, Aug 09, 2019 at 09:55:36AM +0200, Marco Felsch wrote:
> On 19-05-16 19:36, Laurent Pinchart wrote:
> > On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> > > Currently every driver needs to parse the connector endpoints by it self.
> > 
> > s/it self/itself/
> > 
> > > This is the initial work to make this generic. The generic connector has
> > > some common fields and some connector specific parts. The generic one
> > > includes:
> > >   - type
> > >   - label
> > >   - remote_port (the port where the connector is connected to)
> > >   - remote_id   (the endpoint where the connector is connected to)
> > 
> > This assumes a single connection between a connector and a remote port,
> > and a single port on the connector side. Is this guaranteed ? For the
> > mini-DIN-4 connectors (often used for S-Video) for instance, I recall
> > from the extensive discussions we had in the past that they should be
> > modeled with two pins, one for the Y component and one for C components.
> > The rationale for this is to support systems where such a connector
> > could be used to carry S-Video, but also two composite video signals
> > (usually through an external adapter from 2 RCA female connectors to one
> > S-Video male connector) that would be routed to two separate video
> > decoders (or two different inputs of the same video decoder). Other
> > topologies may be possible too.
> 
> I got your concerns and I also remember the tvp5150 port bindings
> myself in the past. Do you know how often such a setup you described
> above happens these days? I would rather add more documentation to the
> bindings [1] and add a check to v4l2_fwnode_parse_connector() to
> guarantee that one port has only one endpoint. Because I don't think
> that analog connectors has a bright future these days.
> 
> [1] Documentation/devicetree/bindings/display/connector/ \
>     analog-tv-connector.txt

I have seen it on older hardware, I don't know about more recent
systems. For the S-Video case at least, you need to support two DT
ports, even if you don't support connecting them to two different
devices yet.

In any case, I'm fine if those topologies are not supported yet, but it
should be possible to support them in a backward-compatible way. In
particular, in this case, we should make sure the DT bindings will allow
such topologies, and the DT parsing API should make it possible to
support them without fugure changes to drivers that use the API from
this patch for "simple" topologies.

> > > The specific fields are within a union, since only one of them can be
> > > available at the time. Since this is the initial support the patch adds
> > > only the analog-connector specific ones.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v6:
> > > - fix some spelling and style issues
> > > - rm unnecessary comments
> > > - drop vga and dvi connector
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> > >  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> > >  2 files changed, 63 insertions(+)
> > >  create mode 100644 include/media/v4l2-connector.h
> > > 
> > > diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > > new file mode 100644
> > > index 000000000000..3a951c54f50e
> > > --- /dev/null
> > > +++ b/include/media/v4l2-connector.h
> > > @@ -0,0 +1,30 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +/*
> > > + * v4l2-connector.h
> > > + *
> > > + * V4L2 connector types.
> > > + *
> > > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > > + */
> > > +
> > > +#ifndef V4L2_CONNECTOR_H
> > > +#define V4L2_CONNECTOR_H
> > > +
> > > +#define V4L2_CONNECTOR_MAX_LABEL 41
> > 
> > Hans pointed out this was a weird number. Should you turn the label
> > field into a pointer to make this more generic (with a
> > v4l2_fwnode_connector_cleanup() function then) ?
> 
> Yes, that would be the better approach. I will change that.
> 
> > > +
> > > +/**
> > > + * enum v4l2_connector_type - connector type
> > > + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> > > + * @V4L2_CON_COMPOSITE: analog composite connector
> > > + * @V4L2_CON_SVIDEO:    analog svideo connector
> > > + * @V4L2_CON_HDMI:      digital hdmi connector
> > > + */
> > > +enum v4l2_connector_type {
> > > +	V4L2_CON_UNKNOWN,
> > > +	V4L2_CON_COMPOSITE,
> > > +	V4L2_CON_SVIDEO,
> > > +	V4L2_CON_HDMI,
> > > +};
> > > +
> > > +#endif /* V4L2_CONNECTOR_H */
> > > +
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index 6c07825e18b9..f4df1b95c5ef 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -22,6 +22,7 @@
> > >  #include <linux/list.h>
> > >  #include <linux/types.h>
> > >  
> > > +#include <media/v4l2-connector.h>
> > >  #include <media/v4l2-mediabus.h>
> > >  #include <media/v4l2-subdev.h>
> > >  
> > > @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> > >  	unsigned int remote_port;
> > >  };
> > >  
> > > +/**
> > > + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > > + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > > + *                     if no restrictions are specified.
> > > + */
> > > +struct v4l2_fwnode_connector_analog {
> > > +	v4l2_std_id supported_tvnorms;
> > > +};
> > > +
> > > +/**
> > > + * struct v4l2_fwnode_connector - the connector data structure
> > > + * @remote_port: identifier of the remote endpoint port the connector connects
> > > + *		 to
> > > + * @remote_id: identifier of the remote endpoint the connector connects to
> > > + * @label: connetor label
> > > + * @type: connector type
> > > + * @connector: connector configuration
> > > + * @connector.analog: analog connector configuration
> > > + *                    &struct v4l2_fwnode_connector_analog
> > > + */
> > > +struct v4l2_fwnode_connector {
> > > +	unsigned int remote_port;
> > > +	unsigned int remote_id;
> > > +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > > +	enum v4l2_connector_type type;
> > > +
> > > +	union {
> > > +		struct v4l2_fwnode_connector_analog analog;
> > > +		/* future connectors */
> > > +	} connector;
> > > +};
> > > +
> > >  /**
> > >   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> > >   * @fwnode: pointer to the endpoint's fwnode handle

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-08-09 12:16         ` Marco Felsch
@ 2019-08-15 12:48           ` Laurent Pinchart
  2019-08-15 13:14             ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 12:48 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Hans Verkuil, Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel,
	Jacopo Mondi

Hi Marco,

On Fri, Aug 09, 2019 at 02:16:06PM +0200, Marco Felsch wrote:
> On 19-05-16 19:51, Laurent Pinchart wrote:
> > On Tue, May 14, 2019 at 03:20:04PM -0300, Mauro Carvalho Chehab wrote:
> >> Em Mon, 6 May 2019 12:10:41 +0200 Hans Verkuil escreveu:
> >>> On 4/15/19 2:44 PM, Marco Felsch wrote:
> >>>> The patch adds the initial connector parsing code, so we can move from a
> >>>> driver specific parsing code to a generic one. Currently only the
> >>>> generic fields and the analog-connector specific fields are parsed. Parsing
> >>>> the other connector specific fields can be added by a simple callbacks.
> >>>> 
> >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> >>>> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>> ---
> >>>> [1] https://patchwork.kernel.org/cover/10794703/
> >>>> 
> >>>> v6:
> >>>> - use 'unsigned int' count var
> >>>> - fix comment and style issues
> >>>> - place '/* fall through */' to correct places
> >>>> - fix error handling and cleanup by releasing fwnode
> >>>> - drop vga and dvi parsing support as those connectors are rarely used
> >>>>   these days
> >>>> 
> >>>> v5:
> >>>> - s/strlcpy/strscpy/
> >>>> 
> >>>> v2-v4:
> >>>> - nothing since the patch was squashed from series [1] into this
> >>>>   series.
> >>>> 
> >>>>  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> >>>>  include/media/v4l2-fwnode.h           |  16 ++++
> >>>>  2 files changed, 127 insertions(+)
> >>>> 
> >>>> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> >>>> index 20571846e636..f1cca95c8fef 100644
> >>>> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> >>>> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> >>>> @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> >>>>  }
> >>>>  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> >>>>  
> >>>> +static const struct v4l2_fwnode_connector_conv {
> >>>> +	enum v4l2_connector_type type;
> >>>> +	const char *name;
> > 
> > Maybe compatible instead of name ?
> 
> Okay, I can change that.
> 
> >>>> +} connectors[] = {
> >>>> +	{
> >>>> +		.type = V4L2_CON_COMPOSITE,
> >>>> +		.name = "composite-video-connector",
> >>>> +	}, {
> >>>> +		.type = V4L2_CON_SVIDEO,
> >>>> +		.name = "svideo-connector",
> >>>> +	}, {
> >>>> +		.type = V4L2_CON_HDMI,
> >>>> +		.name = "hdmi-connector",
> >>>> +	},
> >>>> +};
> >>>> +
> >>>> +static enum v4l2_connector_type
> >>>> +v4l2_fwnode_string_to_connector_type(const char *con_str)
> >>>> +{
> >>>> +	unsigned int i;
> >>>> +
> >>>> +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> >>>> +		if (!strcmp(con_str, connectors[i].name))
> >>>> +			return connectors[i].type;
> >>>> +
> >>>> +	/* no valid connector found */
> > 
> > The usual comment style in this file is to start with a capital letter
> > and end sentences with a period. I would however drop this comment, it's
> > not very useful. The other comments should be updated accordingly.
> 
> I will change my comments and drop this one.
> 
> >>>> +	return V4L2_CON_UNKNOWN;
> >>>> +}
> >>>> +
> >>>> +static int
> >>>> +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> >>>> +				   struct v4l2_fwnode_connector *vc)
> >>>> +{
> >>>> +	u32 tvnorms;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> >>>> +
> >>>> +	/* tvnorms is optional */
> >>>> +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> > 
> > Please document all exported functions with kerneldoc.
> 
> It is documented within the header file. To be aligned with the other
> functions I wouldn't change that.

It's not your fault, but this policy REALLY makes review painful and is
EXTREMELY annoying.

> >>>> +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> >>>> +				struct v4l2_fwnode_connector *connector)
> >>>> +{
> >>>> +	struct fwnode_handle *fwnode;
> >>>> +	struct fwnode_endpoint __ep;
> >>>> +	const char *c_type_str, *label;
> >>>> +	int ret;
> >>>> +
> >>>> +	memset(connector, 0, sizeof(*connector));
> >>>> +
> >>>> +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> > 
> > I would rename the argument __fwnode to fwnode, and rename the fwnode
> > variable to remote (or similar) to make this clearer.
> 
> Okay.
> 
> >>>> +	if (!fwnode)
> >>>> +		return -EINVAL;
> > 
> > Is EINVAL the right error here ? Wouldn't it be useful for the caller to
> > differentiate between unconnected connector nodes and invalid ones ?
> 
> Yes it would. Should I return ENOLINK instead?

Good idea.

> >>>> +
> >>>> +	/* parse all common properties first */
> >>>> +	/* connector-type is stored within the compatible string */
> >>>> +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> > 
> > Prefixing or postfixing names with types is usually frowned upon. You
> > could rename this to type_name for instance.
> 
> Okay.
> 
> >>>> +	if (ret) {
> >>>> +		fwnode_handle_put(fwnode);
> >>>> +		return -EINVAL;
> >>>> +	}
> >>>> +
> >>>> +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> >>>> +
> >>>> +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> >>>> +	connector->remote_port = __ep.port;
> >>>> +	connector->remote_id = __ep.id;
> >>>> +
> >>>> +	ret = fwnode_property_read_string(fwnode, "label", &label);
> >>>> +	if (!ret) {
> >>>> +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> >>>> +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> >>>> +	} else {
> >>>> +		/*
> >>>> +		 * labels are optional, if none is given create one:
> >>>> +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> >>>> +		 */
> >>>> +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> >>>> +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> >>>> +			 connector->remote_id);
> > 
> > Should we really try to create labels when none is available ? If so
> > this needs much more careful thoughts, we need to think about what the
> > label will be used for, and create a good naming scheme accordingly. If
> > the label will be displayed to the end-user I don't think the above name
> > would be very useful, it would be best to leave it empty and let
> > applications create a name based on the connector type and other
> > information they have at their disposal.
> 
> Hm.. I don't have a strong opinion on that. If the others are with you I
> will leave it empty.
> 
> >>>> +	}
> >>>> +
> >>>> +	/* now parse the connector specific properties */
> >>>> +	switch (connector->type) {
> >>>> +	case V4L2_CON_COMPOSITE:
> >>>> +		/* fall through */
> > 
> > I don't think you need a fall-through comment when the two cases are
> > adjacent with no line in-between.
> 
> Hm.. I don't know the compiler behaviour. According the official
> gcc documentation [1] I would not leave that.

Not leave the fall-through comment, and thus remove it ? :-) I really
think it's not needed (otherwise imagine how the big switch-case in
v4l2-ctrls.c would look like for instance).

> [1] https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
> 
> >>>> +	case V4L2_CON_SVIDEO:
> >>>> +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> >>>> +		break;
> >>>> +	case V4L2_CON_HDMI:
> >>>> +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> >>>> +			c_type_str);  
> >>> 
> >>> Why warn? Just drop this.
> >> 
> >> good point. I would prefer to have some warning here, in order to warn a
> >> developer that might be using it that this part of the code would require 
> >> some change.
> >> 
> >> perhaps pr_warn_once()?
> >>
> >>>> +		ret = 0;
> >>>> +		break;
> > 
> > If it's not supported we should warn and return an error. Otherwise we
> > should be silent and return success. Combining a warning with success
> > isn't a good idea, this is either a normal case or an error, not both.
> 
> The generic part still applies and is valid. That was the reason why I
> did return success.

But the HDMI-specific part won't work, so the code will likely not
operate correctly. I'd rather make it an error to for developers using
HDMI connectors to fix it.

> >>>> +	case V4L2_CON_UNKNOWN:
> >>>> +		/* fall through */
> >>>> +	default:
> >>>> +		pr_err("Unknown connector type\n");
> >>>> +		ret = -EINVAL;
> >>>> +	};
> >>>> +
> >>>> +	fwnode_handle_put(fwnode);
> >>>> +
> >>>> +	return ret;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> >>>> +
> >>>>  static int
> >>>>  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> >>>>  					  struct v4l2_async_notifier *notifier,
> >>>> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> >>>> index f4df1b95c5ef..e072f2915ddb 100644
> >>>> --- a/include/media/v4l2-fwnode.h
> >>>> +++ b/include/media/v4l2-fwnode.h
> >>>> @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> >>>>   */
> >>>>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> >>>>  
> > 
> > And I see here that the function is documented. One more reason to move
> > kerneldoc to the .c files...
> 
> Please check my comment above.

I know, it's not your fault, I was complaining about the state of the
universe in general :-)

> >>>> +/**
> >>>> + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> >>>> + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> >>>> + *          connected to
> > 
> > This is very unclear, I would interpret that as the remote endpoint, not
> > the local endpoint. Could you please try to clarify the documentation ?
> 
> Hm.. I have no good idea how I should describe it..
> 
> """
> The device (local) endpoint fwnode handle on which the connector is
> connected to using the remote-enpoint property.
> """
> 
> >>>> + * @connector: pointer to the V4L2 fwnode connector data structure
> >>>> + *
> >>>> + * Fill the connector data structure with the connector type, label and the
> >>>> + * endpoint id and port where the connector belongs to. If no label is present
> >>>> + * a unique one will be created. Labels with more than 40 characters are cut.
> >>>> + *
> >>>> + * Return: %0 on success or a negative error code on failure:
> >>>> + *	   %-EINVAL on parsing failure
> >>>> + */
> >>>> +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> >>>> +				struct v4l2_fwnode_connector *connector);
> >>>> +
> >>>>  /**
> >>>>   * typedef parse_endpoint_func - Driver's callback function to be called on
> >>>>   *	each V4L2 fwnode endpoint.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-08-15 12:33       ` Laurent Pinchart
@ 2019-08-15 12:50         ` Marco Felsch
  2019-08-15 13:02           ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 12:50 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

On 19-08-15 15:33, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Fri, Aug 09, 2019 at 07:58:09AM +0200, Marco Felsch wrote:
> > On 19-05-16 19:27, Laurent Pinchart wrote:
> > > On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> > > > Some connectors no matter if in- or output supports only a limited
> > > > range of tv norms. It doesn't matter if the hardware behind that
> > > > connector supports more than the listed formats since the users are
> > > > restriced by a label e.g. to plug only a camera into this connector
> > > > which uses the PAL format.
> > > > 
> > > > This patch adds the capability to describe such limitation within the
> > > > firmware. There are no format restrictions if the property isn't
> > > > present, so it's completely backward compatible.
> > > 
> > > Why is this needed ? It's not really a hardware property, is it ? What's
> > > the use case ?
> > 
> > Cause some hardware only support a limited range of formats to that
> > connector. Of course it is a hardware property. For example if a
> > customer wants to limit a connector to a specifc norm because the
> > hardware behind that connector only supports that format or is
> > restricted to that format.
> 
> Then it should be a DT property of the hardware behind that connector
> (or information hardcoded directly into that driver), shouldn't it ?

Why? The connector is the limiting factor and not the decoder/bridge
device behind that. Let me explain it a bit more in detail. Our customer
sells hardware boxes and cameras. The camera is connected to the box
using a custom plug. So it's guaranteed that only their cameras can be
connected to. Also the camera they are using supports only PAL. So the
PAL signal is the only one which can be received on that connector. The
TVP itself supports more than just PAL signals and has multiple inputs.
So there can be the use case that a hardware box supports two physical
connectors: e.g. connector-PAL, connector-NTSC. The TVP should be
limited to PAL signals if the connector-PAL is active or limited to NTSC
if the connector-NTSC is active.

Hopefully you see now why we should model it on the connector side and
not on the device behind that connector.

Regards,
  Marco

> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > Reviewed-by: Rob Herring <robh@kernel.org>
> > > > ---
> > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > 
> > > > v6:
> > > > - tvnorms.h: use tabs instead of spaces
> > > > - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > > > - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > > > 
> > > > v2-v4:
> > > > - nothing since the patch was squashed from series [1] into this
> > > >   series.
> > > > 
> > > >  .../display/connector/analog-tv-connector.txt |  4 ++
> > > >  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> > > >  2 files changed, 60 insertions(+)
> > > >  create mode 100644 include/dt-bindings/media/tvnorms.h
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > > index 0c0970c210ab..346f8937a0b7 100644
> > > > --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > > +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > > > @@ -6,6 +6,9 @@ Required properties:
> > > >  
> > > >  Optional properties:
> > > >  - label: a symbolic name for the connector
> > > > +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > > > +           all tv norms are allowed. Possible video standards are defined in
> > > > +           include/dt-bindings/media/tvnorms.h.
> > > >  
> > > >  Required nodes:
> > > >  - Video port for TV input
> > > > @@ -16,6 +19,7 @@ Example
> > > >  tv: connector {
> > > >  	compatible = "composite-video-connector";
> > > >  	label = "tv";
> > > > +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> > > >  
> > > >  	port {
> > > >  		tv_connector_in: endpoint {
> > > > diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > > > new file mode 100644
> > > > index 000000000000..058ab8414145
> > > > --- /dev/null
> > > > +++ b/include/dt-bindings/media/tvnorms.h
> > > > @@ -0,0 +1,56 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > > > +/*
> > > > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > > > + */
> > > > +
> > > > +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > > > +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > > > +
> > > > +/* one bit for each */
> > > > +#define TVNORM_PAL_B		0x00000001
> > > > +#define TVNORM_PAL_B1		0x00000002
> > > > +#define TVNORM_PAL_G		0x00000004
> > > > +#define TVNORM_PAL_H		0x00000008
> > > > +#define TVNORM_PAL_I		0x00000010
> > > > +#define TVNORM_PAL_D		0x00000020
> > > > +#define TVNORM_PAL_D1		0x00000040
> > > > +#define TVNORM_PAL_K		0x00000080
> > > > +
> > > > +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > > > +				 TVNORM_PAL_B1 | \
> > > > +				 TVNORM_PAL_G  | \
> > > > +				 TVNORM_PAL_H  | \
> > > > +				 TVNORM_PAL_I  | \
> > > > +				 TVNORM_PAL_D  | \
> > > > +				 TVNORM_PAL_D1 | \
> > > > +				 TVNORM_PAL_K)
> > > > +
> > > > +#define TVNORM_PAL_M		0x00000100
> > > > +#define TVNORM_PAL_N		0x00000200
> > > > +#define TVNORM_PAL_Nc		0x00000400
> > > > +#define TVNORM_PAL_60		0x00000800
> > > > +
> > > > +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > > > +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > > > +#define TVNORM_NTSC_443		0x00004000
> > > > +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > > > +
> > > > +#define TVNORM_SECAM_B		0x00010000
> > > > +#define TVNORM_SECAM_D		0x00020000
> > > > +#define TVNORM_SECAM_G		0x00040000
> > > > +#define TVNORM_SECAM_H		0x00080000
> > > > +#define TVNORM_SECAM_K		0x00100000
> > > > +#define TVNORM_SECAM_K1		0x00200000
> > > > +#define TVNORM_SECAM_L		0x00400000
> > > > +#define TVNORM_SECAM_LC		0x00800000
> > > > +
> > > > +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > > > +				 TVNORM_SECAM_D  | \
> > > > +				 TVNORM_SECAM_G  | \
> > > > +				 TVNORM_SECAM_H  | \
> > > > +				 TVNORM_SECAM_K  | \
> > > > +				 TVNORM_SECAM_K1 | \
> > > > +				 TVNORM_SECAM_L  | \
> > > > +				 TVNORM_SECAM_LC)
> > > > +
> > > > +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-08-13  8:54       ` Marco Felsch
@ 2019-08-15 12:51         ` Laurent Pinchart
  2019-08-15 13:22           ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 12:51 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel

On Tue, Aug 13, 2019 at 10:54:29AM +0200, Marco Felsch wrote:
> Hi Laurent,
> 
> On 19-05-16 21:03, Laurent Pinchart wrote:
> > Hello Marco,
> > 
> > Thank you for the patch.
> > 
> > On Tue, May 14, 2019 at 03:25:45PM -0300, Mauro Carvalho Chehab wrote:
> > > Em Mon, 15 Apr 2019 14:44:05 +0200 Marco Felsch escreveu:
> > > 
> > > > This patch adds the of_graph support to describe the tvp connections.
> > > > Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> > > > of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> > > > connector must be conneted to port@0/endpoint@1, look at the Documentation
> > 
> > According to [2], it must be connected to port port@0 and port@1, not
> > just port@0.
> 
> You're right. I missed that.. I will change that for the v7.
> 
> > > > for more information. Since the TVP5150 is a converter the device-tree
> > > > must contain at least 1-input and 1-output port. The mc-connectors and
> > > > mc-links are only created if the device-tree contains the corresponding
> > > > connector nodes. If more than one connector is available the
> > > > media_entity_operations.link_setup() callback ensures that only one
> > > > connector is active.
> > > > 
> > > > [1] https://www.spinics.net/lists/linux-media/msg138545.html
> > > > [2] https://www.spinics.net/lists/linux-media/msg138546.html
> > > > 
> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > ---
> > > > Changelog:
> > > > 
> > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > [2] https://patchwork.kernel.org/cover/10786553/
> > > > 
> > > > v6:
> > > > - fix misspelled comments
> > > > - use 'unsigned int' where it's possible
> > > > - cleanup ifdef part-2:
> > > >   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
> > > >     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> > > > - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
> > > >   internal function do this.
> > > > - tvp5150_add_of_connectors: call within probe() to make it cleaner
> > > > - tvp5150_parse_dt: move local loop vars within the loop.
> > > > 
> > > > v5:
> > > > - Fixing build deps:
> > > >   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
> > > >   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
> > > >     includes. This leads into to complex deps for futher development.
> > > >   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
> > > >   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
> > > >   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> > > > 
> > > > - Simplify link_setup routine:
> > > >   - use generic connector parsing since both series [1,2] are squashed into
> > > >     one
> > > >   - struct tvp5150: drop pads_state and modify_second_link property
> > > >     due to link_setup() rework.
> > > >   - tvp5150_link_setup: add more comments
> > > >   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
> > > >     link directly within the driver instead of a recursive media-framework
> > > >     call (__media_entity_setup_link). This improves the readability and
> > > >     shrinks the driver code.
> > > >   - tvp5150_link_setup: disable all active links in case user switches
> > > >     connectors without disable it first.
> > > >   - tvp5150_registered: simplify default link enable path due to link_setup()
> > > >     rework.
> > > > 
> > > > - General cleanups
> > > >   - tvp5150_parse_dt: drop unecessary test
> > > >   - tvp5150_parse_dt: add err message due to misconfiguration
> > > >   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
> > > >   - s/dev_dbg/dev_dbg_lvl
> > > > 
> > > > v4:
> > > >  - rebase on top of media_tree/master, fix merge conflict due to commit
> > > >    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
> > > >    to zero")
> > > > 
> > > > v3:
> > > > - probe(): s/err/err_free_v4l2_ctrls
> > > > - drop MC dependency for tvp5150_pads
> > > > 
> > > > v2:
> > > > - adapt commit message
> > > > - unify ifdef switches
> > > > - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> > > > - mc: use 2-input and 1-output pad
> > > > - mc: link svideo connector to both input pads
> > > > - mc: enable/disable svideo links in one go
> > > > - mc: change link_setup() behaviour, switch the input src don't require a
> > > >       explicite disable before.
> > > > - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> > > > - mc: enable link to the first available connector and set the
> > > >       corresponding tvp5150 input src per default during registered()
> > > > - mc/of: factor out oftree connector allocation
> > > > - of: drop svideo dt port
> > > > - of: move svideo connector to port@0/endpoint@1
> > > > - of: require at least 1-in and 1-out endpoint
> > > > 
> > > >  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
> > > >  1 file changed, 370 insertions(+), 39 deletions(-)
> > > > 
> > > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > > index 89da921c8886..4e3228b2ccbc 100644
> > > > --- a/drivers/media/i2c/tvp5150.c
> > > > +++ b/drivers/media/i2c/tvp5150.c
> > > > @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
> > > >  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
> > > >  
> > > >  enum tvp5150_pads {
> > > > -	TVP5150_PAD_IF_INPUT,
> > > > +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> > > > +	TVP5150_PAD_AIP1B,
> > > >  	TVP5150_PAD_VID_OUT,
> > > >  	TVP5150_NUM_PADS
> > > >  };
> > > >  
> > > > +struct tvp5150_connector {
> > > > +	struct v4l2_fwnode_connector base;
> > > > +	struct media_entity ent;
> > > > +	struct media_pad pad;
> > > > +};
> > > > +
> > > >  struct tvp5150 {
> > > >  	struct v4l2_subdev sd;
> > > > -#ifdef CONFIG_MEDIA_CONTROLLER
> > > > +	/* additional endpoint for the svideo connector */
> > 
> > Could you please capitalize the first word of all comments to match the
> > driver style ?
> 
> Okay, I will check it for my v7.
> 
> > > > +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> > 
> > As the endpoints are only used at probe time, I would declare this as a
> > local variable in the probe function and pass it to both
> > tvp5150_add_of_connectors() and tvp5150_parse_dt(). If you order the
> > calls correctly it should simplify the probe error handling.
> 
> Yes that could be also a solution. I took Jacopo's comments and
> refactored the code so the endpoints no longer needed in my v7.
> 
> > > > +	unsigned int endpoints_num;
> > > > +
> > > > +	/* media-ctl properties */
> > 
> > media-ctl makes me think about the userspace application, maybe "Media
> > controller properties" ?
> 
> I've dopped that comment becuase it is to obvious..
> 
> > > >  	struct media_pad pads[TVP5150_NUM_PADS];
> > > > -#endif
> > > > +	struct tvp5150_connector *connectors;
> > > > +	int connectors_num;
> > 
> > unsigned int ?
> 
> Of course.
> 
> > > > +
> > > >  	struct v4l2_ctrl_handler hdl;
> > > >  	struct v4l2_rect rect;
> > > >  	struct regmap *regmap;
> > > > @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +/****************************************************************************
> > > > + *			Media entity ops
> > > > + ****************************************************************************/
> > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > 
> > Should we depend on CONFIG_MEDIA_CONTROLLER instead, especially since
> > you remove the similar conditional in the struct tvp5150 definition and
> > in the probe function ?
> 
> I don't know if we can add the dependency without worries because the
> tvp5150 is also used by the usb/em28xx devices which can be build
> without CONFIG_MEDIA_CONTROLLER support. During .probe() a stub function
> will be called if CONFIG_MEDIA_CONTROLLER isn't enabled.
> 
> > > > +static int tvp5150_set_link(struct media_pad *connector_pad,
> > > > +			    struct media_pad *tvp5150_pad, u32 flags)
> > > > +{
> > > > +	struct media_link *link;
> > > > +
> > > > +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> > > > +	if (!link)
> > > > +		return -EINVAL;
> > > > +
> > > > +	link->flags = flags;
> > > > +	link->reverse->flags = link->flags;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> > > > +{
> > > > +	struct media_pad *connector_pad;
> > > > +	unsigned int i;
> > > > +	int err;
> > > > +
> > > > +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > > > +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> > > > +		if (!connector_pad)
> > > > +			continue;
> > > > +
> > > > +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> > > > +		if (err)
> > > > +			return err;
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> > > > +			     u32 config);
> > > > +
> > > > +static int tvp5150_link_setup(struct media_entity *entity,
> > > > +			      const struct media_pad *tvp5150_pad,
> > > > +			      const struct media_pad *remote, u32 flags)
> > > > +{
> > > > +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> > > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > > +	struct media_pad *other_tvp5150_pad =
> > > > +		&decoder->pads[tvp5150_pad->index ^ 1];
> > > > +	bool is_svideo = false;
> > > > +	unsigned int i;
> > > > +	int err;
> > > > +
> > > > +	/*
> > > > +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> > > > +	 * Enabling or disabling the source pad link has no effect.
> > > > +	 */
> > > > +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> > > > +		return 0;
> > > > +
> > > > +	/* Check if the svideo connector should be enabled */
> > > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > > +		if (remote->entity == &decoder->connectors[i].ent) {
> > > 
> > > > +			is_svideo =
> > > > +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > > 
> > > Nitpick:
> > > 
> > > I would actually prefer to keep this on a single line. Ok, it will violate
> > > the 80-columns, but it would be better than the above (IMHO).
> > > 
> > > > +			break;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> > > > +		    remote->entity->name, remote->index,
> > > > +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> > > > +		    flags & MEDIA_LNK_FL_ENABLED);
> > > > +	if (is_svideo)
> > > > +		dev_dbg_lvl(sd->dev, 1, debug,
> > > > +			    "link setup '%s':%d->'%s':%d[%d]",
> > > > +			    remote->entity->name, remote->index,
> > > > +			    other_tvp5150_pad->entity->name,
> > > > +			    other_tvp5150_pad->index,
> > > > +			    flags & MEDIA_LNK_FL_ENABLED);
> > > > +
> > > > +	/*
> > > > +	 * The TVP5150 has an internal mux which allows the following setup:
> > > > +	 *
> > > > +	 * comp-connector1  --\
> > > > +	 *		       |---> AIP1A
> > > > +	 *		      /
> > > > +	 * svideo-connector -|
> > > > +	 *		      \
> > > > +	 *		       |---> AIP1B
> > > > +	 * comp-connector2  --/
> > > > +	 *
> > > > +	 * We can't rely on user space that the current connector gets disabled
> > > > +	 * first before enabling the new connector. Disable all active
> > > > +	 * connector links to be on the safe side.
> > > > +	 */
> > > > +	err = tvp5150_disable_all_input_links(decoder);
> > > > +	if (err)
> > > > +		return err;
> > > > +
> > > > +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> > > > +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> > > > +			  TVP5150_BLACK_SCREEN, 0);
> > > > +
> > > > +	if (flags & MEDIA_LNK_FL_ENABLED) {
> > > > +		/*
> > > > +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > > > +		 * Both links must be enabled in one-shot regardless which link
> > > > +		 * the user requests.
> > > > +		 */
> > 
> > This is a very grey area, I don't think the MC API explicitly allows
> > doing this. As changing links during streaming is disallowed, wouldn't
> > it be easier to handle the routing configuration at stream start ? You
> > wouldn't have to deal with this issue then, you could just return an
> > error if only one link is enabled. Furthermore, it would allow
> > supporting a configuration where a composite signal is connected to the
> > Y pin of the mini-DIN connector.
> 
> We discussed this a few series earlier because my first solution what
> like this you describe above. I changed that because Mauro had some
> concerns about the usability. Now this behaviour is easier to use but
> as you pointed out above, such 'special' handling isn't doable anymore.
> I would keep this solution since I want to get this series merged ;)
> If someone wants such a 'special' configuration he can implement it
> later.

But that would break the ABI. I'm sorry, but we need to find an
agreement on this issue to merge the series, it's not a detail that can
be addressed later. Could you start a discussion with Mauro to see if he
can be convinced, or if he has a better proposal ?

> > > > +		if (is_svideo) {
> > > > +			err = tvp5150_set_link((struct media_pad *) remote,
> > > > +					       other_tvp5150_pad, flags);
> > > > +			if (err)
> > > > +				return err;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static const struct media_entity_operations tvp5150_sd_media_ops = {
> > > > +	.link_setup = tvp5150_link_setup,
> > > > +};
> > > > +#endif
> > > >  /****************************************************************************
> > > >  			I2C Command
> > > >   ****************************************************************************/
> > > > @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +static int tvp5150_registered(struct v4l2_subdev *sd)
> > > > +{
> > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > > +	unsigned int i;
> > > > +	int ret;
> > > > +
> > > > +	/*
> > > > +	 * Setup connector pads and links. Enable the link to the first
> > > > +	 * available connector per default.
> > > > +	 */
> > > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > > +		struct media_entity *con = &decoder->connectors[i].ent;
> > > > +		struct media_pad *pad = &decoder->connectors[i].pad;
> > > > +		unsigned int port = decoder->connectors[i].base.remote_port;
> > > > +		bool is_svideo =
> > > > +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > > > +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> > 
> > The flags passed to media_create_pad_link() are unsigned.
> 
> You are right, changed that.
> 
> > > > +
> > > > +		pad->flags = MEDIA_PAD_FL_SOURCE;
> > > > +		ret = media_entity_pads_init(con, 1, pad);
> > > > +		if (ret < 0)
> > > > +			return ret;
> > > > +
> > > > +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> > > > +		if (ret < 0)
> > > > +			return ret;
> > > > +
> > > > +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> > > > +		if (ret < 0) {
> > > > +			media_device_unregister_entity(con);
> > > > +			return ret;
> > > > +		}
> > 
> > Will the other registered media entities be unregistered correctly ?
> 
> Good point. I add a seperate error handling to ensure all registered
> entities gets unregistered.
> 
> > > > +
> > > > +		if (is_svideo) {
> > > > +			/* svideo links to both aip1a and aip1b */
> > > > +			ret = media_create_pad_link(con, 0, &sd->entity,
> > > > +						    port + 1, flags);
> > 
> > Does the TVP5150 support both connecting Y to AIP1A and C to AIP1B, and
> > Y to AIP1B and C to AIP1A ? If so the port + 1 won't always work.
> 
> No, if I understood the datasheet right Y is always connected to AIP1A
> and C to AIP1B. Since I improved the struct v4l2_fwnode_connector to
> hold more connector-port information the 'port+1' logic isn't used
> anymore.
> 
> > > > +			if (ret < 0) {
> > > > +				media_device_unregister_entity(con);
> > > > +				return ret;
> > > > +			}
> > > > +		}
> > > > +
> > > > +		/* enable default input */
> > > > +		if (flags == MEDIA_LNK_FL_ENABLED) {
> > > > +			decoder->input =
> > > > +				is_svideo ? TVP5150_SVIDEO :
> > > > +				port == 0 ? TVP5150_COMPOSITE0 :
> > > > +				TVP5150_COMPOSITE1;
> > > > +
> > > > +			tvp5150_selmux(sd);
> > > > +		}
> > 
> > You could move this after the loop and operation on
> > decoder->connectors[0]. Hopefully you could then use if's instead of
> > nested ? : operators, as the above isn't very readable.
> 
> That's also doable. Mauro which solution do you prefer?
> 
> > > > +	}
> > > > +#endif
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +
> > 
> > One blank line is enough.
> 
> Fixed.
> 
> > > >  /* ----------------------------------------------------------------------- */
> > > >  
> > > >  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> > > > @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
> > > >  	.pad = &tvp5150_pad_ops,
> > > >  };
> > > >  
> > > > +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> > > > +	.registered = tvp5150_registered,
> > > > +};
> > > > +
> > > >  /****************************************************************************
> > > >  			I2C Client & Driver
> > > >   ****************************************************************************/
> > > > @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > > >  {
> > > > -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> > > > -	struct device_node *ep;
> > > > -	unsigned int flags;
> > > > -	int ret = 0;
> > > > +	struct device *dev = decoder->sd.dev;
> > 
> > You use dev in a singla location, I think you could use decoder->sd.dev
> > directly.
> 
> This function is no longer used but you're right.
> 
> > 
> > > > +	struct tvp5150_connector *connectors;
> > > > +	unsigned int connectors_num = decoder->connectors_num;
> > > > +	int i, ret;
> > 
> > i is never negative, you can make it an unsiged int.
> > 
> > > >  
> > > > -	ep = of_graph_get_next_endpoint(np, NULL);
> > > > -	if (!ep)
> > > > -		return -EINVAL;
> > > > +	/*
> > > > +	 * Only add of_connectors if device really is a OF device since
> > > > +	 * the driver is used by usb devices e.g. em28xx and embedded
> > > > +	 * devices.
> > > > +	 */
> > > > +	if (!decoder->connectors_num)
> > 
> > Maybe if (!connectors_num) ?
> > 
> > > > +		return 0;
> > > >  
> > > > -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> > > > -	if (ret)
> > > > -		goto err;
> > > > +	/* Allocate and initialize all available input connectors */
> > > > +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> > > > +				  GFP_KERNEL);
> > > > +	if (!connectors)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	for (i = 0; i < connectors_num; i++) {
> > > > +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> > > > +
> > > > +		ret = v4l2_fwnode_parse_connector(
> > > > +				   of_fwnode_handle(decoder->endpoints[i]), c);
> > 
> > I think you should handle errors here.
> > 
> > > > +
> > > > +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> > > > +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> > > > +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> > > > +		connectors[i].ent.name = c->label;
> > 
> > I don't think using the label as the entity name is a good idea, as we
> > require entity names to be unique, and labels offer no such guarantee.
> 
> Good point. What about <connector dt-name>:<label>? The devicetree name
> is unique.

That should work. Is there a risk it wouldn't fit in the entity name
field though ?

> > > > +	}
> > > > +
> > > > +	decoder->connectors = connectors;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int tvp5150_mc_init(struct tvp5150 *decoder)
> > > > +{
> > > > +	struct v4l2_subdev *sd = &decoder->sd;
> > > > +	unsigned int i;
> > > > +
> > > > +	sd->entity.ops = &tvp5150_sd_media_ops;
> > > > +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > > +
> > > > +	/* Initialize all TVP5150 pads */
> > > > +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> > > > +		if (i < TVP5150_NUM_PADS - 1) {
> > > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > > > +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > > > +		} else {
> > > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > > > +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> > > > +		}
> > > > +	}
> > 
> > You can simplify this to
> > 
> > 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > 		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > 		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > 	}
> > 
> > 	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > 	decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> 
> Yes, already done.
> 
> > > > +
> > > > +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> > > > +				      decoder->pads);
> > > > +}
> > > > +
> > > > +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> > > > +
> > > > +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > > > +{
> > > > +	return 0;
> > > > +}
> > > >  
> > > > -	flags = bus_cfg.bus.parallel.flags;
> > > > +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> > > > +{
> > > > +	return 0;
> > > > +}
> > > > +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
> > > >  
> > > > -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > > -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > > -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > > -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > > +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > > +{
> > > > +	struct device *dev = decoder->sd.dev;
> > > > +	struct device_node *ep_np;
> > > > +	unsigned int i = 0, in = 0;
> > 
> > Let's rename in to num_inputs or num_connectors.
> 
> I refactored the code, so in is no longer used.
> 
> > > > +	int ret;
> > > > +	bool found = false;
> > > > +
> > > > +	/* at least 1 output and 1 input */
> > > > +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> > > > +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> > > > +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
> > > >  		ret = -EINVAL;
> > > >  		goto err;
> > > >  	}
> > > >  
> > > > -	decoder->mbus_type = bus_cfg.bus_type;
> > > > +	for_each_endpoint_of_node(np, ep_np) {
> > > > +		struct v4l2_fwnode_endpoint bus_cfg = {
> > > > +			.bus_type = V4L2_MBUS_UNKNOWN
> > > > +		};
> > > > +		struct v4l2_fwnode_connector c;
> > > > +		struct of_endpoint ep;
> > > > +		unsigned int flags;
> > > > +
> > > > +		of_graph_parse_endpoint(ep_np, &ep);
> > > > +		switch (ep.port) {
> > > > +		case TVP5150_PAD_AIP1A:
> > > > +			/* fall through */
> > 
> > I don't think you need this comment.
> > 
> > > > +		case TVP5150_PAD_AIP1B:
> > > > +			ret = v4l2_fwnode_parse_connector(
> > > > +						   of_fwnode_handle(ep_np), &c);
> > 
> > You use of_fwnode_handle(ep_np) twice, you could move it outside of the
> > switch () to keep lines shorter.
> > 
> > > > +			if (c.type != V4L2_CON_COMPOSITE &&
> > > > +			    c.type != V4L2_CON_SVIDEO) {
> > > > +				dev_err(dev,
> > > > +					"Invalid endpoint %d on port %d\n",
> > 
> > The correct format specifier for unsigned int is %u.
> > 
> > Should the error message be more explicit ? "Invalid connector type for
> > port@%u/endpoint@%u" ?
> > 
> > 
> > > > +					c.remote_id, c.remote_port);
> > > > +				ret = -EINVAL;
> > > > +				goto err;
> > 
> > If you break out of the loop you need an of_node_put(ep_np).
> > Alternatively, you could store ep_np in the endpoints array right before
> > of_graph_parse_endpoint() and call of_node_put() right after
> > of_graph_parse_endpoint().
> > 
> > > > +			}
> > > > +			in++;
> > > > +			break;
> > > > +		case TVP5150_PAD_VID_OUT:
> > > > +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> > > > +							 &bus_cfg);
> > > > +			if (ret)
> > > > +				goto err;
> > > > +
> > > > +			flags = bus_cfg.bus.parallel.flags;
> > > > +
> > > > +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > > +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > > +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > > +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > > +				ret = -EINVAL;
> > > > +				goto err;
> > > > +			}
> > > > +
> > > > +			decoder->mbus_type = bus_cfg.bus_type;
> > > > +			break;
> > > > +		default:
> > > > +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> > 
> > %u here too.
> > 
> > > > +				ep.port, ep.local_node);
> > > > +			ret = -EINVAL;
> > > > +			goto err;
> > > > +		}
> > > > +
> > > > +		of_node_get(ep_np);
> > > > +		decoder->endpoints[i] = ep_np;
> > > > +		i++;
> > > > +
> > > > +		found = true;
> > > > +	}
> > > >  
> > > > +	decoder->connectors_num = in;
> > > > +	return found ? 0 : -ENODEV;
> > > >  err:
> > > > -	of_node_put(ep);
> > > >  	return ret;
> > 
> > You can remove the err label and return ret directly.
> 
> I took your comments into account for the refactored function, thanks.
> 
> > > >  }
> > > >  
> > > > +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> > > > +{
> > > > +	unsigned int i;
> > > > +
> > > > +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> > > > +		of_node_put(decoder->endpoints[i]);
> > > > +}
> > > > +
> > > >  static const char * const tvp5150_test_patterns[2] = {
> > > >  	"Disabled",
> > > >  	"Black screen"
> > > > @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > > >  		res = tvp5150_parse_dt(core, np);
> > > >  		if (res) {
> > > >  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> > > > -			return res;
> > > > +			goto err_cleanup_dt;
> > > >  		}
> > > >  	} else {
> > > >  		/* Default to BT.656 embedded sync */
> > > > @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
> > > >  	}
> > > >  
> > > >  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > > > +	sd->internal_ops = &tvp5150_internal_ops;
> > > >  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > > >  
> > > > -#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> > > > -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> > > > -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> > > > -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> > > > -
> > > > -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > > -
> > > > -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> > > > -	if (res < 0)
> > > > -		return res;
> > > > +	res = tvp5150_mc_init(core);
> > > > +	if (res)
> > > > +		goto err_cleanup_dt;
> > > >  
> > > > -#endif
> > > > +	res = tvp5150_add_of_connectors(core);
> > > > +	if (res)
> > > > +		goto err_cleanup_dt;
> > > >  
> > > >  	res = tvp5150_detect_version(core);
> > > >  	if (res < 0)
> > > > -		return res;
> > > > +		goto err_cleanup_dt;
> > > >  
> > > >  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > > >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > > > @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > > >  	sd->ctrl_handler = &core->hdl;
> > > >  	if (core->hdl.error) {
> > > >  		res = core->hdl.error;
> > > > -		goto err;
> > > > +		goto err_free_v4l2_ctrls;
> > > >  	}
> > > >  
> > > >  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> > > > @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
> > > >  						tvp5150_isr, IRQF_TRIGGER_HIGH |
> > > >  						IRQF_ONESHOT, "tvp5150", core);
> > > >  		if (res)
> > > > -			goto err;
> > > > +			goto err_free_v4l2_ctrls;
> > > >  	}
> > > >  
> > > >  	res = v4l2_async_register_subdev(sd);
> > > >  	if (res < 0)
> > > > -		goto err;
> > > > +		goto err_free_v4l2_ctrls;
> > > >  
> > > >  	if (debug > 1)
> > > >  		tvp5150_log_status(sd);
> > > > +
> > > >  	return 0;
> > > >  
> > > > -err:
> > > > +err_free_v4l2_ctrls:
> > > >  	v4l2_ctrl_handler_free(&core->hdl);
> > > > +err_cleanup_dt:
> > > > +	if (IS_ENABLED(CONFIG_OF) && np)
> > > > +		tvp5150_dt_cleanup(core);
> > > > +
> > > >  	return res;
> > > >  }
> > > >  

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector
  2019-08-13  9:10     ` Marco Felsch
@ 2019-08-15 12:53       ` Laurent Pinchart
  2019-08-15 13:26         ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 12:53 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel

Hi Marco,

On Tue, Aug 13, 2019 at 11:10:30AM +0200, Marco Felsch wrote:
> On 19-05-16 21:07, Laurent Pinchart wrote:
> > On Mon, Apr 15, 2019 at 02:44:12PM +0200, Marco Felsch wrote:
> > > The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
> > > data and is able to auto-detect the input signal. The auto-detection
> > > does not work if the connector does not receive an input signal and the
> > > tvp5150 might not be configured correctly. This misconfiguration leads
> > > into wrong decoded video streams if the tvp5150 gets powered on before
> > > the video signal is present.
> > > 
> > > Limit the supported tv norms according to the actual selected connector
> > > to avoid a misconfiguration.
> > 
> > This seems a bit of a hack to me. In particular, on what grounds would
> > you specify a particular configuration in DT ? Also, this issue affects
> > non-DT systems, and should be solved globally.
> 
> Why is this a hack? Imagine a hardware which supports PAL signals only.
> Then it should be forbidden for the user space to configure it to SECAM
> or any NTSC. Since the hardware makes the limitation it should be
> abstracted on DT level.

What part of the hardware would be the limiting factor here ? Clearly
not the TVP5150 as it supports all TV norms, and also not the connector,
as the connector hardware doesn't care about TV norms.

> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v5:
> > > - probe() initialize supported tv-norms according the given connectors
> > >   if they are available.
> > > - check if media-controller is used. Don't limit the norm if it isn't
> > >   used.
> > > - add more logic to be smarter during connector changing so it is
> > >   intuitiver for the user space.
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > 
> > >  drivers/media/i2c/tvp5150.c | 69 +++++++++++++++++++++++++++++++++++--
> > >  1 file changed, 67 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > index cd54715eb641..c0ee08546643 100644
> > > --- a/drivers/media/i2c/tvp5150.c
> > > +++ b/drivers/media/i2c/tvp5150.c
> > > @@ -32,6 +32,13 @@
> > >  #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
> > >  #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
> > >  #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
> > > +#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
> > > +				 V4L2_STD_NTSC_443 | \
> > > +				 V4L2_STD_PAL      | \
> > > +				 V4L2_STD_PAL_M    | \
> > > +				 V4L2_STD_PAL_N    | \
> > > +				 V4L2_STD_PAL_Nc   | \
> > > +				 V4L2_STD_SECAM)
> > >  
> > >  MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
> > >  MODULE_AUTHOR("Mauro Carvalho Chehab");
> > > @@ -66,6 +73,7 @@ struct tvp5150 {
> > >  	/* media-ctl properties */
> > >  	struct media_pad pads[TVP5150_NUM_PADS];
> > >  	struct tvp5150_connector *connectors;
> > > +	struct tvp5150_connector *cur_connector;
> > >  	int connectors_num;
> > >  
> > >  	struct v4l2_ctrl_handler hdl;
> > > @@ -785,17 +793,28 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
> > >  static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
> > >  {
> > >  	struct tvp5150 *decoder = to_tvp5150(sd);
> > > +	struct tvp5150_connector *cur_con = decoder->cur_connector;
> > > +	v4l2_std_id supported_norms = cur_con ?
> > > +		cur_con->base.connector.analog.supported_tvnorms : V4L2_STD_ALL;
> > >  
> > >  	if (decoder->norm == std)
> > >  		return 0;
> > >  
> > > +	/*
> > > +	 * check if requested std or group of std's is/are supported by the
> > > +	 * connector
> > > +	 */
> > > +	if ((supported_norms & std) == 0)
> > > +		return -EINVAL;
> > > +
> > >  	/* Change cropping height limits */
> > >  	if (std & V4L2_STD_525_60)
> > >  		decoder->rect.height = TVP5150_V_MAX_525_60;
> > >  	else
> > >  		decoder->rect.height = TVP5150_V_MAX_OTHERS;
> > >  
> > > -	decoder->norm = std;
> > > +	/* set only the specific supported std in case of group of std's */
> > > +	decoder->norm = supported_norms & std;
> > >  
> > >  	return tvp5150_set_std(sd, std);
> > >  }
> > > @@ -1347,6 +1366,8 @@ static int tvp5150_link_setup(struct media_entity *entity,
> > >  			  TVP5150_BLACK_SCREEN, 0);
> > >  
> > >  	if (flags & MEDIA_LNK_FL_ENABLED) {
> > > +		u32 new_norm;
> > > +
> > >  		/*
> > >  		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > >  		 * Both links must be enabled in one-shot regardless which link
> > > @@ -1358,6 +1379,26 @@ static int tvp5150_link_setup(struct media_entity *entity,
> > >  			if (err)
> > >  				return err;
> > >  		}
> > > +
> > > +		/* Update the current connector */
> > > +		decoder->cur_connector =
> > > +			container_of(remote, struct tvp5150_connector, pad);
> > > +
> > > +		/*
> > > +		 * Do nothing if the new connector supports the same tv-norms as
> > > +		 * the old one.
> > > +		 */
> > > +		new_norm = decoder->norm &
> > > +			decoder->cur_connector->base.connector.analog.supported_tvnorms;
> > > +		if (decoder->norm == new_norm)
> > > +			return 0;
> > > +
> > > +		/*
> > > +		 * Fallback to the new connector tv-norms if we can't find any
> > > +		 * common between the current tv-norm and the new one.
> > > +		 */
> > > +		tvp5150_s_std(sd, new_norm ? new_norm :
> > > +			decoder->cur_connector->base.connector.analog.supported_tvnorms);
> > >  	}
> > >  
> > >  	return 0;
> > > @@ -1576,6 +1617,9 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
> > >  				TVP5150_COMPOSITE1;
> > >  
> > >  			tvp5150_selmux(sd);
> > > +			decoder->cur_connector = &decoder->connectors[i];
> > > +			tvp5150_s_std(sd,
> > > +				decoder->connectors[i].base.connector.analog.supported_tvnorms);
> > >  		}
> > >  	}
> > >  #endif
> > > @@ -1903,6 +1947,11 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > >  				ret = -EINVAL;
> > >  				goto err;
> > >  			}
> > > +			if (!(c.connector.analog.supported_tvnorms &
> > > +			    TVP5150_STD_MASK))
> > > +				dev_warn(dev,
> > > +					"Unsupported tv-norm on connector %s.\n",
> > > +					c.label);
> > >  			in++;
> > >  			break;
> > >  		case TVP5150_PAD_VID_OUT:
> > > @@ -2011,7 +2060,23 @@ static int tvp5150_probe(struct i2c_client *c,
> > >  	if (res < 0)
> > >  		goto err_cleanup_dt;
> > >  
> > > -	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > > +	/*
> > > +	 * Iterate over all available connectors in case they are supported and
> > > +	 * successfully parsed. Fallback to default autodetect in case they
> > > +	 * aren't supported.
> > > +	 */
> > > +	if (core->connectors) {
> > > +		struct v4l2_fwnode_connector *con;
> > > +		int i;
> > > +
> > > +		for (i = 0; i < core->connectors_num; i++) {
> > > +			con = &core->connectors[i].base;
> > > +			core->norm |= con->connector.analog.supported_tvnorms;
> > > +		}
> > > +	} else {
> > > +		core->norm = V4L2_STD_ALL;
> > > +	}
> > > +
> > >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > >  	core->input = TVP5150_COMPOSITE1;
> > >  	core->enable = true;

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-08-15 12:50         ` Marco Felsch
@ 2019-08-15 13:02           ` Laurent Pinchart
  2019-08-15 13:35             ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 13:02 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Marco,

On Thu, Aug 15, 2019 at 02:50:02PM +0200, Marco Felsch wrote:
> On 19-08-15 15:33, Laurent Pinchart wrote:
> > On Fri, Aug 09, 2019 at 07:58:09AM +0200, Marco Felsch wrote:
> >> On 19-05-16 19:27, Laurent Pinchart wrote:
> >>> On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> >>>> Some connectors no matter if in- or output supports only a limited
> >>>> range of tv norms. It doesn't matter if the hardware behind that
> >>>> connector supports more than the listed formats since the users are
> >>>> restriced by a label e.g. to plug only a camera into this connector
> >>>> which uses the PAL format.
> >>>> 
> >>>> This patch adds the capability to describe such limitation within the
> >>>> firmware. There are no format restrictions if the property isn't
> >>>> present, so it's completely backward compatible.
> >>> 
> >>> Why is this needed ? It's not really a hardware property, is it ? What's
> >>> the use case ?
> >> 
> >> Cause some hardware only support a limited range of formats to that
> >> connector. Of course it is a hardware property. For example if a
> >> customer wants to limit a connector to a specifc norm because the
> >> hardware behind that connector only supports that format or is
> >> restricted to that format.
> > 
> > Then it should be a DT property of the hardware behind that connector
> > (or information hardcoded directly into that driver), shouldn't it ?
> 
> Why? The connector is the limiting factor and not the decoder/bridge
> device behind that. Let me explain it a bit more in detail. Our customer
> sells hardware boxes and cameras. The camera is connected to the box
> using a custom plug. So it's guaranteed that only their cameras can be
> connected to. Also the camera they are using supports only PAL. So the
> PAL signal is the only one which can be received on that connector. The
> TVP itself supports more than just PAL signals and has multiple inputs.
> So there can be the use case that a hardware box supports two physical
> connectors: e.g. connector-PAL, connector-NTSC. The TVP should be
> limited to PAL signals if the connector-PAL is active or limited to NTSC
> if the connector-NTSC is active.
> 
> Hopefully you see now why we should model it on the connector side and
> not on the device behind that connector.

So it essentially means that if someone connects an NTSC camera on the
PAL input with the same custom connector, the hardware will support it,
right ? I don't think it's a hardware limitation of the connector in
that case :-) And I don't think it belongs to DT. Userspace is probably
where I would handle this type of policy.

> >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> >>>> Reviewed-by: Rob Herring <robh@kernel.org>
> >>>> ---
> >>>> [1] https://patchwork.kernel.org/cover/10794703/
> >>>> 
> >>>> v6:
> >>>> - tvnorms.h: use tabs instead of spaces
> >>>> - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> >>>> - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> >>>> 
> >>>> v2-v4:
> >>>> - nothing since the patch was squashed from series [1] into this
> >>>>   series.
> >>>> 
> >>>>  .../display/connector/analog-tv-connector.txt |  4 ++
> >>>>  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> >>>>  2 files changed, 60 insertions(+)
> >>>>  create mode 100644 include/dt-bindings/media/tvnorms.h
> >>>> 
> >>>> diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> >>>> index 0c0970c210ab..346f8937a0b7 100644
> >>>> --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> >>>> +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> >>>> @@ -6,6 +6,9 @@ Required properties:
> >>>>  
> >>>>  Optional properties:
> >>>>  - label: a symbolic name for the connector
> >>>> +- tvnorms: limit the supported tv norms on a connector to the given ones else
> >>>> +           all tv norms are allowed. Possible video standards are defined in
> >>>> +           include/dt-bindings/media/tvnorms.h.
> >>>>  
> >>>>  Required nodes:
> >>>>  - Video port for TV input
> >>>> @@ -16,6 +19,7 @@ Example
> >>>>  tv: connector {
> >>>>  	compatible = "composite-video-connector";
> >>>>  	label = "tv";
> >>>> +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> >>>>  
> >>>>  	port {
> >>>>  		tv_connector_in: endpoint {
> >>>> diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> >>>> new file mode 100644
> >>>> index 000000000000..058ab8414145
> >>>> --- /dev/null
> >>>> +++ b/include/dt-bindings/media/tvnorms.h
> >>>> @@ -0,0 +1,56 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> >>>> +/*
> >>>> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> >>>> + */
> >>>> +
> >>>> +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> >>>> +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> >>>> +
> >>>> +/* one bit for each */
> >>>> +#define TVNORM_PAL_B		0x00000001
> >>>> +#define TVNORM_PAL_B1		0x00000002
> >>>> +#define TVNORM_PAL_G		0x00000004
> >>>> +#define TVNORM_PAL_H		0x00000008
> >>>> +#define TVNORM_PAL_I		0x00000010
> >>>> +#define TVNORM_PAL_D		0x00000020
> >>>> +#define TVNORM_PAL_D1		0x00000040
> >>>> +#define TVNORM_PAL_K		0x00000080
> >>>> +
> >>>> +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> >>>> +				 TVNORM_PAL_B1 | \
> >>>> +				 TVNORM_PAL_G  | \
> >>>> +				 TVNORM_PAL_H  | \
> >>>> +				 TVNORM_PAL_I  | \
> >>>> +				 TVNORM_PAL_D  | \
> >>>> +				 TVNORM_PAL_D1 | \
> >>>> +				 TVNORM_PAL_K)
> >>>> +
> >>>> +#define TVNORM_PAL_M		0x00000100
> >>>> +#define TVNORM_PAL_N		0x00000200
> >>>> +#define TVNORM_PAL_Nc		0x00000400
> >>>> +#define TVNORM_PAL_60		0x00000800
> >>>> +
> >>>> +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> >>>> +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> >>>> +#define TVNORM_NTSC_443		0x00004000
> >>>> +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> >>>> +
> >>>> +#define TVNORM_SECAM_B		0x00010000
> >>>> +#define TVNORM_SECAM_D		0x00020000
> >>>> +#define TVNORM_SECAM_G		0x00040000
> >>>> +#define TVNORM_SECAM_H		0x00080000
> >>>> +#define TVNORM_SECAM_K		0x00100000
> >>>> +#define TVNORM_SECAM_K1		0x00200000
> >>>> +#define TVNORM_SECAM_L		0x00400000
> >>>> +#define TVNORM_SECAM_LC		0x00800000
> >>>> +
> >>>> +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> >>>> +				 TVNORM_SECAM_D  | \
> >>>> +				 TVNORM_SECAM_G  | \
> >>>> +				 TVNORM_SECAM_H  | \
> >>>> +				 TVNORM_SECAM_K  | \
> >>>> +				 TVNORM_SECAM_K1 | \
> >>>> +				 TVNORM_SECAM_L  | \
> >>>> +				 TVNORM_SECAM_LC)
> >>>> +
> >>>> +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-08-15 12:38       ` Laurent Pinchart
@ 2019-08-15 13:04         ` Marco Felsch
  2019-08-15 13:10           ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:04 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Laurent,

On 19-08-15 15:38, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Fri, Aug 09, 2019 at 09:55:36AM +0200, Marco Felsch wrote:
> > On 19-05-16 19:36, Laurent Pinchart wrote:
> > > On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> > > > Currently every driver needs to parse the connector endpoints by it self.
> > > 
> > > s/it self/itself/
> > > 
> > > > This is the initial work to make this generic. The generic connector has
> > > > some common fields and some connector specific parts. The generic one
> > > > includes:
> > > >   - type
> > > >   - label
> > > >   - remote_port (the port where the connector is connected to)
> > > >   - remote_id   (the endpoint where the connector is connected to)
> > > 
> > > This assumes a single connection between a connector and a remote port,
> > > and a single port on the connector side. Is this guaranteed ? For the
> > > mini-DIN-4 connectors (often used for S-Video) for instance, I recall
> > > from the extensive discussions we had in the past that they should be
> > > modeled with two pins, one for the Y component and one for C components.
> > > The rationale for this is to support systems where such a connector
> > > could be used to carry S-Video, but also two composite video signals
> > > (usually through an external adapter from 2 RCA female connectors to one
> > > S-Video male connector) that would be routed to two separate video
> > > decoders (or two different inputs of the same video decoder). Other
> > > topologies may be possible too.
> > 
> > I got your concerns and I also remember the tvp5150 port bindings
> > myself in the past. Do you know how often such a setup you described
> > above happens these days? I would rather add more documentation to the
> > bindings [1] and add a check to v4l2_fwnode_parse_connector() to
> > guarantee that one port has only one endpoint. Because I don't think
> > that analog connectors has a bright future these days.
> > 
> > [1] Documentation/devicetree/bindings/display/connector/ \
> >     analog-tv-connector.txt
> 
> I have seen it on older hardware, I don't know about more recent
> systems. For the S-Video case at least, you need to support two DT
> ports, even if you don't support connecting them to two different
> devices yet.

Can you take a look on the v7 I send a few minutes ago? I changed the
layout ;)

> In any case, I'm fine if those topologies are not supported yet, but it
> should be possible to support them in a backward-compatible way. In
> particular, in this case, we should make sure the DT bindings will allow
> such topologies, and the DT parsing API should make it possible to
> support them without fugure changes to drivers that use the API from
> this patch for "simple" topologies.

You're right. I adapted the struct to be more extendible.

Regards,
  Marco

> 
> > > > The specific fields are within a union, since only one of them can be
> > > > available at the time. Since this is the initial support the patch adds
> > > > only the analog-connector specific ones.
> > > > 
> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > ---
> > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > 
> > > > v6:
> > > > - fix some spelling and style issues
> > > > - rm unnecessary comments
> > > > - drop vga and dvi connector
> > > > 
> > > > v2-v4:
> > > > - nothing since the patch was squashed from series [1] into this
> > > >   series.
> > > > 
> > > >  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> > > >  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> > > >  2 files changed, 63 insertions(+)
> > > >  create mode 100644 include/media/v4l2-connector.h
> > > > 
> > > > diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > > > new file mode 100644
> > > > index 000000000000..3a951c54f50e
> > > > --- /dev/null
> > > > +++ b/include/media/v4l2-connector.h
> > > > @@ -0,0 +1,30 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > > +/*
> > > > + * v4l2-connector.h
> > > > + *
> > > > + * V4L2 connector types.
> > > > + *
> > > > + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > > > + */
> > > > +
> > > > +#ifndef V4L2_CONNECTOR_H
> > > > +#define V4L2_CONNECTOR_H
> > > > +
> > > > +#define V4L2_CONNECTOR_MAX_LABEL 41
> > > 
> > > Hans pointed out this was a weird number. Should you turn the label
> > > field into a pointer to make this more generic (with a
> > > v4l2_fwnode_connector_cleanup() function then) ?
> > 
> > Yes, that would be the better approach. I will change that.
> > 
> > > > +
> > > > +/**
> > > > + * enum v4l2_connector_type - connector type
> > > > + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> > > > + * @V4L2_CON_COMPOSITE: analog composite connector
> > > > + * @V4L2_CON_SVIDEO:    analog svideo connector
> > > > + * @V4L2_CON_HDMI:      digital hdmi connector
> > > > + */
> > > > +enum v4l2_connector_type {
> > > > +	V4L2_CON_UNKNOWN,
> > > > +	V4L2_CON_COMPOSITE,
> > > > +	V4L2_CON_SVIDEO,
> > > > +	V4L2_CON_HDMI,
> > > > +};
> > > > +
> > > > +#endif /* V4L2_CONNECTOR_H */
> > > > +
> > > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > > index 6c07825e18b9..f4df1b95c5ef 100644
> > > > --- a/include/media/v4l2-fwnode.h
> > > > +++ b/include/media/v4l2-fwnode.h
> > > > @@ -22,6 +22,7 @@
> > > >  #include <linux/list.h>
> > > >  #include <linux/types.h>
> > > >  
> > > > +#include <media/v4l2-connector.h>
> > > >  #include <media/v4l2-mediabus.h>
> > > >  #include <media/v4l2-subdev.h>
> > > >  
> > > > @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> > > >  	unsigned int remote_port;
> > > >  };
> > > >  
> > > > +/**
> > > > + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > > > + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > > > + *                     if no restrictions are specified.
> > > > + */
> > > > +struct v4l2_fwnode_connector_analog {
> > > > +	v4l2_std_id supported_tvnorms;
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct v4l2_fwnode_connector - the connector data structure
> > > > + * @remote_port: identifier of the remote endpoint port the connector connects
> > > > + *		 to
> > > > + * @remote_id: identifier of the remote endpoint the connector connects to
> > > > + * @label: connetor label
> > > > + * @type: connector type
> > > > + * @connector: connector configuration
> > > > + * @connector.analog: analog connector configuration
> > > > + *                    &struct v4l2_fwnode_connector_analog
> > > > + */
> > > > +struct v4l2_fwnode_connector {
> > > > +	unsigned int remote_port;
> > > > +	unsigned int remote_id;
> > > > +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > > > +	enum v4l2_connector_type type;
> > > > +
> > > > +	union {
> > > > +		struct v4l2_fwnode_connector_analog analog;
> > > > +		/* future connectors */
> > > > +	} connector;
> > > > +};
> > > > +
> > > >  /**
> > > >   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> > > >   * @fwnode: pointer to the endpoint's fwnode handle
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-08-15 13:04         ` Marco Felsch
@ 2019-08-15 13:10           ` Laurent Pinchart
  2019-08-15 13:37             ` Marco Felsch
  0 siblings, 1 reply; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 13:10 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Marco,

On Thu, Aug 15, 2019 at 03:04:37PM +0200, Marco Felsch wrote:
> On 19-08-15 15:38, Laurent Pinchart wrote:
> > On Fri, Aug 09, 2019 at 09:55:36AM +0200, Marco Felsch wrote:
> >> On 19-05-16 19:36, Laurent Pinchart wrote:
> >>> On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> >>>> Currently every driver needs to parse the connector endpoints by it self.
> >>> 
> >>> s/it self/itself/
> >>> 
> >>>> This is the initial work to make this generic. The generic connector has
> >>>> some common fields and some connector specific parts. The generic one
> >>>> includes:
> >>>>   - type
> >>>>   - label
> >>>>   - remote_port (the port where the connector is connected to)
> >>>>   - remote_id   (the endpoint where the connector is connected to)
> >>> 
> >>> This assumes a single connection between a connector and a remote port,
> >>> and a single port on the connector side. Is this guaranteed ? For the
> >>> mini-DIN-4 connectors (often used for S-Video) for instance, I recall
> >>> from the extensive discussions we had in the past that they should be
> >>> modeled with two pins, one for the Y component and one for C components.
> >>> The rationale for this is to support systems where such a connector
> >>> could be used to carry S-Video, but also two composite video signals
> >>> (usually through an external adapter from 2 RCA female connectors to one
> >>> S-Video male connector) that would be routed to two separate video
> >>> decoders (or two different inputs of the same video decoder). Other
> >>> topologies may be possible too.
> >> 
> >> I got your concerns and I also remember the tvp5150 port bindings
> >> myself in the past. Do you know how often such a setup you described
> >> above happens these days? I would rather add more documentation to the
> >> bindings [1] and add a check to v4l2_fwnode_parse_connector() to
> >> guarantee that one port has only one endpoint. Because I don't think
> >> that analog connectors has a bright future these days.
> >> 
> >> [1] Documentation/devicetree/bindings/display/connector/ \
> >>     analog-tv-connector.txt
> > 
> > I have seen it on older hardware, I don't know about more recent
> > systems. For the S-Video case at least, you need to support two DT
> > ports, even if you don't support connecting them to two different
> > devices yet.
> 
> Can you take a look on the v7 I send a few minutes ago? I changed the
> layout ;)

I'll try to get to that ASAP, but I have a Rockchip driver to review
first :-)

> > In any case, I'm fine if those topologies are not supported yet, but it
> > should be possible to support them in a backward-compatible way. In
> > particular, in this case, we should make sure the DT bindings will allow
> > such topologies, and the DT parsing API should make it possible to
> > support them without fugure changes to drivers that use the API from
> > this patch for "simple" topologies.
> 
> You're right. I adapted the struct to be more extendible.
> 
> >>>> The specific fields are within a union, since only one of them can be
> >>>> available at the time. Since this is the initial support the patch adds
> >>>> only the analog-connector specific ones.
> >>>> 
> >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> >>>> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>> ---
> >>>> [1] https://patchwork.kernel.org/cover/10794703/
> >>>> 
> >>>> v6:
> >>>> - fix some spelling and style issues
> >>>> - rm unnecessary comments
> >>>> - drop vga and dvi connector
> >>>> 
> >>>> v2-v4:
> >>>> - nothing since the patch was squashed from series [1] into this
> >>>>   series.
> >>>> 
> >>>>  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> >>>>  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> >>>>  2 files changed, 63 insertions(+)
> >>>>  create mode 100644 include/media/v4l2-connector.h
> >>>> 
> >>>> diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> >>>> new file mode 100644
> >>>> index 000000000000..3a951c54f50e
> >>>> --- /dev/null
> >>>> +++ b/include/media/v4l2-connector.h
> >>>> @@ -0,0 +1,30 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0-only */
> >>>> +/*
> >>>> + * v4l2-connector.h
> >>>> + *
> >>>> + * V4L2 connector types.
> >>>> + *
> >>>> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> >>>> + */
> >>>> +
> >>>> +#ifndef V4L2_CONNECTOR_H
> >>>> +#define V4L2_CONNECTOR_H
> >>>> +
> >>>> +#define V4L2_CONNECTOR_MAX_LABEL 41
> >>> 
> >>> Hans pointed out this was a weird number. Should you turn the label
> >>> field into a pointer to make this more generic (with a
> >>> v4l2_fwnode_connector_cleanup() function then) ?
> >> 
> >> Yes, that would be the better approach. I will change that.
> >> 
> >>>> +
> >>>> +/**
> >>>> + * enum v4l2_connector_type - connector type
> >>>> + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> >>>> + * @V4L2_CON_COMPOSITE: analog composite connector
> >>>> + * @V4L2_CON_SVIDEO:    analog svideo connector
> >>>> + * @V4L2_CON_HDMI:      digital hdmi connector
> >>>> + */
> >>>> +enum v4l2_connector_type {
> >>>> +	V4L2_CON_UNKNOWN,
> >>>> +	V4L2_CON_COMPOSITE,
> >>>> +	V4L2_CON_SVIDEO,
> >>>> +	V4L2_CON_HDMI,
> >>>> +};
> >>>> +
> >>>> +#endif /* V4L2_CONNECTOR_H */
> >>>> +
> >>>> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> >>>> index 6c07825e18b9..f4df1b95c5ef 100644
> >>>> --- a/include/media/v4l2-fwnode.h
> >>>> +++ b/include/media/v4l2-fwnode.h
> >>>> @@ -22,6 +22,7 @@
> >>>>  #include <linux/list.h>
> >>>>  #include <linux/types.h>
> >>>>  
> >>>> +#include <media/v4l2-connector.h>
> >>>>  #include <media/v4l2-mediabus.h>
> >>>>  #include <media/v4l2-subdev.h>
> >>>>  
> >>>> @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> >>>>  	unsigned int remote_port;
> >>>>  };
> >>>>  
> >>>> +/**
> >>>> + * struct v4l2_fwnode_connector_analog - analog connector data structure
> >>>> + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> >>>> + *                     if no restrictions are specified.
> >>>> + */
> >>>> +struct v4l2_fwnode_connector_analog {
> >>>> +	v4l2_std_id supported_tvnorms;
> >>>> +};
> >>>> +
> >>>> +/**
> >>>> + * struct v4l2_fwnode_connector - the connector data structure
> >>>> + * @remote_port: identifier of the remote endpoint port the connector connects
> >>>> + *		 to
> >>>> + * @remote_id: identifier of the remote endpoint the connector connects to
> >>>> + * @label: connetor label
> >>>> + * @type: connector type
> >>>> + * @connector: connector configuration
> >>>> + * @connector.analog: analog connector configuration
> >>>> + *                    &struct v4l2_fwnode_connector_analog
> >>>> + */
> >>>> +struct v4l2_fwnode_connector {
> >>>> +	unsigned int remote_port;
> >>>> +	unsigned int remote_id;
> >>>> +	char label[V4L2_CONNECTOR_MAX_LABEL];
> >>>> +	enum v4l2_connector_type type;
> >>>> +
> >>>> +	union {
> >>>> +		struct v4l2_fwnode_connector_analog analog;
> >>>> +		/* future connectors */
> >>>> +	} connector;
> >>>> +};
> >>>> +
> >>>>  /**
> >>>>   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> >>>>   * @fwnode: pointer to the endpoint's fwnode handle

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support
  2019-08-15 12:48           ` Laurent Pinchart
@ 2019-08-15 13:14             ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:14 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel,
	Jacopo Mondi

Hi Laurent,

On 19-08-15 15:48, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Fri, Aug 09, 2019 at 02:16:06PM +0200, Marco Felsch wrote:
> > On 19-05-16 19:51, Laurent Pinchart wrote:
> > > On Tue, May 14, 2019 at 03:20:04PM -0300, Mauro Carvalho Chehab wrote:
> > >> Em Mon, 6 May 2019 12:10:41 +0200 Hans Verkuil escreveu:
> > >>> On 4/15/19 2:44 PM, Marco Felsch wrote:
> > >>>> The patch adds the initial connector parsing code, so we can move from a
> > >>>> driver specific parsing code to a generic one. Currently only the
> > >>>> generic fields and the analog-connector specific fields are parsed. Parsing
> > >>>> the other connector specific fields can be added by a simple callbacks.
> > >>>> 
> > >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > >>>> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > >>>> ---
> > >>>> [1] https://patchwork.kernel.org/cover/10794703/
> > >>>> 
> > >>>> v6:
> > >>>> - use 'unsigned int' count var
> > >>>> - fix comment and style issues
> > >>>> - place '/* fall through */' to correct places
> > >>>> - fix error handling and cleanup by releasing fwnode
> > >>>> - drop vga and dvi parsing support as those connectors are rarely used
> > >>>>   these days
> > >>>> 
> > >>>> v5:
> > >>>> - s/strlcpy/strscpy/
> > >>>> 
> > >>>> v2-v4:
> > >>>> - nothing since the patch was squashed from series [1] into this
> > >>>>   series.
> > >>>> 
> > >>>>  drivers/media/v4l2-core/v4l2-fwnode.c | 111 ++++++++++++++++++++++++++
> > >>>>  include/media/v4l2-fwnode.h           |  16 ++++
> > >>>>  2 files changed, 127 insertions(+)
> > >>>> 
> > >>>> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > >>>> index 20571846e636..f1cca95c8fef 100644
> > >>>> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > >>>> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > >>>> @@ -592,6 +592,117 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > >>>>  }
> > >>>>  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > >>>>  
> > >>>> +static const struct v4l2_fwnode_connector_conv {
> > >>>> +	enum v4l2_connector_type type;
> > >>>> +	const char *name;
> > > 
> > > Maybe compatible instead of name ?
> > 
> > Okay, I can change that.
> > 
> > >>>> +} connectors[] = {
> > >>>> +	{
> > >>>> +		.type = V4L2_CON_COMPOSITE,
> > >>>> +		.name = "composite-video-connector",
> > >>>> +	}, {
> > >>>> +		.type = V4L2_CON_SVIDEO,
> > >>>> +		.name = "svideo-connector",
> > >>>> +	}, {
> > >>>> +		.type = V4L2_CON_HDMI,
> > >>>> +		.name = "hdmi-connector",
> > >>>> +	},
> > >>>> +};
> > >>>> +
> > >>>> +static enum v4l2_connector_type
> > >>>> +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > >>>> +{
> > >>>> +	unsigned int i;
> > >>>> +
> > >>>> +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > >>>> +		if (!strcmp(con_str, connectors[i].name))
> > >>>> +			return connectors[i].type;
> > >>>> +
> > >>>> +	/* no valid connector found */
> > > 
> > > The usual comment style in this file is to start with a capital letter
> > > and end sentences with a period. I would however drop this comment, it's
> > > not very useful. The other comments should be updated accordingly.
> > 
> > I will change my comments and drop this one.
> > 
> > >>>> +	return V4L2_CON_UNKNOWN;
> > >>>> +}
> > >>>> +
> > >>>> +static int
> > >>>> +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > >>>> +				   struct v4l2_fwnode_connector *vc)
> > >>>> +{
> > >>>> +	u32 tvnorms;
> > >>>> +	int ret;
> > >>>> +
> > >>>> +	ret = fwnode_property_read_u32(fwnode, "tvnorms", &tvnorms);
> > >>>> +
> > >>>> +	/* tvnorms is optional */
> > >>>> +	vc->connector.analog.supported_tvnorms = ret ? V4L2_STD_ALL : tvnorms;
> > >>>> +
> > >>>> +	return 0;
> > >>>> +}
> > >>>> +
> > > 
> > > Please document all exported functions with kerneldoc.
> > 
> > It is documented within the header file. To be aligned with the other
> > functions I wouldn't change that.
> 
> It's not your fault, but this policy REALLY makes review painful and is
> EXTREMELY annoying.

I'm with you..

> > >>>> +int v4l2_fwnode_parse_connector(struct fwnode_handle *__fwnode,
> > >>>> +				struct v4l2_fwnode_connector *connector)
> > >>>> +{
> > >>>> +	struct fwnode_handle *fwnode;
> > >>>> +	struct fwnode_endpoint __ep;
> > >>>> +	const char *c_type_str, *label;
> > >>>> +	int ret;
> > >>>> +
> > >>>> +	memset(connector, 0, sizeof(*connector));
> > >>>> +
> > >>>> +	fwnode = fwnode_graph_get_remote_port_parent(__fwnode);
> > > 
> > > I would rename the argument __fwnode to fwnode, and rename the fwnode
> > > variable to remote (or similar) to make this clearer.
> > 
> > Okay.
> > 
> > >>>> +	if (!fwnode)
> > >>>> +		return -EINVAL;
> > > 
> > > Is EINVAL the right error here ? Wouldn't it be useful for the caller to
> > > differentiate between unconnected connector nodes and invalid ones ?
> > 
> > Yes it would. Should I return ENOLINK instead?
> 
> Good idea.

Good because I used it in my v7 :-)

> > >>>> +
> > >>>> +	/* parse all common properties first */
> > >>>> +	/* connector-type is stored within the compatible string */
> > >>>> +	ret = fwnode_property_read_string(fwnode, "compatible", &c_type_str);
> > > 
> > > Prefixing or postfixing names with types is usually frowned upon. You
> > > could rename this to type_name for instance.
> > 
> > Okay.
> > 
> > >>>> +	if (ret) {
> > >>>> +		fwnode_handle_put(fwnode);
> > >>>> +		return -EINVAL;
> > >>>> +	}
> > >>>> +
> > >>>> +	connector->type = v4l2_fwnode_string_to_connector_type(c_type_str);
> > >>>> +
> > >>>> +	fwnode_graph_parse_endpoint(__fwnode, &__ep);
> > >>>> +	connector->remote_port = __ep.port;
> > >>>> +	connector->remote_id = __ep.id;
> > >>>> +
> > >>>> +	ret = fwnode_property_read_string(fwnode, "label", &label);
> > >>>> +	if (!ret) {
> > >>>> +		/* ensure label doesn't exceed V4L2_CONNECTOR_MAX_LABEL size */
> > >>>> +		strscpy(connector->label, label, V4L2_CONNECTOR_MAX_LABEL);
> > >>>> +	} else {
> > >>>> +		/*
> > >>>> +		 * labels are optional, if none is given create one:
> > >>>> +		 * <connector-type-string>@port<endpoint_port>/ep<endpoint_id>
> > >>>> +		 */
> > >>>> +		snprintf(connector->label, V4L2_CONNECTOR_MAX_LABEL,
> > >>>> +			 "%s@port%u/ep%u", c_type_str, connector->remote_port,
> > >>>> +			 connector->remote_id);
> > > 
> > > Should we really try to create labels when none is available ? If so
> > > this needs much more careful thoughts, we need to think about what the
> > > label will be used for, and create a good naming scheme accordingly. If
> > > the label will be displayed to the end-user I don't think the above name
> > > would be very useful, it would be best to leave it empty and let
> > > applications create a name based on the connector type and other
> > > information they have at their disposal.
> > 
> > Hm.. I don't have a strong opinion on that. If the others are with you I
> > will leave it empty.
> > 
> > >>>> +	}
> > >>>> +
> > >>>> +	/* now parse the connector specific properties */
> > >>>> +	switch (connector->type) {
> > >>>> +	case V4L2_CON_COMPOSITE:
> > >>>> +		/* fall through */
> > > 
> > > I don't think you need a fall-through comment when the two cases are
> > > adjacent with no line in-between.
> > 
> > Hm.. I don't know the compiler behaviour. According the official
> > gcc documentation [1] I would not leave that.
> 
> Not leave the fall-through comment, and thus remove it ? :-) I really
> think it's not needed (otherwise imagine how the big switch-case in
> v4l2-ctrls.c would look like for instance).

Yes you're right. I dopped that in my v7.

> 
> > [1] https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
> > 
> > >>>> +	case V4L2_CON_SVIDEO:
> > >>>> +		ret = v4l2_fwnode_connector_parse_analog(fwnode, connector);
> > >>>> +		break;
> > >>>> +	case V4L2_CON_HDMI:
> > >>>> +		pr_warn("Connector specific parsing is currently not supported for %s\n",
> > >>>> +			c_type_str);  
> > >>> 
> > >>> Why warn? Just drop this.
> > >> 
> > >> good point. I would prefer to have some warning here, in order to warn a
> > >> developer that might be using it that this part of the code would require 
> > >> some change.
> > >> 
> > >> perhaps pr_warn_once()?
> > >>
> > >>>> +		ret = 0;
> > >>>> +		break;
> > > 
> > > If it's not supported we should warn and return an error. Otherwise we
> > > should be silent and return success. Combining a warning with success
> > > isn't a good idea, this is either a normal case or an error, not both.
> > 
> > The generic part still applies and is valid. That was the reason why I
> > did return success.
> 
> But the HDMI-specific part won't work, so the code will likely not
> operate correctly. I'd rather make it an error to for developers using
> HDMI connectors to fix it.

Hm.. Since you and Hans have your concerns about it I can change that
behaviour.

Regards,
  Marco

> > >>>> +	case V4L2_CON_UNKNOWN:
> > >>>> +		/* fall through */
> > >>>> +	default:
> > >>>> +		pr_err("Unknown connector type\n");
> > >>>> +		ret = -EINVAL;
> > >>>> +	};
> > >>>> +
> > >>>> +	fwnode_handle_put(fwnode);
> > >>>> +
> > >>>> +	return ret;
> > >>>> +}
> > >>>> +EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_connector);
> > >>>> +
> > >>>>  static int
> > >>>>  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > >>>>  					  struct v4l2_async_notifier *notifier,
> > >>>> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > >>>> index f4df1b95c5ef..e072f2915ddb 100644
> > >>>> --- a/include/media/v4l2-fwnode.h
> > >>>> +++ b/include/media/v4l2-fwnode.h
> > >>>> @@ -269,6 +269,22 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > >>>>   */
> > >>>>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > >>>>  
> > > 
> > > And I see here that the function is documented. One more reason to move
> > > kerneldoc to the .c files...
> > 
> > Please check my comment above.
> 
> I know, it's not your fault, I was complaining about the state of the
> universe in general :-)
> 
> > >>>> +/**
> > >>>> + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > >>>> + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > >>>> + *          connected to
> > > 
> > > This is very unclear, I would interpret that as the remote endpoint, not
> > > the local endpoint. Could you please try to clarify the documentation ?
> > 
> > Hm.. I have no good idea how I should describe it..
> > 
> > """
> > The device (local) endpoint fwnode handle on which the connector is
> > connected to using the remote-enpoint property.
> > """
> > 
> > >>>> + * @connector: pointer to the V4L2 fwnode connector data structure
> > >>>> + *
> > >>>> + * Fill the connector data structure with the connector type, label and the
> > >>>> + * endpoint id and port where the connector belongs to. If no label is present
> > >>>> + * a unique one will be created. Labels with more than 40 characters are cut.
> > >>>> + *
> > >>>> + * Return: %0 on success or a negative error code on failure:
> > >>>> + *	   %-EINVAL on parsing failure
> > >>>> + */
> > >>>> +int v4l2_fwnode_parse_connector(struct fwnode_handle *fwnode,
> > >>>> +				struct v4l2_fwnode_connector *connector);
> > >>>> +
> > >>>>  /**
> > >>>>   * typedef parse_endpoint_func - Driver's callback function to be called on
> > >>>>   *	each V4L2 fwnode endpoint.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-08-15 12:51         ` Laurent Pinchart
@ 2019-08-15 13:22           ` Marco Felsch
  2019-08-15 13:26             ` Laurent Pinchart
  0 siblings, 1 reply; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:22 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel

Hi Laurent,

On 19-08-15 15:51, Laurent Pinchart wrote:
> On Tue, Aug 13, 2019 at 10:54:29AM +0200, Marco Felsch wrote:
> > Hi Laurent,
> > 
> > On 19-05-16 21:03, Laurent Pinchart wrote:
> > > Hello Marco,
> > > 
> > > Thank you for the patch.
> > > 
> > > On Tue, May 14, 2019 at 03:25:45PM -0300, Mauro Carvalho Chehab wrote:
> > > > Em Mon, 15 Apr 2019 14:44:05 +0200 Marco Felsch escreveu:
> > > > 
> > > > > This patch adds the of_graph support to describe the tvp connections.
> > > > > Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> > > > > of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> > > > > connector must be conneted to port@0/endpoint@1, look at the Documentation
> > > 
> > > According to [2], it must be connected to port port@0 and port@1, not
> > > just port@0.
> > 
> > You're right. I missed that.. I will change that for the v7.
> > 
> > > > > for more information. Since the TVP5150 is a converter the device-tree
> > > > > must contain at least 1-input and 1-output port. The mc-connectors and
> > > > > mc-links are only created if the device-tree contains the corresponding
> > > > > connector nodes. If more than one connector is available the
> > > > > media_entity_operations.link_setup() callback ensures that only one
> > > > > connector is active.
> > > > > 
> > > > > [1] https://www.spinics.net/lists/linux-media/msg138545.html
> > > > > [2] https://www.spinics.net/lists/linux-media/msg138546.html
> > > > > 
> > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > > ---
> > > > > Changelog:
> > > > > 
> > > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > > [2] https://patchwork.kernel.org/cover/10786553/
> > > > > 
> > > > > v6:
> > > > > - fix misspelled comments
> > > > > - use 'unsigned int' where it's possible
> > > > > - cleanup ifdef part-2:
> > > > >   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
> > > > >     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> > > > > - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
> > > > >   internal function do this.
> > > > > - tvp5150_add_of_connectors: call within probe() to make it cleaner
> > > > > - tvp5150_parse_dt: move local loop vars within the loop.
> > > > > 
> > > > > v5:
> > > > > - Fixing build deps:
> > > > >   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
> > > > >   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
> > > > >     includes. This leads into to complex deps for futher development.
> > > > >   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
> > > > >   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
> > > > >   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> > > > > 
> > > > > - Simplify link_setup routine:
> > > > >   - use generic connector parsing since both series [1,2] are squashed into
> > > > >     one
> > > > >   - struct tvp5150: drop pads_state and modify_second_link property
> > > > >     due to link_setup() rework.
> > > > >   - tvp5150_link_setup: add more comments
> > > > >   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
> > > > >     link directly within the driver instead of a recursive media-framework
> > > > >     call (__media_entity_setup_link). This improves the readability and
> > > > >     shrinks the driver code.
> > > > >   - tvp5150_link_setup: disable all active links in case user switches
> > > > >     connectors without disable it first.
> > > > >   - tvp5150_registered: simplify default link enable path due to link_setup()
> > > > >     rework.
> > > > > 
> > > > > - General cleanups
> > > > >   - tvp5150_parse_dt: drop unecessary test
> > > > >   - tvp5150_parse_dt: add err message due to misconfiguration
> > > > >   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
> > > > >   - s/dev_dbg/dev_dbg_lvl
> > > > > 
> > > > > v4:
> > > > >  - rebase on top of media_tree/master, fix merge conflict due to commit
> > > > >    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
> > > > >    to zero")
> > > > > 
> > > > > v3:
> > > > > - probe(): s/err/err_free_v4l2_ctrls
> > > > > - drop MC dependency for tvp5150_pads
> > > > > 
> > > > > v2:
> > > > > - adapt commit message
> > > > > - unify ifdef switches
> > > > > - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> > > > > - mc: use 2-input and 1-output pad
> > > > > - mc: link svideo connector to both input pads
> > > > > - mc: enable/disable svideo links in one go
> > > > > - mc: change link_setup() behaviour, switch the input src don't require a
> > > > >       explicite disable before.
> > > > > - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> > > > > - mc: enable link to the first available connector and set the
> > > > >       corresponding tvp5150 input src per default during registered()
> > > > > - mc/of: factor out oftree connector allocation
> > > > > - of: drop svideo dt port
> > > > > - of: move svideo connector to port@0/endpoint@1
> > > > > - of: require at least 1-in and 1-out endpoint
> > > > > 
> > > > >  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
> > > > >  1 file changed, 370 insertions(+), 39 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > > > index 89da921c8886..4e3228b2ccbc 100644
> > > > > --- a/drivers/media/i2c/tvp5150.c
> > > > > +++ b/drivers/media/i2c/tvp5150.c
> > > > > @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
> > > > >  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
> > > > >  
> > > > >  enum tvp5150_pads {
> > > > > -	TVP5150_PAD_IF_INPUT,
> > > > > +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> > > > > +	TVP5150_PAD_AIP1B,
> > > > >  	TVP5150_PAD_VID_OUT,
> > > > >  	TVP5150_NUM_PADS
> > > > >  };
> > > > >  
> > > > > +struct tvp5150_connector {
> > > > > +	struct v4l2_fwnode_connector base;
> > > > > +	struct media_entity ent;
> > > > > +	struct media_pad pad;
> > > > > +};
> > > > > +
> > > > >  struct tvp5150 {
> > > > >  	struct v4l2_subdev sd;
> > > > > -#ifdef CONFIG_MEDIA_CONTROLLER
> > > > > +	/* additional endpoint for the svideo connector */
> > > 
> > > Could you please capitalize the first word of all comments to match the
> > > driver style ?
> > 
> > Okay, I will check it for my v7.
> > 
> > > > > +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> > > 
> > > As the endpoints are only used at probe time, I would declare this as a
> > > local variable in the probe function and pass it to both
> > > tvp5150_add_of_connectors() and tvp5150_parse_dt(). If you order the
> > > calls correctly it should simplify the probe error handling.
> > 
> > Yes that could be also a solution. I took Jacopo's comments and
> > refactored the code so the endpoints no longer needed in my v7.
> > 
> > > > > +	unsigned int endpoints_num;
> > > > > +
> > > > > +	/* media-ctl properties */
> > > 
> > > media-ctl makes me think about the userspace application, maybe "Media
> > > controller properties" ?
> > 
> > I've dopped that comment becuase it is to obvious..
> > 
> > > > >  	struct media_pad pads[TVP5150_NUM_PADS];
> > > > > -#endif
> > > > > +	struct tvp5150_connector *connectors;
> > > > > +	int connectors_num;
> > > 
> > > unsigned int ?
> > 
> > Of course.
> > 
> > > > > +
> > > > >  	struct v4l2_ctrl_handler hdl;
> > > > >  	struct v4l2_rect rect;
> > > > >  	struct regmap *regmap;
> > > > > @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > +/****************************************************************************
> > > > > + *			Media entity ops
> > > > > + ****************************************************************************/
> > > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > 
> > > Should we depend on CONFIG_MEDIA_CONTROLLER instead, especially since
> > > you remove the similar conditional in the struct tvp5150 definition and
> > > in the probe function ?
> > 
> > I don't know if we can add the dependency without worries because the
> > tvp5150 is also used by the usb/em28xx devices which can be build
> > without CONFIG_MEDIA_CONTROLLER support. During .probe() a stub function
> > will be called if CONFIG_MEDIA_CONTROLLER isn't enabled.
> > 
> > > > > +static int tvp5150_set_link(struct media_pad *connector_pad,
> > > > > +			    struct media_pad *tvp5150_pad, u32 flags)
> > > > > +{
> > > > > +	struct media_link *link;
> > > > > +
> > > > > +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> > > > > +	if (!link)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	link->flags = flags;
> > > > > +	link->reverse->flags = link->flags;
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> > > > > +{
> > > > > +	struct media_pad *connector_pad;
> > > > > +	unsigned int i;
> > > > > +	int err;
> > > > > +
> > > > > +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > > > > +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> > > > > +		if (!connector_pad)
> > > > > +			continue;
> > > > > +
> > > > > +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> > > > > +		if (err)
> > > > > +			return err;
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> > > > > +			     u32 config);
> > > > > +
> > > > > +static int tvp5150_link_setup(struct media_entity *entity,
> > > > > +			      const struct media_pad *tvp5150_pad,
> > > > > +			      const struct media_pad *remote, u32 flags)
> > > > > +{
> > > > > +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> > > > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > > > +	struct media_pad *other_tvp5150_pad =
> > > > > +		&decoder->pads[tvp5150_pad->index ^ 1];
> > > > > +	bool is_svideo = false;
> > > > > +	unsigned int i;
> > > > > +	int err;
> > > > > +
> > > > > +	/*
> > > > > +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> > > > > +	 * Enabling or disabling the source pad link has no effect.
> > > > > +	 */
> > > > > +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> > > > > +		return 0;
> > > > > +
> > > > > +	/* Check if the svideo connector should be enabled */
> > > > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > > > +		if (remote->entity == &decoder->connectors[i].ent) {
> > > > 
> > > > > +			is_svideo =
> > > > > +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > > > 
> > > > Nitpick:
> > > > 
> > > > I would actually prefer to keep this on a single line. Ok, it will violate
> > > > the 80-columns, but it would be better than the above (IMHO).
> > > > 
> > > > > +			break;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> > > > > +		    remote->entity->name, remote->index,
> > > > > +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> > > > > +		    flags & MEDIA_LNK_FL_ENABLED);
> > > > > +	if (is_svideo)
> > > > > +		dev_dbg_lvl(sd->dev, 1, debug,
> > > > > +			    "link setup '%s':%d->'%s':%d[%d]",
> > > > > +			    remote->entity->name, remote->index,
> > > > > +			    other_tvp5150_pad->entity->name,
> > > > > +			    other_tvp5150_pad->index,
> > > > > +			    flags & MEDIA_LNK_FL_ENABLED);
> > > > > +
> > > > > +	/*
> > > > > +	 * The TVP5150 has an internal mux which allows the following setup:
> > > > > +	 *
> > > > > +	 * comp-connector1  --\
> > > > > +	 *		       |---> AIP1A
> > > > > +	 *		      /
> > > > > +	 * svideo-connector -|
> > > > > +	 *		      \
> > > > > +	 *		       |---> AIP1B
> > > > > +	 * comp-connector2  --/
> > > > > +	 *
> > > > > +	 * We can't rely on user space that the current connector gets disabled
> > > > > +	 * first before enabling the new connector. Disable all active
> > > > > +	 * connector links to be on the safe side.
> > > > > +	 */
> > > > > +	err = tvp5150_disable_all_input_links(decoder);
> > > > > +	if (err)
> > > > > +		return err;
> > > > > +
> > > > > +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> > > > > +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> > > > > +			  TVP5150_BLACK_SCREEN, 0);
> > > > > +
> > > > > +	if (flags & MEDIA_LNK_FL_ENABLED) {
> > > > > +		/*
> > > > > +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > > > > +		 * Both links must be enabled in one-shot regardless which link
> > > > > +		 * the user requests.
> > > > > +		 */
> > > 
> > > This is a very grey area, I don't think the MC API explicitly allows
> > > doing this. As changing links during streaming is disallowed, wouldn't
> > > it be easier to handle the routing configuration at stream start ? You
> > > wouldn't have to deal with this issue then, you could just return an
> > > error if only one link is enabled. Furthermore, it would allow
> > > supporting a configuration where a composite signal is connected to the
> > > Y pin of the mini-DIN connector.
> > 
> > We discussed this a few series earlier because my first solution what
> > like this you describe above. I changed that because Mauro had some
> > concerns about the usability. Now this behaviour is easier to use but
> > as you pointed out above, such 'special' handling isn't doable anymore.
> > I would keep this solution since I want to get this series merged ;)
> > If someone wants such a 'special' configuration he can implement it
> > later.
> 
> But that would break the ABI. I'm sorry, but we need to find an
> agreement on this issue to merge the series, it's not a detail that can
> be addressed later. Could you start a discussion with Mauro to see if he
> can be convinced, or if he has a better proposal ?

You're right this would break the ABI or needs some special later on
handling introducing new dt-bindings...

Unfortunately this is the result of Mauro's proposal and I have no good
arguments against it.

Regards,
  Marco

> > > > > +		if (is_svideo) {
> > > > > +			err = tvp5150_set_link((struct media_pad *) remote,
> > > > > +					       other_tvp5150_pad, flags);
> > > > > +			if (err)
> > > > > +				return err;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct media_entity_operations tvp5150_sd_media_ops = {
> > > > > +	.link_setup = tvp5150_link_setup,
> > > > > +};
> > > > > +#endif
> > > > >  /****************************************************************************
> > > > >  			I2C Command
> > > > >   ****************************************************************************/
> > > > > @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > +static int tvp5150_registered(struct v4l2_subdev *sd)
> > > > > +{
> > > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > > > +	unsigned int i;
> > > > > +	int ret;
> > > > > +
> > > > > +	/*
> > > > > +	 * Setup connector pads and links. Enable the link to the first
> > > > > +	 * available connector per default.
> > > > > +	 */
> > > > > +	for (i = 0; i < decoder->connectors_num; i++) {
> > > > > +		struct media_entity *con = &decoder->connectors[i].ent;
> > > > > +		struct media_pad *pad = &decoder->connectors[i].pad;
> > > > > +		unsigned int port = decoder->connectors[i].base.remote_port;
> > > > > +		bool is_svideo =
> > > > > +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> > > > > +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> > > 
> > > The flags passed to media_create_pad_link() are unsigned.
> > 
> > You are right, changed that.
> > 
> > > > > +
> > > > > +		pad->flags = MEDIA_PAD_FL_SOURCE;
> > > > > +		ret = media_entity_pads_init(con, 1, pad);
> > > > > +		if (ret < 0)
> > > > > +			return ret;
> > > > > +
> > > > > +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> > > > > +		if (ret < 0)
> > > > > +			return ret;
> > > > > +
> > > > > +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> > > > > +		if (ret < 0) {
> > > > > +			media_device_unregister_entity(con);
> > > > > +			return ret;
> > > > > +		}
> > > 
> > > Will the other registered media entities be unregistered correctly ?
> > 
> > Good point. I add a seperate error handling to ensure all registered
> > entities gets unregistered.
> > 
> > > > > +
> > > > > +		if (is_svideo) {
> > > > > +			/* svideo links to both aip1a and aip1b */
> > > > > +			ret = media_create_pad_link(con, 0, &sd->entity,
> > > > > +						    port + 1, flags);
> > > 
> > > Does the TVP5150 support both connecting Y to AIP1A and C to AIP1B, and
> > > Y to AIP1B and C to AIP1A ? If so the port + 1 won't always work.
> > 
> > No, if I understood the datasheet right Y is always connected to AIP1A
> > and C to AIP1B. Since I improved the struct v4l2_fwnode_connector to
> > hold more connector-port information the 'port+1' logic isn't used
> > anymore.
> > 
> > > > > +			if (ret < 0) {
> > > > > +				media_device_unregister_entity(con);
> > > > > +				return ret;
> > > > > +			}
> > > > > +		}
> > > > > +
> > > > > +		/* enable default input */
> > > > > +		if (flags == MEDIA_LNK_FL_ENABLED) {
> > > > > +			decoder->input =
> > > > > +				is_svideo ? TVP5150_SVIDEO :
> > > > > +				port == 0 ? TVP5150_COMPOSITE0 :
> > > > > +				TVP5150_COMPOSITE1;
> > > > > +
> > > > > +			tvp5150_selmux(sd);
> > > > > +		}
> > > 
> > > You could move this after the loop and operation on
> > > decoder->connectors[0]. Hopefully you could then use if's instead of
> > > nested ? : operators, as the above isn't very readable.
> > 
> > That's also doable. Mauro which solution do you prefer?
> > 
> > > > > +	}
> > > > > +#endif
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +
> > > 
> > > One blank line is enough.
> > 
> > Fixed.
> > 
> > > > >  /* ----------------------------------------------------------------------- */
> > > > >  
> > > > >  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> > > > > @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
> > > > >  	.pad = &tvp5150_pad_ops,
> > > > >  };
> > > > >  
> > > > > +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> > > > > +	.registered = tvp5150_registered,
> > > > > +};
> > > > > +
> > > > >  /****************************************************************************
> > > > >  			I2C Client & Driver
> > > > >   ****************************************************************************/
> > > > > @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > > +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > > > >  {
> > > > > -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> > > > > -	struct device_node *ep;
> > > > > -	unsigned int flags;
> > > > > -	int ret = 0;
> > > > > +	struct device *dev = decoder->sd.dev;
> > > 
> > > You use dev in a singla location, I think you could use decoder->sd.dev
> > > directly.
> > 
> > This function is no longer used but you're right.
> > 
> > > 
> > > > > +	struct tvp5150_connector *connectors;
> > > > > +	unsigned int connectors_num = decoder->connectors_num;
> > > > > +	int i, ret;
> > > 
> > > i is never negative, you can make it an unsiged int.
> > > 
> > > > >  
> > > > > -	ep = of_graph_get_next_endpoint(np, NULL);
> > > > > -	if (!ep)
> > > > > -		return -EINVAL;
> > > > > +	/*
> > > > > +	 * Only add of_connectors if device really is a OF device since
> > > > > +	 * the driver is used by usb devices e.g. em28xx and embedded
> > > > > +	 * devices.
> > > > > +	 */
> > > > > +	if (!decoder->connectors_num)
> > > 
> > > Maybe if (!connectors_num) ?
> > > 
> > > > > +		return 0;
> > > > >  
> > > > > -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> > > > > -	if (ret)
> > > > > -		goto err;
> > > > > +	/* Allocate and initialize all available input connectors */
> > > > > +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> > > > > +				  GFP_KERNEL);
> > > > > +	if (!connectors)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	for (i = 0; i < connectors_num; i++) {
> > > > > +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> > > > > +
> > > > > +		ret = v4l2_fwnode_parse_connector(
> > > > > +				   of_fwnode_handle(decoder->endpoints[i]), c);
> > > 
> > > I think you should handle errors here.
> > > 
> > > > > +
> > > > > +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> > > > > +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> > > > > +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> > > > > +		connectors[i].ent.name = c->label;
> > > 
> > > I don't think using the label as the entity name is a good idea, as we
> > > require entity names to be unique, and labels offer no such guarantee.
> > 
> > Good point. What about <connector dt-name>:<label>? The devicetree name
> > is unique.
> 
> That should work. Is there a risk it wouldn't fit in the entity name
> field though ?
> 
> > > > > +	}
> > > > > +
> > > > > +	decoder->connectors = connectors;
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int tvp5150_mc_init(struct tvp5150 *decoder)
> > > > > +{
> > > > > +	struct v4l2_subdev *sd = &decoder->sd;
> > > > > +	unsigned int i;
> > > > > +
> > > > > +	sd->entity.ops = &tvp5150_sd_media_ops;
> > > > > +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > > > +
> > > > > +	/* Initialize all TVP5150 pads */
> > > > > +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> > > > > +		if (i < TVP5150_NUM_PADS - 1) {
> > > > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > > > > +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > > > > +		} else {
> > > > > +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > > > > +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> > > > > +		}
> > > > > +	}
> > > 
> > > You can simplify this to
> > > 
> > > 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> > > 		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> > > 		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> > > 	}
> > > 
> > > 	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> > > 	decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> > 
> > Yes, already done.
> > 
> > > > > +
> > > > > +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> > > > > +				      decoder->pads);
> > > > > +}
> > > > > +
> > > > > +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> > > > > +
> > > > > +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> > > > > +{
> > > > > +	return 0;
> > > > > +}
> > > > >  
> > > > > -	flags = bus_cfg.bus.parallel.flags;
> > > > > +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> > > > > +{
> > > > > +	return 0;
> > > > > +}
> > > > > +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
> > > > >  
> > > > > -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > > > -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > > > -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > > > -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > > > +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > > > +{
> > > > > +	struct device *dev = decoder->sd.dev;
> > > > > +	struct device_node *ep_np;
> > > > > +	unsigned int i = 0, in = 0;
> > > 
> > > Let's rename in to num_inputs or num_connectors.
> > 
> > I refactored the code, so in is no longer used.
> > 
> > > > > +	int ret;
> > > > > +	bool found = false;
> > > > > +
> > > > > +	/* at least 1 output and 1 input */
> > > > > +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> > > > > +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> > > > > +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
> > > > >  		ret = -EINVAL;
> > > > >  		goto err;
> > > > >  	}
> > > > >  
> > > > > -	decoder->mbus_type = bus_cfg.bus_type;
> > > > > +	for_each_endpoint_of_node(np, ep_np) {
> > > > > +		struct v4l2_fwnode_endpoint bus_cfg = {
> > > > > +			.bus_type = V4L2_MBUS_UNKNOWN
> > > > > +		};
> > > > > +		struct v4l2_fwnode_connector c;
> > > > > +		struct of_endpoint ep;
> > > > > +		unsigned int flags;
> > > > > +
> > > > > +		of_graph_parse_endpoint(ep_np, &ep);
> > > > > +		switch (ep.port) {
> > > > > +		case TVP5150_PAD_AIP1A:
> > > > > +			/* fall through */
> > > 
> > > I don't think you need this comment.
> > > 
> > > > > +		case TVP5150_PAD_AIP1B:
> > > > > +			ret = v4l2_fwnode_parse_connector(
> > > > > +						   of_fwnode_handle(ep_np), &c);
> > > 
> > > You use of_fwnode_handle(ep_np) twice, you could move it outside of the
> > > switch () to keep lines shorter.
> > > 
> > > > > +			if (c.type != V4L2_CON_COMPOSITE &&
> > > > > +			    c.type != V4L2_CON_SVIDEO) {
> > > > > +				dev_err(dev,
> > > > > +					"Invalid endpoint %d on port %d\n",
> > > 
> > > The correct format specifier for unsigned int is %u.
> > > 
> > > Should the error message be more explicit ? "Invalid connector type for
> > > port@%u/endpoint@%u" ?
> > > 
> > > 
> > > > > +					c.remote_id, c.remote_port);
> > > > > +				ret = -EINVAL;
> > > > > +				goto err;
> > > 
> > > If you break out of the loop you need an of_node_put(ep_np).
> > > Alternatively, you could store ep_np in the endpoints array right before
> > > of_graph_parse_endpoint() and call of_node_put() right after
> > > of_graph_parse_endpoint().
> > > 
> > > > > +			}
> > > > > +			in++;
> > > > > +			break;
> > > > > +		case TVP5150_PAD_VID_OUT:
> > > > > +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> > > > > +							 &bus_cfg);
> > > > > +			if (ret)
> > > > > +				goto err;
> > > > > +
> > > > > +			flags = bus_cfg.bus.parallel.flags;
> > > > > +
> > > > > +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> > > > > +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> > > > > +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> > > > > +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> > > > > +				ret = -EINVAL;
> > > > > +				goto err;
> > > > > +			}
> > > > > +
> > > > > +			decoder->mbus_type = bus_cfg.bus_type;
> > > > > +			break;
> > > > > +		default:
> > > > > +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> > > 
> > > %u here too.
> > > 
> > > > > +				ep.port, ep.local_node);
> > > > > +			ret = -EINVAL;
> > > > > +			goto err;
> > > > > +		}
> > > > > +
> > > > > +		of_node_get(ep_np);
> > > > > +		decoder->endpoints[i] = ep_np;
> > > > > +		i++;
> > > > > +
> > > > > +		found = true;
> > > > > +	}
> > > > >  
> > > > > +	decoder->connectors_num = in;
> > > > > +	return found ? 0 : -ENODEV;
> > > > >  err:
> > > > > -	of_node_put(ep);
> > > > >  	return ret;
> > > 
> > > You can remove the err label and return ret directly.
> > 
> > I took your comments into account for the refactored function, thanks.
> > 
> > > > >  }
> > > > >  
> > > > > +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> > > > > +{
> > > > > +	unsigned int i;
> > > > > +
> > > > > +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> > > > > +		of_node_put(decoder->endpoints[i]);
> > > > > +}
> > > > > +
> > > > >  static const char * const tvp5150_test_patterns[2] = {
> > > > >  	"Disabled",
> > > > >  	"Black screen"
> > > > > @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > > > >  		res = tvp5150_parse_dt(core, np);
> > > > >  		if (res) {
> > > > >  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> > > > > -			return res;
> > > > > +			goto err_cleanup_dt;
> > > > >  		}
> > > > >  	} else {
> > > > >  		/* Default to BT.656 embedded sync */
> > > > > @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
> > > > >  	}
> > > > >  
> > > > >  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> > > > > +	sd->internal_ops = &tvp5150_internal_ops;
> > > > >  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > > > >  
> > > > > -#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > > -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> > > > > -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> > > > > -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> > > > > -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> > > > > -
> > > > > -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> > > > > -
> > > > > -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> > > > > -	if (res < 0)
> > > > > -		return res;
> > > > > +	res = tvp5150_mc_init(core);
> > > > > +	if (res)
> > > > > +		goto err_cleanup_dt;
> > > > >  
> > > > > -#endif
> > > > > +	res = tvp5150_add_of_connectors(core);
> > > > > +	if (res)
> > > > > +		goto err_cleanup_dt;
> > > > >  
> > > > >  	res = tvp5150_detect_version(core);
> > > > >  	if (res < 0)
> > > > > -		return res;
> > > > > +		goto err_cleanup_dt;
> > > > >  
> > > > >  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > > > >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > > > > @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
> > > > >  	sd->ctrl_handler = &core->hdl;
> > > > >  	if (core->hdl.error) {
> > > > >  		res = core->hdl.error;
> > > > > -		goto err;
> > > > > +		goto err_free_v4l2_ctrls;
> > > > >  	}
> > > > >  
> > > > >  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> > > > > @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
> > > > >  						tvp5150_isr, IRQF_TRIGGER_HIGH |
> > > > >  						IRQF_ONESHOT, "tvp5150", core);
> > > > >  		if (res)
> > > > > -			goto err;
> > > > > +			goto err_free_v4l2_ctrls;
> > > > >  	}
> > > > >  
> > > > >  	res = v4l2_async_register_subdev(sd);
> > > > >  	if (res < 0)
> > > > > -		goto err;
> > > > > +		goto err_free_v4l2_ctrls;
> > > > >  
> > > > >  	if (debug > 1)
> > > > >  		tvp5150_log_status(sd);
> > > > > +
> > > > >  	return 0;
> > > > >  
> > > > > -err:
> > > > > +err_free_v4l2_ctrls:
> > > > >  	v4l2_ctrl_handler_free(&core->hdl);
> > > > > +err_cleanup_dt:
> > > > > +	if (IS_ENABLED(CONFIG_OF) && np)
> > > > > +		tvp5150_dt_cleanup(core);
> > > > > +
> > > > >  	return res;
> > > > >  }
> > > > >  
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector
  2019-08-15 12:53       ` Laurent Pinchart
@ 2019-08-15 13:26         ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:26 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel

Hi Laurent,

On 19-08-15 15:53, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Tue, Aug 13, 2019 at 11:10:30AM +0200, Marco Felsch wrote:
> > On 19-05-16 21:07, Laurent Pinchart wrote:
> > > On Mon, Apr 15, 2019 at 02:44:12PM +0200, Marco Felsch wrote:
> > > > The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
> > > > data and is able to auto-detect the input signal. The auto-detection
> > > > does not work if the connector does not receive an input signal and the
> > > > tvp5150 might not be configured correctly. This misconfiguration leads
> > > > into wrong decoded video streams if the tvp5150 gets powered on before
> > > > the video signal is present.
> > > > 
> > > > Limit the supported tv norms according to the actual selected connector
> > > > to avoid a misconfiguration.
> > > 
> > > This seems a bit of a hack to me. In particular, on what grounds would
> > > you specify a particular configuration in DT ? Also, this issue affects
> > > non-DT systems, and should be solved globally.
> > 
> > Why is this a hack? Imagine a hardware which supports PAL signals only.
> > Then it should be forbidden for the user space to configure it to SECAM
> > or any NTSC. Since the hardware makes the limitation it should be
> > abstracted on DT level.
> 
> What part of the hardware would be the limiting factor here ? Clearly
> not the TVP5150 as it supports all TV norms, and also not the connector,
> as the connector hardware doesn't care about TV norms.

Of course the TVP5150 nor the connector is limiting but the connector is
the part where we get signal from the outside world. I can't model the
camera here. So the connector seems to be the correct place.

Regards,
  Marco

> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > ---
> > > > [1] https://patchwork.kernel.org/cover/10794703/
> > > > 
> > > > v5:
> > > > - probe() initialize supported tv-norms according the given connectors
> > > >   if they are available.
> > > > - check if media-controller is used. Don't limit the norm if it isn't
> > > >   used.
> > > > - add more logic to be smarter during connector changing so it is
> > > >   intuitiver for the user space.
> > > > 
> > > > v2-v4:
> > > > - nothing since the patch was squashed from series [1] into this
> > > >   series.
> > > > 
> > > >  drivers/media/i2c/tvp5150.c | 69 +++++++++++++++++++++++++++++++++++--
> > > >  1 file changed, 67 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > > index cd54715eb641..c0ee08546643 100644
> > > > --- a/drivers/media/i2c/tvp5150.c
> > > > +++ b/drivers/media/i2c/tvp5150.c
> > > > @@ -32,6 +32,13 @@
> > > >  #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
> > > >  #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
> > > >  #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
> > > > +#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
> > > > +				 V4L2_STD_NTSC_443 | \
> > > > +				 V4L2_STD_PAL      | \
> > > > +				 V4L2_STD_PAL_M    | \
> > > > +				 V4L2_STD_PAL_N    | \
> > > > +				 V4L2_STD_PAL_Nc   | \
> > > > +				 V4L2_STD_SECAM)
> > > >  
> > > >  MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
> > > >  MODULE_AUTHOR("Mauro Carvalho Chehab");
> > > > @@ -66,6 +73,7 @@ struct tvp5150 {
> > > >  	/* media-ctl properties */
> > > >  	struct media_pad pads[TVP5150_NUM_PADS];
> > > >  	struct tvp5150_connector *connectors;
> > > > +	struct tvp5150_connector *cur_connector;
> > > >  	int connectors_num;
> > > >  
> > > >  	struct v4l2_ctrl_handler hdl;
> > > > @@ -785,17 +793,28 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
> > > >  static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
> > > >  {
> > > >  	struct tvp5150 *decoder = to_tvp5150(sd);
> > > > +	struct tvp5150_connector *cur_con = decoder->cur_connector;
> > > > +	v4l2_std_id supported_norms = cur_con ?
> > > > +		cur_con->base.connector.analog.supported_tvnorms : V4L2_STD_ALL;
> > > >  
> > > >  	if (decoder->norm == std)
> > > >  		return 0;
> > > >  
> > > > +	/*
> > > > +	 * check if requested std or group of std's is/are supported by the
> > > > +	 * connector
> > > > +	 */
> > > > +	if ((supported_norms & std) == 0)
> > > > +		return -EINVAL;
> > > > +
> > > >  	/* Change cropping height limits */
> > > >  	if (std & V4L2_STD_525_60)
> > > >  		decoder->rect.height = TVP5150_V_MAX_525_60;
> > > >  	else
> > > >  		decoder->rect.height = TVP5150_V_MAX_OTHERS;
> > > >  
> > > > -	decoder->norm = std;
> > > > +	/* set only the specific supported std in case of group of std's */
> > > > +	decoder->norm = supported_norms & std;
> > > >  
> > > >  	return tvp5150_set_std(sd, std);
> > > >  }
> > > > @@ -1347,6 +1366,8 @@ static int tvp5150_link_setup(struct media_entity *entity,
> > > >  			  TVP5150_BLACK_SCREEN, 0);
> > > >  
> > > >  	if (flags & MEDIA_LNK_FL_ENABLED) {
> > > > +		u32 new_norm;
> > > > +
> > > >  		/*
> > > >  		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> > > >  		 * Both links must be enabled in one-shot regardless which link
> > > > @@ -1358,6 +1379,26 @@ static int tvp5150_link_setup(struct media_entity *entity,
> > > >  			if (err)
> > > >  				return err;
> > > >  		}
> > > > +
> > > > +		/* Update the current connector */
> > > > +		decoder->cur_connector =
> > > > +			container_of(remote, struct tvp5150_connector, pad);
> > > > +
> > > > +		/*
> > > > +		 * Do nothing if the new connector supports the same tv-norms as
> > > > +		 * the old one.
> > > > +		 */
> > > > +		new_norm = decoder->norm &
> > > > +			decoder->cur_connector->base.connector.analog.supported_tvnorms;
> > > > +		if (decoder->norm == new_norm)
> > > > +			return 0;
> > > > +
> > > > +		/*
> > > > +		 * Fallback to the new connector tv-norms if we can't find any
> > > > +		 * common between the current tv-norm and the new one.
> > > > +		 */
> > > > +		tvp5150_s_std(sd, new_norm ? new_norm :
> > > > +			decoder->cur_connector->base.connector.analog.supported_tvnorms);
> > > >  	}
> > > >  
> > > >  	return 0;
> > > > @@ -1576,6 +1617,9 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
> > > >  				TVP5150_COMPOSITE1;
> > > >  
> > > >  			tvp5150_selmux(sd);
> > > > +			decoder->cur_connector = &decoder->connectors[i];
> > > > +			tvp5150_s_std(sd,
> > > > +				decoder->connectors[i].base.connector.analog.supported_tvnorms);
> > > >  		}
> > > >  	}
> > > >  #endif
> > > > @@ -1903,6 +1947,11 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> > > >  				ret = -EINVAL;
> > > >  				goto err;
> > > >  			}
> > > > +			if (!(c.connector.analog.supported_tvnorms &
> > > > +			    TVP5150_STD_MASK))
> > > > +				dev_warn(dev,
> > > > +					"Unsupported tv-norm on connector %s.\n",
> > > > +					c.label);
> > > >  			in++;
> > > >  			break;
> > > >  		case TVP5150_PAD_VID_OUT:
> > > > @@ -2011,7 +2060,23 @@ static int tvp5150_probe(struct i2c_client *c,
> > > >  	if (res < 0)
> > > >  		goto err_cleanup_dt;
> > > >  
> > > > -	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> > > > +	/*
> > > > +	 * Iterate over all available connectors in case they are supported and
> > > > +	 * successfully parsed. Fallback to default autodetect in case they
> > > > +	 * aren't supported.
> > > > +	 */
> > > > +	if (core->connectors) {
> > > > +		struct v4l2_fwnode_connector *con;
> > > > +		int i;
> > > > +
> > > > +		for (i = 0; i < core->connectors_num; i++) {
> > > > +			con = &core->connectors[i].base;
> > > > +			core->norm |= con->connector.analog.supported_tvnorms;
> > > > +		}
> > > > +	} else {
> > > > +		core->norm = V4L2_STD_ALL;
> > > > +	}
> > > > +
> > > >  	core->detected_norm = V4L2_STD_UNKNOWN;
> > > >  	core->input = TVP5150_COMPOSITE1;
> > > >  	core->enable = true;
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support
  2019-08-15 13:22           ` Marco Felsch
@ 2019-08-15 13:26             ` Laurent Pinchart
  0 siblings, 0 replies; 70+ messages in thread
From: Laurent Pinchart @ 2019-08-15 13:26 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Mauro Carvalho Chehab, sakari.ailus, hans.verkuil,
	jacopo+renesas, robh+dt, linux-media, devicetree, kernel

H Marco,

On Thu, Aug 15, 2019 at 03:22:51PM +0200, Marco Felsch wrote:
> On 19-08-15 15:51, Laurent Pinchart wrote:
> > On Tue, Aug 13, 2019 at 10:54:29AM +0200, Marco Felsch wrote:
> >> On 19-05-16 21:03, Laurent Pinchart wrote:
> >>> On Tue, May 14, 2019 at 03:25:45PM -0300, Mauro Carvalho Chehab wrote:
> >>>> Em Mon, 15 Apr 2019 14:44:05 +0200 Marco Felsch escreveu:
> >>>> 
> >>>>> This patch adds the of_graph support to describe the tvp connections.
> >>>>> Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
> >>>>> of discussion [1],[2] the device-tree maps these ports 1:1. The svideo
> >>>>> connector must be conneted to port@0/endpoint@1, look at the Documentation
> >>> 
> >>> According to [2], it must be connected to port port@0 and port@1, not
> >>> just port@0.
> >> 
> >> You're right. I missed that.. I will change that for the v7.
> >> 
> >>>>> for more information. Since the TVP5150 is a converter the device-tree
> >>>>> must contain at least 1-input and 1-output port. The mc-connectors and
> >>>>> mc-links are only created if the device-tree contains the corresponding
> >>>>> connector nodes. If more than one connector is available the
> >>>>> media_entity_operations.link_setup() callback ensures that only one
> >>>>> connector is active.
> >>>>> 
> >>>>> [1] https://www.spinics.net/lists/linux-media/msg138545.html
> >>>>> [2] https://www.spinics.net/lists/linux-media/msg138546.html
> >>>>> 
> >>>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> >>>>> ---
> >>>>> Changelog:
> >>>>> 
> >>>>> [1] https://patchwork.kernel.org/cover/10794703/
> >>>>> [2] https://patchwork.kernel.org/cover/10786553/
> >>>>> 
> >>>>> v6:
> >>>>> - fix misspelled comments
> >>>>> - use 'unsigned int' where it's possible
> >>>>> - cleanup ifdef part-2:
> >>>>>   - tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
> >>>>>     CONFIG_MEDIA_CONTROLLER ifdef and stubs to improve readability
> >>>>> - tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
> >>>>>   internal function do this.
> >>>>> - tvp5150_add_of_connectors: call within probe() to make it cleaner
> >>>>> - tvp5150_parse_dt: move local loop vars within the loop.
> >>>>> 
> >>>>> v5:
> >>>>> - Fixing build deps:
> >>>>>   - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
> >>>>>   - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
> >>>>>     includes. This leads into to complex deps for futher development.
> >>>>>   - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
> >>>>>   - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
> >>>>>   - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled
> >>>>> 
> >>>>> - Simplify link_setup routine:
> >>>>>   - use generic connector parsing since both series [1,2] are squashed into
> >>>>>     one
> >>>>>   - struct tvp5150: drop pads_state and modify_second_link property
> >>>>>     due to link_setup() rework.
> >>>>>   - tvp5150_link_setup: add more comments
> >>>>>   - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
> >>>>>     link directly within the driver instead of a recursive media-framework
> >>>>>     call (__media_entity_setup_link). This improves the readability and
> >>>>>     shrinks the driver code.
> >>>>>   - tvp5150_link_setup: disable all active links in case user switches
> >>>>>     connectors without disable it first.
> >>>>>   - tvp5150_registered: simplify default link enable path due to link_setup()
> >>>>>     rework.
> >>>>> 
> >>>>> - General cleanups
> >>>>>   - tvp5150_parse_dt: drop unecessary test
> >>>>>   - tvp5150_parse_dt: add err message due to misconfiguration
> >>>>>   - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
> >>>>>   - s/dev_dbg/dev_dbg_lvl
> >>>>> 
> >>>>> v4:
> >>>>>  - rebase on top of media_tree/master, fix merge conflict due to commit
> >>>>>    60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
> >>>>>    to zero")
> >>>>> 
> >>>>> v3:
> >>>>> - probe(): s/err/err_free_v4l2_ctrls
> >>>>> - drop MC dependency for tvp5150_pads
> >>>>> 
> >>>>> v2:
> >>>>> - adapt commit message
> >>>>> - unify ifdef switches
> >>>>> - rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
> >>>>> - mc: use 2-input and 1-output pad
> >>>>> - mc: link svideo connector to both input pads
> >>>>> - mc: enable/disable svideo links in one go
> >>>>> - mc: change link_setup() behaviour, switch the input src don't require a
> >>>>>       explicite disable before.
> >>>>> - mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
> >>>>> - mc: enable link to the first available connector and set the
> >>>>>       corresponding tvp5150 input src per default during registered()
> >>>>> - mc/of: factor out oftree connector allocation
> >>>>> - of: drop svideo dt port
> >>>>> - of: move svideo connector to port@0/endpoint@1
> >>>>> - of: require at least 1-in and 1-out endpoint
> >>>>> 
> >>>>>  drivers/media/i2c/tvp5150.c | 409 ++++++++++++++++++++++++++++++++----
> >>>>>  1 file changed, 370 insertions(+), 39 deletions(-)
> >>>>> 
> >>>>> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> >>>>> index 89da921c8886..4e3228b2ccbc 100644
> >>>>> --- a/drivers/media/i2c/tvp5150.c
> >>>>> +++ b/drivers/media/i2c/tvp5150.c
> >>>>> @@ -44,16 +44,29 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
> >>>>>  #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
> >>>>>  
> >>>>>  enum tvp5150_pads {
> >>>>> -	TVP5150_PAD_IF_INPUT,
> >>>>> +	TVP5150_PAD_AIP1A = TVP5150_COMPOSITE0,
> >>>>> +	TVP5150_PAD_AIP1B,
> >>>>>  	TVP5150_PAD_VID_OUT,
> >>>>>  	TVP5150_NUM_PADS
> >>>>>  };
> >>>>>  
> >>>>> +struct tvp5150_connector {
> >>>>> +	struct v4l2_fwnode_connector base;
> >>>>> +	struct media_entity ent;
> >>>>> +	struct media_pad pad;
> >>>>> +};
> >>>>> +
> >>>>>  struct tvp5150 {
> >>>>>  	struct v4l2_subdev sd;
> >>>>> -#ifdef CONFIG_MEDIA_CONTROLLER
> >>>>> +	/* additional endpoint for the svideo connector */
> >>> 
> >>> Could you please capitalize the first word of all comments to match the
> >>> driver style ?
> >> 
> >> Okay, I will check it for my v7.
> >> 
> >>>>> +	struct device_node *endpoints[TVP5150_NUM_PADS + 1];
> >>> 
> >>> As the endpoints are only used at probe time, I would declare this as a
> >>> local variable in the probe function and pass it to both
> >>> tvp5150_add_of_connectors() and tvp5150_parse_dt(). If you order the
> >>> calls correctly it should simplify the probe error handling.
> >> 
> >> Yes that could be also a solution. I took Jacopo's comments and
> >> refactored the code so the endpoints no longer needed in my v7.
> >> 
> >>>>> +	unsigned int endpoints_num;
> >>>>> +
> >>>>> +	/* media-ctl properties */
> >>> 
> >>> media-ctl makes me think about the userspace application, maybe "Media
> >>> controller properties" ?
> >> 
> >> I've dopped that comment becuase it is to obvious..
> >> 
> >>>>>  	struct media_pad pads[TVP5150_NUM_PADS];
> >>>>> -#endif
> >>>>> +	struct tvp5150_connector *connectors;
> >>>>> +	int connectors_num;
> >>> 
> >>> unsigned int ?
> >> 
> >> Of course.
> >> 
> >>>>> +
> >>>>>  	struct v4l2_ctrl_handler hdl;
> >>>>>  	struct v4l2_rect rect;
> >>>>>  	struct regmap *regmap;
> >>>>> @@ -1167,6 +1180,131 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> >>>>>  	return 0;
> >>>>>  }
> >>>>>  
> >>>>> +/****************************************************************************
> >>>>> + *			Media entity ops
> >>>>> + ****************************************************************************/
> >>>>> +#if defined(CONFIG_MEDIA_CONTROLLER)
> >>> 
> >>> Should we depend on CONFIG_MEDIA_CONTROLLER instead, especially since
> >>> you remove the similar conditional in the struct tvp5150 definition and
> >>> in the probe function ?
> >> 
> >> I don't know if we can add the dependency without worries because the
> >> tvp5150 is also used by the usb/em28xx devices which can be build
> >> without CONFIG_MEDIA_CONTROLLER support. During .probe() a stub function
> >> will be called if CONFIG_MEDIA_CONTROLLER isn't enabled.
> >> 
> >>>>> +static int tvp5150_set_link(struct media_pad *connector_pad,
> >>>>> +			    struct media_pad *tvp5150_pad, u32 flags)
> >>>>> +{
> >>>>> +	struct media_link *link;
> >>>>> +
> >>>>> +	link = media_entity_find_link(connector_pad, tvp5150_pad);
> >>>>> +	if (!link)
> >>>>> +		return -EINVAL;
> >>>>> +
> >>>>> +	link->flags = flags;
> >>>>> +	link->reverse->flags = link->flags;
> >>>>> +
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
> >>>>> +{
> >>>>> +	struct media_pad *connector_pad;
> >>>>> +	unsigned int i;
> >>>>> +	int err;
> >>>>> +
> >>>>> +	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> >>>>> +		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
> >>>>> +		if (!connector_pad)
> >>>>> +			continue;
> >>>>> +
> >>>>> +		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
> >>>>> +		if (err)
> >>>>> +			return err;
> >>>>> +	}
> >>>>> +
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> >>>>> +			     u32 config);
> >>>>> +
> >>>>> +static int tvp5150_link_setup(struct media_entity *entity,
> >>>>> +			      const struct media_pad *tvp5150_pad,
> >>>>> +			      const struct media_pad *remote, u32 flags)
> >>>>> +{
> >>>>> +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> >>>>> +	struct tvp5150 *decoder = to_tvp5150(sd);
> >>>>> +	struct media_pad *other_tvp5150_pad =
> >>>>> +		&decoder->pads[tvp5150_pad->index ^ 1];
> >>>>> +	bool is_svideo = false;
> >>>>> +	unsigned int i;
> >>>>> +	int err;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * The TVP5150 state is determined by the enabled sink pad link(s).
> >>>>> +	 * Enabling or disabling the source pad link has no effect.
> >>>>> +	 */
> >>>>> +	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	/* Check if the svideo connector should be enabled */
> >>>>> +	for (i = 0; i < decoder->connectors_num; i++) {
> >>>>> +		if (remote->entity == &decoder->connectors[i].ent) {
> >>>> 
> >>>>> +			is_svideo =
> >>>>> +			   decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> >>>> 
> >>>> Nitpick:
> >>>> 
> >>>> I would actually prefer to keep this on a single line. Ok, it will violate
> >>>> the 80-columns, but it would be better than the above (IMHO).
> >>>> 
> >>>>> +			break;
> >>>>> +		}
> >>>>> +	}
> >>>>> +
> >>>>> +	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
> >>>>> +		    remote->entity->name, remote->index,
> >>>>> +		    tvp5150_pad->entity->name, tvp5150_pad->index,
> >>>>> +		    flags & MEDIA_LNK_FL_ENABLED);
> >>>>> +	if (is_svideo)
> >>>>> +		dev_dbg_lvl(sd->dev, 1, debug,
> >>>>> +			    "link setup '%s':%d->'%s':%d[%d]",
> >>>>> +			    remote->entity->name, remote->index,
> >>>>> +			    other_tvp5150_pad->entity->name,
> >>>>> +			    other_tvp5150_pad->index,
> >>>>> +			    flags & MEDIA_LNK_FL_ENABLED);
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * The TVP5150 has an internal mux which allows the following setup:
> >>>>> +	 *
> >>>>> +	 * comp-connector1  --\
> >>>>> +	 *		       |---> AIP1A
> >>>>> +	 *		      /
> >>>>> +	 * svideo-connector -|
> >>>>> +	 *		      \
> >>>>> +	 *		       |---> AIP1B
> >>>>> +	 * comp-connector2  --/
> >>>>> +	 *
> >>>>> +	 * We can't rely on user space that the current connector gets disabled
> >>>>> +	 * first before enabling the new connector. Disable all active
> >>>>> +	 * connector links to be on the safe side.
> >>>>> +	 */
> >>>>> +	err = tvp5150_disable_all_input_links(decoder);
> >>>>> +	if (err)
> >>>>> +		return err;
> >>>>> +
> >>>>> +	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
> >>>>> +			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
> >>>>> +			  TVP5150_BLACK_SCREEN, 0);
> >>>>> +
> >>>>> +	if (flags & MEDIA_LNK_FL_ENABLED) {
> >>>>> +		/*
> >>>>> +		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
> >>>>> +		 * Both links must be enabled in one-shot regardless which link
> >>>>> +		 * the user requests.
> >>>>> +		 */
> >>> 
> >>> This is a very grey area, I don't think the MC API explicitly allows
> >>> doing this. As changing links during streaming is disallowed, wouldn't
> >>> it be easier to handle the routing configuration at stream start ? You
> >>> wouldn't have to deal with this issue then, you could just return an
> >>> error if only one link is enabled. Furthermore, it would allow
> >>> supporting a configuration where a composite signal is connected to the
> >>> Y pin of the mini-DIN connector.
> >> 
> >> We discussed this a few series earlier because my first solution what
> >> like this you describe above. I changed that because Mauro had some
> >> concerns about the usability. Now this behaviour is easier to use but
> >> as you pointed out above, such 'special' handling isn't doable anymore.
> >> I would keep this solution since I want to get this series merged ;)
> >> If someone wants such a 'special' configuration he can implement it
> >> later.
> > 
> > But that would break the ABI. I'm sorry, but we need to find an
> > agreement on this issue to merge the series, it's not a detail that can
> > be addressed later. Could you start a discussion with Mauro to see if he
> > can be convinced, or if he has a better proposal ?
> 
> You're right this would break the ABI or needs some special later on
> handling introducing new dt-bindings...
> 
> Unfortunately this is the result of Mauro's proposal and I have no good
> arguments against it.

Could you propose a time for a discussion on #v4l ? I think it would be
faster that way.

> >>>>> +		if (is_svideo) {
> >>>>> +			err = tvp5150_set_link((struct media_pad *) remote,
> >>>>> +					       other_tvp5150_pad, flags);
> >>>>> +			if (err)
> >>>>> +				return err;
> >>>>> +		}
> >>>>> +	}
> >>>>> +
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static const struct media_entity_operations tvp5150_sd_media_ops = {
> >>>>> +	.link_setup = tvp5150_link_setup,
> >>>>> +};
> >>>>> +#endif
> >>>>>  /****************************************************************************
> >>>>>  			I2C Command
> >>>>>   ****************************************************************************/
> >>>>> @@ -1314,6 +1452,65 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> >>>>>  	return 0;
> >>>>>  }
> >>>>>  
> >>>>> +static int tvp5150_registered(struct v4l2_subdev *sd)
> >>>>> +{
> >>>>> +#if defined(CONFIG_MEDIA_CONTROLLER)
> >>>>> +	struct tvp5150 *decoder = to_tvp5150(sd);
> >>>>> +	unsigned int i;
> >>>>> +	int ret;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * Setup connector pads and links. Enable the link to the first
> >>>>> +	 * available connector per default.
> >>>>> +	 */
> >>>>> +	for (i = 0; i < decoder->connectors_num; i++) {
> >>>>> +		struct media_entity *con = &decoder->connectors[i].ent;
> >>>>> +		struct media_pad *pad = &decoder->connectors[i].pad;
> >>>>> +		unsigned int port = decoder->connectors[i].base.remote_port;
> >>>>> +		bool is_svideo =
> >>>>> +			decoder->connectors[i].base.type == V4L2_CON_SVIDEO;
> >>>>> +		int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
> >>> 
> >>> The flags passed to media_create_pad_link() are unsigned.
> >> 
> >> You are right, changed that.
> >> 
> >>>>> +
> >>>>> +		pad->flags = MEDIA_PAD_FL_SOURCE;
> >>>>> +		ret = media_entity_pads_init(con, 1, pad);
> >>>>> +		if (ret < 0)
> >>>>> +			return ret;
> >>>>> +
> >>>>> +		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
> >>>>> +		if (ret < 0)
> >>>>> +			return ret;
> >>>>> +
> >>>>> +		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
> >>>>> +		if (ret < 0) {
> >>>>> +			media_device_unregister_entity(con);
> >>>>> +			return ret;
> >>>>> +		}
> >>> 
> >>> Will the other registered media entities be unregistered correctly ?
> >> 
> >> Good point. I add a seperate error handling to ensure all registered
> >> entities gets unregistered.
> >> 
> >>>>> +
> >>>>> +		if (is_svideo) {
> >>>>> +			/* svideo links to both aip1a and aip1b */
> >>>>> +			ret = media_create_pad_link(con, 0, &sd->entity,
> >>>>> +						    port + 1, flags);
> >>> 
> >>> Does the TVP5150 support both connecting Y to AIP1A and C to AIP1B, and
> >>> Y to AIP1B and C to AIP1A ? If so the port + 1 won't always work.
> >> 
> >> No, if I understood the datasheet right Y is always connected to AIP1A
> >> and C to AIP1B. Since I improved the struct v4l2_fwnode_connector to
> >> hold more connector-port information the 'port+1' logic isn't used
> >> anymore.
> >> 
> >>>>> +			if (ret < 0) {
> >>>>> +				media_device_unregister_entity(con);
> >>>>> +				return ret;
> >>>>> +			}
> >>>>> +		}
> >>>>> +
> >>>>> +		/* enable default input */
> >>>>> +		if (flags == MEDIA_LNK_FL_ENABLED) {
> >>>>> +			decoder->input =
> >>>>> +				is_svideo ? TVP5150_SVIDEO :
> >>>>> +				port == 0 ? TVP5150_COMPOSITE0 :
> >>>>> +				TVP5150_COMPOSITE1;
> >>>>> +
> >>>>> +			tvp5150_selmux(sd);
> >>>>> +		}
> >>> 
> >>> You could move this after the loop and operation on
> >>> decoder->connectors[0]. Hopefully you could then use if's instead of
> >>> nested ? : operators, as the above isn't very readable.
> >> 
> >> That's also doable. Mauro which solution do you prefer?
> >> 
> >>>>> +	}
> >>>>> +#endif
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>> +
> >>> 
> >>> One blank line is enough.
> >> 
> >> Fixed.
> >> 
> >>>>>  /* ----------------------------------------------------------------------- */
> >>>>>  
> >>>>>  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
> >>>>> @@ -1367,6 +1564,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
> >>>>>  	.pad = &tvp5150_pad_ops,
> >>>>>  };
> >>>>>  
> >>>>> +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> >>>>> +	.registered = tvp5150_registered,
> >>>>> +};
> >>>>> +
> >>>>>  /****************************************************************************
> >>>>>  			I2C Client & Driver
> >>>>>   ****************************************************************************/
> >>>>> @@ -1515,38 +1716,168 @@ static int tvp5150_init(struct i2c_client *c)
> >>>>>  	return 0;
> >>>>>  }
> >>>>>  
> >>>>> -static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> >>>>> +#if defined(CONFIG_MEDIA_CONTROLLER)
> >>>>> +static int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> >>>>>  {
> >>>>> -	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
> >>>>> -	struct device_node *ep;
> >>>>> -	unsigned int flags;
> >>>>> -	int ret = 0;
> >>>>> +	struct device *dev = decoder->sd.dev;
> >>> 
> >>> You use dev in a singla location, I think you could use decoder->sd.dev
> >>> directly.
> >> 
> >> This function is no longer used but you're right.
> >> 
> >>> 
> >>>>> +	struct tvp5150_connector *connectors;
> >>>>> +	unsigned int connectors_num = decoder->connectors_num;
> >>>>> +	int i, ret;
> >>> 
> >>> i is never negative, you can make it an unsiged int.
> >>> 
> >>>>>  
> >>>>> -	ep = of_graph_get_next_endpoint(np, NULL);
> >>>>> -	if (!ep)
> >>>>> -		return -EINVAL;
> >>>>> +	/*
> >>>>> +	 * Only add of_connectors if device really is a OF device since
> >>>>> +	 * the driver is used by usb devices e.g. em28xx and embedded
> >>>>> +	 * devices.
> >>>>> +	 */
> >>>>> +	if (!decoder->connectors_num)
> >>> 
> >>> Maybe if (!connectors_num) ?
> >>> 
> >>>>> +		return 0;
> >>>>>  
> >>>>> -	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
> >>>>> -	if (ret)
> >>>>> -		goto err;
> >>>>> +	/* Allocate and initialize all available input connectors */
> >>>>> +	connectors = devm_kcalloc(dev, connectors_num, sizeof(*connectors),
> >>>>> +				  GFP_KERNEL);
> >>>>> +	if (!connectors)
> >>>>> +		return -ENOMEM;
> >>>>> +
> >>>>> +	for (i = 0; i < connectors_num; i++) {
> >>>>> +		struct v4l2_fwnode_connector *c = &connectors[i].base;
> >>>>> +
> >>>>> +		ret = v4l2_fwnode_parse_connector(
> >>>>> +				   of_fwnode_handle(decoder->endpoints[i]), c);
> >>> 
> >>> I think you should handle errors here.
> >>> 
> >>>>> +
> >>>>> +		connectors[i].ent.flags = MEDIA_ENT_FL_CONNECTOR;
> >>>>> +		connectors[i].ent.function = c->type == V4L2_CON_SVIDEO ?
> >>>>> +			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
> >>>>> +		connectors[i].ent.name = c->label;
> >>> 
> >>> I don't think using the label as the entity name is a good idea, as we
> >>> require entity names to be unique, and labels offer no such guarantee.
> >> 
> >> Good point. What about <connector dt-name>:<label>? The devicetree name
> >> is unique.
> > 
> > That should work. Is there a risk it wouldn't fit in the entity name
> > field though ?
> > 
> >>>>> +	}
> >>>>> +
> >>>>> +	decoder->connectors = connectors;
> >>>>> +
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static int tvp5150_mc_init(struct tvp5150 *decoder)
> >>>>> +{
> >>>>> +	struct v4l2_subdev *sd = &decoder->sd;
> >>>>> +	unsigned int i;
> >>>>> +
> >>>>> +	sd->entity.ops = &tvp5150_sd_media_ops;
> >>>>> +	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> >>>>> +
> >>>>> +	/* Initialize all TVP5150 pads */
> >>>>> +	for (i = 0; i < TVP5150_NUM_PADS; i++) {
> >>>>> +		if (i < TVP5150_NUM_PADS - 1) {
> >>>>> +			decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> >>>>> +			decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> >>>>> +		} else {
> >>>>> +			decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> >>>>> +			decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> >>>>> +		}
> >>>>> +	}
> >>> 
> >>> You can simplify this to
> >>> 
> >>> 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
> >>> 		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
> >>> 		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
> >>> 	}
> >>> 
> >>> 	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
> >>> 	decoder->pads[i].sig_type = PAD_SIGNAL_DV;
> >> 
> >> Yes, already done.
> >> 
> >>>>> +
> >>>>> +	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
> >>>>> +				      decoder->pads);
> >>>>> +}
> >>>>> +
> >>>>> +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
> >>>>> +
> >>>>> +static inline int tvp5150_add_of_connectors(struct tvp5150 *decoder)
> >>>>> +{
> >>>>> +	return 0;
> >>>>> +}
> >>>>>  
> >>>>> -	flags = bus_cfg.bus.parallel.flags;
> >>>>> +static inline int tvp5150_mc_init(struct tvp5150 *decoder)
> >>>>> +{
> >>>>> +	return 0;
> >>>>> +}
> >>>>> +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
> >>>>>  
> >>>>> -	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> >>>>> -	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> >>>>> -	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> >>>>> -	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> >>>>> +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
> >>>>> +{
> >>>>> +	struct device *dev = decoder->sd.dev;
> >>>>> +	struct device_node *ep_np;
> >>>>> +	unsigned int i = 0, in = 0;
> >>> 
> >>> Let's rename in to num_inputs or num_connectors.
> >> 
> >> I refactored the code, so in is no longer used.
> >> 
> >>>>> +	int ret;
> >>>>> +	bool found = false;
> >>>>> +
> >>>>> +	/* at least 1 output and 1 input */
> >>>>> +	decoder->endpoints_num = of_graph_get_endpoint_count(np);
> >>>>> +	if (decoder->endpoints_num < 2 || decoder->endpoints_num > 4) {
> >>>>> +		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
> >>>>>  		ret = -EINVAL;
> >>>>>  		goto err;
> >>>>>  	}
> >>>>>  
> >>>>> -	decoder->mbus_type = bus_cfg.bus_type;
> >>>>> +	for_each_endpoint_of_node(np, ep_np) {
> >>>>> +		struct v4l2_fwnode_endpoint bus_cfg = {
> >>>>> +			.bus_type = V4L2_MBUS_UNKNOWN
> >>>>> +		};
> >>>>> +		struct v4l2_fwnode_connector c;
> >>>>> +		struct of_endpoint ep;
> >>>>> +		unsigned int flags;
> >>>>> +
> >>>>> +		of_graph_parse_endpoint(ep_np, &ep);
> >>>>> +		switch (ep.port) {
> >>>>> +		case TVP5150_PAD_AIP1A:
> >>>>> +			/* fall through */
> >>> 
> >>> I don't think you need this comment.
> >>> 
> >>>>> +		case TVP5150_PAD_AIP1B:
> >>>>> +			ret = v4l2_fwnode_parse_connector(
> >>>>> +						   of_fwnode_handle(ep_np), &c);
> >>> 
> >>> You use of_fwnode_handle(ep_np) twice, you could move it outside of the
> >>> switch () to keep lines shorter.
> >>> 
> >>>>> +			if (c.type != V4L2_CON_COMPOSITE &&
> >>>>> +			    c.type != V4L2_CON_SVIDEO) {
> >>>>> +				dev_err(dev,
> >>>>> +					"Invalid endpoint %d on port %d\n",
> >>> 
> >>> The correct format specifier for unsigned int is %u.
> >>> 
> >>> Should the error message be more explicit ? "Invalid connector type for
> >>> port@%u/endpoint@%u" ?
> >>> 
> >>> 
> >>>>> +					c.remote_id, c.remote_port);
> >>>>> +				ret = -EINVAL;
> >>>>> +				goto err;
> >>> 
> >>> If you break out of the loop you need an of_node_put(ep_np).
> >>> Alternatively, you could store ep_np in the endpoints array right before
> >>> of_graph_parse_endpoint() and call of_node_put() right after
> >>> of_graph_parse_endpoint().
> >>> 
> >>>>> +			}
> >>>>> +			in++;
> >>>>> +			break;
> >>>>> +		case TVP5150_PAD_VID_OUT:
> >>>>> +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np),
> >>>>> +							 &bus_cfg);
> >>>>> +			if (ret)
> >>>>> +				goto err;
> >>>>> +
> >>>>> +			flags = bus_cfg.bus.parallel.flags;
> >>>>> +
> >>>>> +			if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
> >>>>> +			    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
> >>>>> +			      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
> >>>>> +			      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
> >>>>> +				ret = -EINVAL;
> >>>>> +				goto err;
> >>>>> +			}
> >>>>> +
> >>>>> +			decoder->mbus_type = bus_cfg.bus_type;
> >>>>> +			break;
> >>>>> +		default:
> >>>>> +			dev_err(dev, "Invalid port %d for endpoint %pOF\n",
> >>> 
> >>> %u here too.
> >>> 
> >>>>> +				ep.port, ep.local_node);
> >>>>> +			ret = -EINVAL;
> >>>>> +			goto err;
> >>>>> +		}
> >>>>> +
> >>>>> +		of_node_get(ep_np);
> >>>>> +		decoder->endpoints[i] = ep_np;
> >>>>> +		i++;
> >>>>> +
> >>>>> +		found = true;
> >>>>> +	}
> >>>>>  
> >>>>> +	decoder->connectors_num = in;
> >>>>> +	return found ? 0 : -ENODEV;
> >>>>>  err:
> >>>>> -	of_node_put(ep);
> >>>>>  	return ret;
> >>> 
> >>> You can remove the err label and return ret directly.
> >> 
> >> I took your comments into account for the refactored function, thanks.
> >> 
> >>>>>  }
> >>>>>  
> >>>>> +static void tvp5150_dt_cleanup(struct tvp5150 *decoder)
> >>>>> +{
> >>>>> +	unsigned int i;
> >>>>> +
> >>>>> +	for (i = 0; i < TVP5150_NUM_PADS; i++)
> >>>>> +		of_node_put(decoder->endpoints[i]);
> >>>>> +}
> >>>>> +
> >>>>>  static const char * const tvp5150_test_patterns[2] = {
> >>>>>  	"Disabled",
> >>>>>  	"Black screen"
> >>>>> @@ -1585,7 +1916,7 @@ static int tvp5150_probe(struct i2c_client *c,
> >>>>>  		res = tvp5150_parse_dt(core, np);
> >>>>>  		if (res) {
> >>>>>  			dev_err(sd->dev, "DT parsing error: %d\n", res);
> >>>>> -			return res;
> >>>>> +			goto err_cleanup_dt;
> >>>>>  		}
> >>>>>  	} else {
> >>>>>  		/* Default to BT.656 embedded sync */
> >>>>> @@ -1593,25 +1924,20 @@ static int tvp5150_probe(struct i2c_client *c,
> >>>>>  	}
> >>>>>  
> >>>>>  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
> >>>>> +	sd->internal_ops = &tvp5150_internal_ops;
> >>>>>  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> >>>>>  
> >>>>> -#if defined(CONFIG_MEDIA_CONTROLLER)
> >>>>> -	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
> >>>>> -	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
> >>>>> -	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
> >>>>> -	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
> >>>>> -
> >>>>> -	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
> >>>>> -
> >>>>> -	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
> >>>>> -	if (res < 0)
> >>>>> -		return res;
> >>>>> +	res = tvp5150_mc_init(core);
> >>>>> +	if (res)
> >>>>> +		goto err_cleanup_dt;
> >>>>>  
> >>>>> -#endif
> >>>>> +	res = tvp5150_add_of_connectors(core);
> >>>>> +	if (res)
> >>>>> +		goto err_cleanup_dt;
> >>>>>  
> >>>>>  	res = tvp5150_detect_version(core);
> >>>>>  	if (res < 0)
> >>>>> -		return res;
> >>>>> +		goto err_cleanup_dt;
> >>>>>  
> >>>>>  	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
> >>>>>  	core->detected_norm = V4L2_STD_UNKNOWN;
> >>>>> @@ -1637,7 +1963,7 @@ static int tvp5150_probe(struct i2c_client *c,
> >>>>>  	sd->ctrl_handler = &core->hdl;
> >>>>>  	if (core->hdl.error) {
> >>>>>  		res = core->hdl.error;
> >>>>> -		goto err;
> >>>>> +		goto err_free_v4l2_ctrls;
> >>>>>  	}
> >>>>>  
> >>>>>  	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
> >>>>> @@ -1649,19 +1975,24 @@ static int tvp5150_probe(struct i2c_client *c,
> >>>>>  						tvp5150_isr, IRQF_TRIGGER_HIGH |
> >>>>>  						IRQF_ONESHOT, "tvp5150", core);
> >>>>>  		if (res)
> >>>>> -			goto err;
> >>>>> +			goto err_free_v4l2_ctrls;
> >>>>>  	}
> >>>>>  
> >>>>>  	res = v4l2_async_register_subdev(sd);
> >>>>>  	if (res < 0)
> >>>>> -		goto err;
> >>>>> +		goto err_free_v4l2_ctrls;
> >>>>>  
> >>>>>  	if (debug > 1)
> >>>>>  		tvp5150_log_status(sd);
> >>>>> +
> >>>>>  	return 0;
> >>>>>  
> >>>>> -err:
> >>>>> +err_free_v4l2_ctrls:
> >>>>>  	v4l2_ctrl_handler_free(&core->hdl);
> >>>>> +err_cleanup_dt:
> >>>>> +	if (IS_ENABLED(CONFIG_OF) && np)
> >>>>> +		tvp5150_dt_cleanup(core);
> >>>>> +
> >>>>>  	return res;
> >>>>>  }
> >>>>>  

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property
  2019-08-15 13:02           ` Laurent Pinchart
@ 2019-08-15 13:35             ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:35 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Rob Herring

Hi Laurent,

On 19-08-15 16:02, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Thu, Aug 15, 2019 at 02:50:02PM +0200, Marco Felsch wrote:
> > On 19-08-15 15:33, Laurent Pinchart wrote:
> > > On Fri, Aug 09, 2019 at 07:58:09AM +0200, Marco Felsch wrote:
> > >> On 19-05-16 19:27, Laurent Pinchart wrote:
> > >>> On Mon, Apr 15, 2019 at 02:44:01PM +0200, Marco Felsch wrote:
> > >>>> Some connectors no matter if in- or output supports only a limited
> > >>>> range of tv norms. It doesn't matter if the hardware behind that
> > >>>> connector supports more than the listed formats since the users are
> > >>>> restriced by a label e.g. to plug only a camera into this connector
> > >>>> which uses the PAL format.
> > >>>> 
> > >>>> This patch adds the capability to describe such limitation within the
> > >>>> firmware. There are no format restrictions if the property isn't
> > >>>> present, so it's completely backward compatible.
> > >>> 
> > >>> Why is this needed ? It's not really a hardware property, is it ? What's
> > >>> the use case ?
> > >> 
> > >> Cause some hardware only support a limited range of formats to that
> > >> connector. Of course it is a hardware property. For example if a
> > >> customer wants to limit a connector to a specifc norm because the
> > >> hardware behind that connector only supports that format or is
> > >> restricted to that format.
> > > 
> > > Then it should be a DT property of the hardware behind that connector
> > > (or information hardcoded directly into that driver), shouldn't it ?
> > 
> > Why? The connector is the limiting factor and not the decoder/bridge
> > device behind that. Let me explain it a bit more in detail. Our customer
> > sells hardware boxes and cameras. The camera is connected to the box
> > using a custom plug. So it's guaranteed that only their cameras can be
> > connected to. Also the camera they are using supports only PAL. So the
> > PAL signal is the only one which can be received on that connector. The
> > TVP itself supports more than just PAL signals and has multiple inputs.
> > So there can be the use case that a hardware box supports two physical
> > connectors: e.g. connector-PAL, connector-NTSC. The TVP should be
> > limited to PAL signals if the connector-PAL is active or limited to NTSC
> > if the connector-NTSC is active.
> > 
> > Hopefully you see now why we should model it on the connector side and
> > not on the device behind that connector.
> 
> So it essentially means that if someone connects an NTSC camera on the
> PAL input with the same custom connector, the hardware will support it,
> right ? I don't think it's a hardware limitation of the connector in
> that case :-) And I don't think it belongs to DT. Userspace is probably
> where I would handle this type of policy.

What you describe here would be a 'user hack' because our customer sells
only PAL cameras. I think it is a connector limitation because the
connector can be labeld with "PAL only" and is rectangle and there can
be a round "NTSC only" connector. IMHO this is a hardware limiting
factor and no one would expect that a NTSC camera is working on a "PAL
only" labeld connector.

Regards,
  Marco

> > >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > >>>> Reviewed-by: Rob Herring <robh@kernel.org>
> > >>>> ---
> > >>>> [1] https://patchwork.kernel.org/cover/10794703/
> > >>>> 
> > >>>> v6:
> > >>>> - tvnorms.h: use tabs instead of spaces
> > >>>> - tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
> > >>>> - tvnorms.h: drop rarely used TVNORM_ATSC_* norms
> > >>>> 
> > >>>> v2-v4:
> > >>>> - nothing since the patch was squashed from series [1] into this
> > >>>>   series.
> > >>>> 
> > >>>>  .../display/connector/analog-tv-connector.txt |  4 ++
> > >>>>  include/dt-bindings/media/tvnorms.h           | 56 +++++++++++++++++++
> > >>>>  2 files changed, 60 insertions(+)
> > >>>>  create mode 100644 include/dt-bindings/media/tvnorms.h
> > >>>> 
> > >>>> diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > >>>> index 0c0970c210ab..346f8937a0b7 100644
> > >>>> --- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > >>>> +++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
> > >>>> @@ -6,6 +6,9 @@ Required properties:
> > >>>>  
> > >>>>  Optional properties:
> > >>>>  - label: a symbolic name for the connector
> > >>>> +- tvnorms: limit the supported tv norms on a connector to the given ones else
> > >>>> +           all tv norms are allowed. Possible video standards are defined in
> > >>>> +           include/dt-bindings/media/tvnorms.h.
> > >>>>  
> > >>>>  Required nodes:
> > >>>>  - Video port for TV input
> > >>>> @@ -16,6 +19,7 @@ Example
> > >>>>  tv: connector {
> > >>>>  	compatible = "composite-video-connector";
> > >>>>  	label = "tv";
> > >>>> +	tvnorms = <(TVNORM_PAL_M | TVNORM_NTSC_M)>;
> > >>>>  
> > >>>>  	port {
> > >>>>  		tv_connector_in: endpoint {
> > >>>> diff --git a/include/dt-bindings/media/tvnorms.h b/include/dt-bindings/media/tvnorms.h
> > >>>> new file mode 100644
> > >>>> index 000000000000..058ab8414145
> > >>>> --- /dev/null
> > >>>> +++ b/include/dt-bindings/media/tvnorms.h
> > >>>> @@ -0,0 +1,56 @@
> > >>>> +/* SPDX-License-Identifier: GPL-2.0-only or X11 */
> > >>>> +/*
> > >>>> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > >>>> + */
> > >>>> +
> > >>>> +#ifndef _DT_BINDINGS_MEDIA_TVNORMS_H
> > >>>> +#define _DT_BINDINGS_MEDIA_TVNORMS_H
> > >>>> +
> > >>>> +/* one bit for each */
> > >>>> +#define TVNORM_PAL_B		0x00000001
> > >>>> +#define TVNORM_PAL_B1		0x00000002
> > >>>> +#define TVNORM_PAL_G		0x00000004
> > >>>> +#define TVNORM_PAL_H		0x00000008
> > >>>> +#define TVNORM_PAL_I		0x00000010
> > >>>> +#define TVNORM_PAL_D		0x00000020
> > >>>> +#define TVNORM_PAL_D1		0x00000040
> > >>>> +#define TVNORM_PAL_K		0x00000080
> > >>>> +
> > >>>> +#define TVNORM_PAL		(TVNORM_PAL_B  | \
> > >>>> +				 TVNORM_PAL_B1 | \
> > >>>> +				 TVNORM_PAL_G  | \
> > >>>> +				 TVNORM_PAL_H  | \
> > >>>> +				 TVNORM_PAL_I  | \
> > >>>> +				 TVNORM_PAL_D  | \
> > >>>> +				 TVNORM_PAL_D1 | \
> > >>>> +				 TVNORM_PAL_K)
> > >>>> +
> > >>>> +#define TVNORM_PAL_M		0x00000100
> > >>>> +#define TVNORM_PAL_N		0x00000200
> > >>>> +#define TVNORM_PAL_Nc		0x00000400
> > >>>> +#define TVNORM_PAL_60		0x00000800
> > >>>> +
> > >>>> +#define TVNORM_NTSC_M		0x00001000	/* BTSC */
> > >>>> +#define TVNORM_NTSC_M_JP	0x00002000	/* EIA-J */
> > >>>> +#define TVNORM_NTSC_443		0x00004000
> > >>>> +#define TVNORM_NTSC_M_KR	0x00008000	/* FM A2 */
> > >>>> +
> > >>>> +#define TVNORM_SECAM_B		0x00010000
> > >>>> +#define TVNORM_SECAM_D		0x00020000
> > >>>> +#define TVNORM_SECAM_G		0x00040000
> > >>>> +#define TVNORM_SECAM_H		0x00080000
> > >>>> +#define TVNORM_SECAM_K		0x00100000
> > >>>> +#define TVNORM_SECAM_K1		0x00200000
> > >>>> +#define TVNORM_SECAM_L		0x00400000
> > >>>> +#define TVNORM_SECAM_LC		0x00800000
> > >>>> +
> > >>>> +#define TVNORM_SECAM		(TVNORM_SECAM_B  | \
> > >>>> +				 TVNORM_SECAM_D  | \
> > >>>> +				 TVNORM_SECAM_G  | \
> > >>>> +				 TVNORM_SECAM_H  | \
> > >>>> +				 TVNORM_SECAM_K  | \
> > >>>> +				 TVNORM_SECAM_K1 | \
> > >>>> +				 TVNORM_SECAM_L  | \
> > >>>> +				 TVNORM_SECAM_LC)
> > >>>> +
> > >>>> +#endif /* _DT_BINDINGS_MEDIA_TVNORMS_H */
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-08-15 13:10           ` Laurent Pinchart
@ 2019-08-15 13:37             ` Marco Felsch
  0 siblings, 0 replies; 70+ messages in thread
From: Marco Felsch @ 2019-08-15 13:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	linux-media, devicetree, kernel, Jacopo Mondi

Hi Laurent,

On 19-08-15 16:10, Laurent Pinchart wrote:
> Hi Marco,
> 
> On Thu, Aug 15, 2019 at 03:04:37PM +0200, Marco Felsch wrote:
> > On 19-08-15 15:38, Laurent Pinchart wrote:
> > > On Fri, Aug 09, 2019 at 09:55:36AM +0200, Marco Felsch wrote:
> > >> On 19-05-16 19:36, Laurent Pinchart wrote:
> > >>> On Mon, Apr 15, 2019 at 02:44:02PM +0200, Marco Felsch wrote:
> > >>>> Currently every driver needs to parse the connector endpoints by it self.
> > >>> 
> > >>> s/it self/itself/
> > >>> 
> > >>>> This is the initial work to make this generic. The generic connector has
> > >>>> some common fields and some connector specific parts. The generic one
> > >>>> includes:
> > >>>>   - type
> > >>>>   - label
> > >>>>   - remote_port (the port where the connector is connected to)
> > >>>>   - remote_id   (the endpoint where the connector is connected to)
> > >>> 
> > >>> This assumes a single connection between a connector and a remote port,
> > >>> and a single port on the connector side. Is this guaranteed ? For the
> > >>> mini-DIN-4 connectors (often used for S-Video) for instance, I recall
> > >>> from the extensive discussions we had in the past that they should be
> > >>> modeled with two pins, one for the Y component and one for C components.
> > >>> The rationale for this is to support systems where such a connector
> > >>> could be used to carry S-Video, but also two composite video signals
> > >>> (usually through an external adapter from 2 RCA female connectors to one
> > >>> S-Video male connector) that would be routed to two separate video
> > >>> decoders (or two different inputs of the same video decoder). Other
> > >>> topologies may be possible too.
> > >> 
> > >> I got your concerns and I also remember the tvp5150 port bindings
> > >> myself in the past. Do you know how often such a setup you described
> > >> above happens these days? I would rather add more documentation to the
> > >> bindings [1] and add a check to v4l2_fwnode_parse_connector() to
> > >> guarantee that one port has only one endpoint. Because I don't think
> > >> that analog connectors has a bright future these days.
> > >> 
> > >> [1] Documentation/devicetree/bindings/display/connector/ \
> > >>     analog-tv-connector.txt
> > > 
> > > I have seen it on older hardware, I don't know about more recent
> > > systems. For the S-Video case at least, you need to support two DT
> > > ports, even if you don't support connecting them to two different
> > > devices yet.
> > 
> > Can you take a look on the v7 I send a few minutes ago? I changed the
> > layout ;)
> 
> I'll try to get to that ASAP, but I have a Rockchip driver to review
> first :-)

No stress just wanted to link them here :)

> > > In any case, I'm fine if those topologies are not supported yet, but it
> > > should be possible to support them in a backward-compatible way. In
> > > particular, in this case, we should make sure the DT bindings will allow
> > > such topologies, and the DT parsing API should make it possible to
> > > support them without fugure changes to drivers that use the API from
> > > this patch for "simple" topologies.
> > 
> > You're right. I adapted the struct to be more extendible.
> > 
> > >>>> The specific fields are within a union, since only one of them can be
> > >>>> available at the time. Since this is the initial support the patch adds
> > >>>> only the analog-connector specific ones.
> > >>>> 
> > >>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > >>>> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> > >>>> ---
> > >>>> [1] https://patchwork.kernel.org/cover/10794703/
> > >>>> 
> > >>>> v6:
> > >>>> - fix some spelling and style issues
> > >>>> - rm unnecessary comments
> > >>>> - drop vga and dvi connector
> > >>>> 
> > >>>> v2-v4:
> > >>>> - nothing since the patch was squashed from series [1] into this
> > >>>>   series.
> > >>>> 
> > >>>>  include/media/v4l2-connector.h | 30 ++++++++++++++++++++++++++++++
> > >>>>  include/media/v4l2-fwnode.h    | 33 +++++++++++++++++++++++++++++++++
> > >>>>  2 files changed, 63 insertions(+)
> > >>>>  create mode 100644 include/media/v4l2-connector.h
> > >>>> 
> > >>>> diff --git a/include/media/v4l2-connector.h b/include/media/v4l2-connector.h
> > >>>> new file mode 100644
> > >>>> index 000000000000..3a951c54f50e
> > >>>> --- /dev/null
> > >>>> +++ b/include/media/v4l2-connector.h
> > >>>> @@ -0,0 +1,30 @@
> > >>>> +/* SPDX-License-Identifier: GPL-2.0-only */
> > >>>> +/*
> > >>>> + * v4l2-connector.h
> > >>>> + *
> > >>>> + * V4L2 connector types.
> > >>>> + *
> > >>>> + * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
> > >>>> + */
> > >>>> +
> > >>>> +#ifndef V4L2_CONNECTOR_H
> > >>>> +#define V4L2_CONNECTOR_H
> > >>>> +
> > >>>> +#define V4L2_CONNECTOR_MAX_LABEL 41
> > >>> 
> > >>> Hans pointed out this was a weird number. Should you turn the label
> > >>> field into a pointer to make this more generic (with a
> > >>> v4l2_fwnode_connector_cleanup() function then) ?
> > >> 
> > >> Yes, that would be the better approach. I will change that.
> > >> 
> > >>>> +
> > >>>> +/**
> > >>>> + * enum v4l2_connector_type - connector type
> > >>>> + * @V4L2_CON_UNKNOWN:   unknown connector type, no V4L2 connetor configuration
> > >>>> + * @V4L2_CON_COMPOSITE: analog composite connector
> > >>>> + * @V4L2_CON_SVIDEO:    analog svideo connector
> > >>>> + * @V4L2_CON_HDMI:      digital hdmi connector
> > >>>> + */
> > >>>> +enum v4l2_connector_type {
> > >>>> +	V4L2_CON_UNKNOWN,
> > >>>> +	V4L2_CON_COMPOSITE,
> > >>>> +	V4L2_CON_SVIDEO,
> > >>>> +	V4L2_CON_HDMI,
> > >>>> +};
> > >>>> +
> > >>>> +#endif /* V4L2_CONNECTOR_H */
> > >>>> +
> > >>>> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > >>>> index 6c07825e18b9..f4df1b95c5ef 100644
> > >>>> --- a/include/media/v4l2-fwnode.h
> > >>>> +++ b/include/media/v4l2-fwnode.h
> > >>>> @@ -22,6 +22,7 @@
> > >>>>  #include <linux/list.h>
> > >>>>  #include <linux/types.h>
> > >>>>  
> > >>>> +#include <media/v4l2-connector.h>
> > >>>>  #include <media/v4l2-mediabus.h>
> > >>>>  #include <media/v4l2-subdev.h>
> > >>>>  
> > >>>> @@ -126,6 +127,38 @@ struct v4l2_fwnode_link {
> > >>>>  	unsigned int remote_port;
> > >>>>  };
> > >>>>  
> > >>>> +/**
> > >>>> + * struct v4l2_fwnode_connector_analog - analog connector data structure
> > >>>> + * @supported_tvnorms: tv norms this connector supports, set to V4L2_STD_ALL
> > >>>> + *                     if no restrictions are specified.
> > >>>> + */
> > >>>> +struct v4l2_fwnode_connector_analog {
> > >>>> +	v4l2_std_id supported_tvnorms;
> > >>>> +};
> > >>>> +
> > >>>> +/**
> > >>>> + * struct v4l2_fwnode_connector - the connector data structure
> > >>>> + * @remote_port: identifier of the remote endpoint port the connector connects
> > >>>> + *		 to
> > >>>> + * @remote_id: identifier of the remote endpoint the connector connects to
> > >>>> + * @label: connetor label
> > >>>> + * @type: connector type
> > >>>> + * @connector: connector configuration
> > >>>> + * @connector.analog: analog connector configuration
> > >>>> + *                    &struct v4l2_fwnode_connector_analog
> > >>>> + */
> > >>>> +struct v4l2_fwnode_connector {
> > >>>> +	unsigned int remote_port;
> > >>>> +	unsigned int remote_id;
> > >>>> +	char label[V4L2_CONNECTOR_MAX_LABEL];
> > >>>> +	enum v4l2_connector_type type;
> > >>>> +
> > >>>> +	union {
> > >>>> +		struct v4l2_fwnode_connector_analog analog;
> > >>>> +		/* future connectors */
> > >>>> +	} connector;
> > >>>> +};
> > >>>> +
> > >>>>  /**
> > >>>>   * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> > >>>>   * @fwnode: pointer to the endpoint's fwnode handle
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

end of thread, other threads:[~2019-08-15 13:37 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-15 12:44 [PATCH v6 00/13] TVP5150 new features Marco Felsch
2019-04-15 12:44 ` [PATCH v6 01/13] dt-bindings: connector: analog: add tv norms property Marco Felsch
2019-05-06 10:01   ` Hans Verkuil
2019-05-06 10:06     ` Hans Verkuil
2019-05-14 18:11     ` Mauro Carvalho Chehab
2019-08-09  6:00       ` Marco Felsch
2019-05-16 16:27   ` Laurent Pinchart
2019-08-09  5:58     ` Marco Felsch
2019-08-15 12:33       ` Laurent Pinchart
2019-08-15 12:50         ` Marco Felsch
2019-08-15 13:02           ` Laurent Pinchart
2019-08-15 13:35             ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 02/13] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
2019-05-06  9:50   ` Hans Verkuil
2019-05-14 18:17     ` Mauro Carvalho Chehab
2019-08-09  7:20     ` Marco Felsch
2019-05-16 16:36   ` Laurent Pinchart
2019-08-09  7:55     ` Marco Felsch
2019-08-15 12:38       ` Laurent Pinchart
2019-08-15 13:04         ` Marco Felsch
2019-08-15 13:10           ` Laurent Pinchart
2019-08-15 13:37             ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 03/13] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
2019-05-06 10:10   ` Hans Verkuil
2019-05-14 18:20     ` Mauro Carvalho Chehab
2019-05-16 16:51       ` Laurent Pinchart
2019-08-09 12:16         ` Marco Felsch
2019-08-15 12:48           ` Laurent Pinchart
2019-08-15 13:14             ` Marco Felsch
2019-08-09  8:59       ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 04/13] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
2019-04-15 12:44 ` [PATCH v6 05/13] media: tvp5150: add input source selection of_graph support Marco Felsch
2019-05-06 10:09   ` Jacopo Mondi
2019-05-14 18:25   ` Mauro Carvalho Chehab
2019-05-16 18:03     ` Laurent Pinchart
2019-08-13  8:54       ` Marco Felsch
2019-08-15 12:51         ` Laurent Pinchart
2019-08-15 13:22           ` Marco Felsch
2019-08-15 13:26             ` Laurent Pinchart
2019-04-15 12:44 ` [PATCH v6 06/13] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
2019-05-14 18:27   ` Mauro Carvalho Chehab
2019-05-16 18:05   ` Laurent Pinchart
2019-08-13  8:56     ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 07/13] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
2019-05-06 13:36   ` Jacopo Mondi
2019-08-09  5:33     ` Marco Felsch
2019-05-14 18:48   ` Mauro Carvalho Chehab
2019-08-09  5:34     ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 08/13] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
2019-05-14 20:20   ` Mauro Carvalho Chehab
2019-08-09  5:42     ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 09/13] media: tvp5150: add s_power callback Marco Felsch
2019-05-14 20:13   ` Mauro Carvalho Chehab
2019-08-09  5:39     ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 10/13] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
2019-04-15 12:44 ` [PATCH v6 11/13] media: dt-bindings: tvp5150: add optional tvnorms documentation Marco Felsch
2019-04-15 12:44 ` [PATCH v6 12/13] media: tvp5150: add support to limit tv norms on connector Marco Felsch
2019-05-16 18:07   ` Laurent Pinchart
2019-08-13  9:10     ` Marco Felsch
2019-08-15 12:53       ` Laurent Pinchart
2019-08-15 13:26         ` Marco Felsch
2019-04-15 12:44 ` [PATCH v6 13/13] media: tvp5150: make debug output more readable Marco Felsch
2019-05-06 13:39   ` Jacopo Mondi
2019-05-14 20:18     ` Mauro Carvalho Chehab
2019-08-09  5:42       ` Marco Felsch
2019-05-06  5:47 ` [PATCH v6 00/13] TVP5150 new features Marco Felsch
2019-05-14 17:18   ` Mauro Carvalho Chehab
2019-05-14 20:20     ` Mauro Carvalho Chehab
2019-05-14 20:58       ` Marco Felsch
2019-05-14 23:41         ` Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).