From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-media@vger.kernel.org
Cc: Steve Longerbeam <steve_longerbeam@mentor.com>,
Marek Vasut <marex@denx.de>, Hans Verkuil <hverkuil@xs4all.nl>,
Gary Bisson <gary.bisson@boundarydevices.com>,
kernel@pengutronix.de, Philipp Zabel <p.zabel@pengutronix.de>
Subject: [PATCH v2 05/21] [media] imx: Add i.MX SoC wide media device driver
Date: Fri, 14 Oct 2016 19:34:25 +0200 [thread overview]
Message-ID: <1476466481-24030-6-git-send-email-p.zabel@pengutronix.de> (raw)
In-Reply-To: <1476466481-24030-1-git-send-email-p.zabel@pengutronix.de>
This driver registers a single, SoC wide media device, which all entities
in the media graph can be registered to. It is probed from device tree
using a capture-subsystem node, listing the IPUv3 input ports, similarly
to the already existing display-subsystem node that lists the IPUv3 output
ports.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
.../devicetree/bindings/media/fsl-imx-capture.txt | 25 +++
drivers/media/platform/Kconfig | 2 +
drivers/media/platform/Makefile | 1 +
drivers/media/platform/imx/Kconfig | 7 +
drivers/media/platform/imx/Makefile | 1 +
drivers/media/platform/imx/imx-media.c | 249 +++++++++++++++++++++
6 files changed, 285 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/fsl-imx-capture.txt
create mode 100644 drivers/media/platform/imx/Kconfig
create mode 100644 drivers/media/platform/imx/Makefile
create mode 100644 drivers/media/platform/imx/imx-media.c
diff --git a/Documentation/devicetree/bindings/media/fsl-imx-capture.txt b/Documentation/devicetree/bindings/media/fsl-imx-capture.txt
new file mode 100644
index 0000000..5805331
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/fsl-imx-capture.txt
@@ -0,0 +1,25 @@
+Freescale i.MX IPUv3 capture subsystem
+======================================
+
+The i.MX5/6 IPUv3 capture subsystem consists of one or two IPUs and all
+external subdevices connected to the IPU CSI input ports. On i.MX5 these
+are only external subdevices. On i.MX6, there are additional SoC internal
+multiplexers and a MIPI CSI-2 bridge connected to the CSI input ports via
+of_graph bindings.
+
+On i.MX6 variants with two IPUs, either a single capture subsystem node may be
+defined, containing all CSI ports, or two separate capture subsystem nodes may
+be defined, each containing the CSI ports of a single IPU. In the latter case
+there must be no external of_graph links between the two subsystems.
+
+Required properties:
+- compatible: should be "fsl,imx-capture-subsystem"
+- ports: should contain a list of phandles pointing to the capture interface
+ ports of IPU devices
+
+Example:
+
+capture-subsystem {
+ compatible = "fsl,imx-capture-subsystem";
+ ports = <&ipu1_csi0>, <&ipu1_csi1>, <&ipu2_csi0>, <&ipu2_csi1>;
+};
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ce4a96f..105bf57 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -29,6 +29,8 @@ config VIDEO_VIA_CAMERA
source "drivers/media/platform/davinci/Kconfig"
+source "drivers/media/platform/imx/Kconfig"
+
source "drivers/media/platform/omap/Kconfig"
source "drivers/media/platform/blackfin/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 40b18d1..f7f9008 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o
obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
+obj-y += imx/
obj-y += omap/
obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
diff --git a/drivers/media/platform/imx/Kconfig b/drivers/media/platform/imx/Kconfig
new file mode 100644
index 0000000..3bd699c
--- /dev/null
+++ b/drivers/media/platform/imx/Kconfig
@@ -0,0 +1,7 @@
+config MEDIA_IMX
+ tristate "Multimedia Support for Freescale i.MX"
+ depends on MEDIA_CONTROLLER
+ default y if IMX_IPUV3_CORE
+ ---help---
+ This driver provides a SoC wide media controller device that all
+ multimedia components in i.MX5 and i.MX6 SoCs can register with.
diff --git a/drivers/media/platform/imx/Makefile b/drivers/media/platform/imx/Makefile
new file mode 100644
index 0000000..74bed76
--- /dev/null
+++ b/drivers/media/platform/imx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MEDIA_IMX) += imx-media.o
diff --git a/drivers/media/platform/imx/imx-media.c b/drivers/media/platform/imx/imx-media.c
new file mode 100644
index 0000000..1f1fab4
--- /dev/null
+++ b/drivers/media/platform/imx/imx-media.c
@@ -0,0 +1,249 @@
+/*
+ * i.MX V4L2 Capture Driver
+ *
+ * Copyright (C) 2016, Pengutronix, Philipp Zabel <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
+
+#define IMX_MEDIA_MAX_PORTS 4
+
+struct imx_media {
+ struct media_device mdev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev subdevs[IMX_MEDIA_MAX_PORTS];
+};
+
+static int v4l2_of_create_pad_link(struct v4l2_subdev *sd,
+ struct v4l2_of_link *link)
+{
+ struct v4l2_subdev *remote_sd, *src_sd, *sink_sd;
+ struct media_link *mlink;
+ int src_port, sink_port;
+
+ if (link->local_port >= sd->entity.num_pads)
+ return -EINVAL;
+
+ remote_sd = v4l2_find_subdev_by_node(sd->v4l2_dev, link->remote_node);
+ if (!remote_sd)
+ return 0;
+
+ if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
+ src_sd = remote_sd;
+ src_port = link->remote_port;
+ sink_sd = sd;
+ sink_port = link->local_port;
+ } else {
+ src_sd = sd;
+ src_port = link->local_port;
+ sink_sd = remote_sd;
+ sink_port = link->remote_port;
+ }
+
+ mlink = media_entity_find_link(&src_sd->entity.pads[src_port],
+ &sink_sd->entity.pads[sink_port]);
+ if (mlink)
+ return 0;
+
+ return media_create_pad_link(&src_sd->entity, src_port,
+ &sink_sd->entity, sink_port, 0);
+}
+
+static int imx_media_complete(struct v4l2_async_notifier *notifier)
+{
+ struct imx_media *im = container_of(notifier, struct imx_media,
+ subdev_notifier);
+ struct media_device *mdev = &im->mdev;
+ struct v4l2_subdev *sd;
+ struct device_node *ep;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /*
+ * Link all subdevices
+ */
+ list_for_each_entry(sd, ¬ifier->done, async_list) {
+ struct v4l2_of_link link;
+ int ret;
+
+ /*
+ * The IPU port nodes 0 and 1 correspond to the CSI subdevices.
+ * We can't use for_each_endpoint_of_node here, which would
+ * iterate over all endpoints of the IPU, including output ones.
+ */
+ if (strcmp(sd->of_node->name, "port") == 0) {
+ /* There should be one endpoint in the CSI port */
+ ep = of_get_next_child(sd->of_node, NULL);
+ if (!ep)
+ continue;
+
+ ret = v4l2_of_parse_link(ep, &link);
+ if (ret) {
+ of_node_put(ep);
+ continue;
+ }
+
+ /*
+ * The IPU port id in the device tree does not
+ * correspond to the CSI pad id. Always connect
+ * the source to the CSI input pad (pad 0).
+ */
+ link.local_port = 0;
+
+ v4l2_of_create_pad_link(sd, &link);
+
+ v4l2_of_put_link(&link);
+
+ continue;
+ }
+
+ /*
+ * TODO: for now assume that all subdevices other than CSI have
+ * a 1:1 relationship between device_node and v4l2_subdev and
+ * between of_graph port number and media_entity pad index.
+ */
+ for_each_endpoint_of_node(sd->of_node, ep) {
+ ret = v4l2_of_parse_link(ep, &link);
+ if (ret)
+ continue;
+
+ v4l2_of_create_pad_link(sd, &link);
+
+ v4l2_of_put_link(&link);
+ }
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ return v4l2_device_register_subdev_nodes(&im->v4l2_dev);
+}
+
+static void imx_media_register_notifier(struct imx_media *im)
+{
+ struct v4l2_async_notifier *notifier = &im->subdev_notifier;
+ struct v4l2_async_subdev *asd = &im->subdevs[0];
+ struct device_node *port;
+ int i;
+
+ /*
+ * ports correspond to the CSI subdevices that terminate the media
+ * pipelines.
+ */
+ for (i = 0; i < IMX_MEDIA_MAX_PORTS; i++) {
+ port = of_parse_phandle(im->mdev.dev->of_node, "ports", i);
+ if (!port)
+ break;
+
+ if (!of_device_is_available(port->parent)) {
+ of_node_put(port);
+ continue;
+ }
+
+ asd[i].match_type = V4L2_ASYNC_MATCH_OF;
+ asd[i].match.of.node = port;
+ of_node_put(port);
+ }
+ notifier->num_subdevs = i;
+ notifier->subdevs = devm_kcalloc(im->mdev.dev, i,
+ sizeof(*notifier->subdevs),
+ GFP_KERNEL);
+ for (i = 0; i < notifier->num_subdevs; i++)
+ notifier->subdevs[i] = &im->subdevs[i];
+
+ notifier->complete = imx_media_complete;
+
+ v4l2_async_notifier_register(&im->v4l2_dev, notifier);
+}
+
+static int imx_media_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct media_device *mdev;
+ struct imx_media *im;
+ int ret;
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ im = devm_kzalloc(dev, sizeof(*im), GFP_KERNEL);
+ if (!im)
+ return -ENOMEM;
+
+ mdev = &im->mdev;
+ mdev->dev = dev;
+ strlcpy(mdev->model, "i.MX IPUv3", sizeof(mdev->model));
+ media_device_init(mdev);
+
+ im->v4l2_dev.mdev = mdev;
+ ret = v4l2_device_register(dev, &im->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "Failed to register v4l2 device: %d\n", ret);
+ return ret;
+ }
+
+ imx_media_register_notifier(im);
+
+ ret = media_device_register(mdev);
+ if (ret) {
+ dev_err(dev, "Failed to register media controller device: %d\n",
+ ret);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, mdev);
+
+ return 0;
+
+err:
+ media_device_cleanup(mdev);
+ return ret;
+}
+
+static int imx_media_remove(struct platform_device *pdev)
+{
+ struct media_device *mdev = platform_get_drvdata(pdev);
+ struct imx_media *im = container_of(mdev, struct imx_media, mdev);
+
+ media_device_unregister(mdev);
+ v4l2_device_unregister(&im->v4l2_dev);
+ media_device_cleanup(mdev);
+
+ return 0;
+}
+
+static const struct of_device_id imx_media_dt_ids[] = {
+ { .compatible = "fsl,imx-capture-subsystem", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx_media_dt_ids);
+
+static struct platform_driver imx_media_driver = {
+ .probe = imx_media_probe,
+ .remove = imx_media_remove,
+ .driver = {
+ .name = "imx-media",
+ .of_match_table = imx_media_dt_ids,
+ },
+};
+module_platform_driver(imx_media_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX SoC wide media device");
+MODULE_LICENSE("GPL");
--
2.9.3
next prev parent reply other threads:[~2016-10-14 17:34 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-14 17:34 [PATCH v2 00/21] Basic i.MX IPUv3 capture support Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 01/21] [media] v4l2-async: move code out of v4l2_async_notifier_register into v4l2_async_test_nofity_all Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 02/21] [media] v4l2-async: allow subdevices to add further subdevices to the notifier waiting list Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 03/21] [media] v4l: of: add v4l2_of_subdev_registered Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 04/21] [media] v4l2-async: add new subdevices to the tail of subdev_list Philipp Zabel
2016-10-14 17:34 ` Philipp Zabel [this message]
2016-10-14 17:34 ` [PATCH v2 06/21] [media] imx: Add IPUv3 media common code Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 07/21] [media] imx-ipu: Add i.MX IPUv3 CSI subdevice driver Philipp Zabel
2016-11-08 7:18 ` Ying Liu
2016-10-14 17:34 ` [PATCH v2 08/21] [media] imx: Add i.MX IPUv3 capture driver Philipp Zabel
2016-10-17 11:32 ` Jack Mitchell
2016-10-17 11:35 ` Marek Vasut
2016-10-17 11:40 ` Jack Mitchell
2016-10-17 12:12 ` Philipp Zabel
2016-10-19 16:22 ` Jack Mitchell
2016-10-19 19:25 ` Marek Vasut
2016-10-26 11:29 ` Jack Mitchell
2016-11-08 7:21 ` Ying Liu
2016-10-14 17:34 ` [PATCH v2 09/21] [media] platform: add video-multiplexer subdevice driver Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 10/21] [media] imx: Add i.MX MIPI CSI-2 " Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 11/21] [media] tc358743: put lanes in STOP state before starting streaming Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 12/21] ARM: dts: imx6qdl: Add capture-subsystem node Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 13/21] ARM: dts: imx6qdl: Add mipi_ipu1/2 multiplexers, mipi_csi, and their connections Philipp Zabel
2016-11-08 8:23 ` Ying Liu
2016-10-14 17:34 ` [PATCH v2 14/21] ARM: dts: imx6qdl: Add MIPI CSI-2 D-PHY compatible and clocks Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 15/21] ARM: dts: nitrogen6x: Add dtsi for BD_HDMI_MIPI HDMI to MIPI CSI-2 receiver board Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 16/21] gpu: ipuv3: add ipu_csi_set_downsize Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 17/21] [media] imx-ipuv3-csi: support downsizing Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 18/21] [media] add mux and video interface bridge entity functions Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 19/21] [media] video-multiplexer: set entity function to mux Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 20/21] [media] imx: Set i.MX MIPI CSI-2 entity function to bridge Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 21/21] [media] tc358743: set entity function to video interface bridge Philipp Zabel
2016-10-17 10:18 ` [PATCH v2 00/21] Basic i.MX IPUv3 capture support Gary Bisson
2016-10-17 12:41 ` Philipp Zabel
2016-10-19 21:30 ` Sakari Ailus
[not found] ` <CAH-u=807nRYzza0kTfOMv1AiWazk6FGJyz6W5_bYw7v9nOrccA@mail.gmail.com>
2016-12-29 15:10 ` Jean-Michel Hautbois
2016-12-29 20:51 ` Robert Schwebel
2016-12-30 19:06 ` Marek Vasut
2016-12-30 20:26 ` Steve Longerbeam
2017-01-02 13:51 ` Jean-Michel Hautbois
2017-01-02 14:45 ` Hans Verkuil
2017-01-02 14:59 ` Jean-Michel Hautbois
2017-01-02 19:19 ` Fabio Estevam
2017-01-02 19:20 ` Steve Longerbeam
2017-01-02 17:04 ` Fabio Estevam
2017-01-02 19:17 ` Steve Longerbeam
2017-01-09 19:43 ` Philipp Zabel
2017-01-10 0:15 ` Steve Longerbeam
2017-01-10 23:52 ` Steve Longerbeam
2017-01-11 9:12 ` Jean-Michel Hautbois
2017-01-11 12:10 ` Philipp Zabel
2017-01-12 23:22 ` Steve Longerbeam
2017-01-12 23:43 ` Steve Longerbeam
2017-01-13 2:22 ` Steve Longerbeam
2017-01-13 11:18 ` Philipp Zabel
2017-01-13 11:04 ` Philipp Zabel
2017-01-13 11:05 ` Philipp Zabel
2017-01-14 20:26 ` Steve Longerbeam
2017-01-16 11:49 ` Philipp Zabel
2017-01-11 12:11 ` Philipp Zabel
2017-01-24 18:11 ` Philipp Zabel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1476466481-24030-6-git-send-email-p.zabel@pengutronix.de \
--to=p.zabel@pengutronix.de \
--cc=gary.bisson@boundarydevices.com \
--cc=hverkuil@xs4all.nl \
--cc=kernel@pengutronix.de \
--cc=linux-media@vger.kernel.org \
--cc=marex@denx.de \
--cc=steve_longerbeam@mentor.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).