From: Steve Longerbeam <slongerbeam@gmail.com>
To: robh+dt@kernel.org, mark.rutland@arm.com, shawnguo@kernel.org,
kernel@pengutronix.de, fabio.estevam@nxp.com,
linux@armlinux.org.uk, mchehab@kernel.org, hverkuil@xs4all.nl,
nick@shmanahar.org, markus.heiser@darmarIT.de,
p.zabel@pengutronix.de,
laurent.pinchart+renesas@ideasonboard.com, bparrot@ti.com,
geert@linux-m68k.org, arnd@arndb.de, sudipm.mukherjee@gmail.com,
minghsiu.tsai@mediatek.com, tiffany.lin@mediatek.com,
jean-christophe.trotin@st.com, horms+renesas@verge.net.au,
niklas.soderlund+renesas@ragnatech.se, robert.jarzmik@free.fr,
songjun.wu@microchip.com, andrew-ct.chen@mediatek.com,
gregkh@linuxfoundation.org
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-media@vger.kernel.org, devel@driverdev.osuosl.org,
Steve Longerbeam <steve_longerbeam@mentor.com>
Subject: [PATCH v3 18/24] media: imx: Add SMFC subdev driver
Date: Fri, 6 Jan 2017 18:11:36 -0800 [thread overview]
Message-ID: <1483755102-24785-19-git-send-email-steve_longerbeam@mentor.com> (raw)
In-Reply-To: <1483755102-24785-1-git-send-email-steve_longerbeam@mentor.com>
This is a media entity subdevice driver for the i.MX Sensor Multi-FIFO
Controller module. Video frames are received from the CSI and can
be routed to various sinks including the i.MX Image Converter for
scaling, color-space conversion, motion compensated deinterlacing,
and image rotation.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/staging/media/imx/Makefile | 1 +
drivers/staging/media/imx/imx-smfc.c | 737 +++++++++++++++++++++++++++++++++++
2 files changed, 738 insertions(+)
create mode 100644 drivers/staging/media/imx/imx-smfc.c
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index 133672a..3559d7b 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-common.o
obj-$(CONFIG_VIDEO_IMX_CAMERA) += imx-csi.o
+obj-$(CONFIG_VIDEO_IMX_CAMERA) += imx-smfc.o
diff --git a/drivers/staging/media/imx/imx-smfc.c b/drivers/staging/media/imx/imx-smfc.c
new file mode 100644
index 0000000..614a4381
--- /dev/null
+++ b/drivers/staging/media/imx/imx-smfc.c
@@ -0,0 +1,737 @@
+/*
+ * V4L2 Capture SMFC Subdev for Freescale i.MX5/6 SOC
+ *
+ * This subdevice handles capture of raw/unconverted video frames
+ * from the CSI, directly to memory via the Sensor Multi-FIFO Controller.
+ *
+ * Copyright (c) 2012-2016 Mentor Graphics Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/imx.h>
+#include "imx-media.h"
+
+/*
+ * Min/Max supported width and heights.
+ *
+ * We allow planar output from the SMFC, so we have to align
+ * output width by 16 pixels to meet IDMAC alignment requirements,
+ * which also means input width must have the same alignment.
+ */
+#define MIN_W 176
+#define MIN_H 144
+#define MAX_W 8192
+#define MAX_H 4096
+#define W_ALIGN 4 /* multiple of 16 pixels */
+#define H_ALIGN 1 /* multiple of 2 lines */
+#define S_ALIGN 1 /* multiple of 2 */
+
+#define SMFC_NUM_PADS 2
+
+struct imx_smfc_priv {
+ struct device *dev;
+ struct ipu_soc *ipu;
+ struct imx_media_dev *md;
+ struct v4l2_subdev sd;
+ struct media_pad pad[SMFC_NUM_PADS];
+ int ipu_id;
+ int smfc_id;
+ int input_pad;
+ int output_pad;
+
+ struct ipuv3_channel *smfc_ch;
+ struct ipu_smfc *smfc;
+
+ struct v4l2_mbus_framefmt format_mbus[SMFC_NUM_PADS];
+ const struct imx_media_pixfmt *cc[SMFC_NUM_PADS];
+
+ struct v4l2_mbus_config sensor_mbus_cfg;
+
+ /* the dma buffer ring to send to sink */
+ struct imx_media_dma_buf_ring *out_ring;
+ struct imx_media_dma_buf *next;
+
+ int ipu_buf_num; /* ipu double buffer index: 0-1 */
+
+ /* the sink that will receive the dma buffers */
+ struct v4l2_subdev *sink_sd;
+ struct v4l2_subdev *src_sd;
+
+ /*
+ * the CSI id and mipi virtual channel number at
+ * link validate
+ */
+ int csi_id;
+ int vc_num;
+
+ /* the attached sensor at stream on */
+ struct imx_media_subdev *sensor;
+
+ spinlock_t irqlock;
+ struct timer_list eof_timeout_timer;
+ int eof_irq;
+ int nfb4eof_irq;
+
+ bool stream_on; /* streaming is on */
+ bool last_eof; /* waiting for last EOF at stream off */
+ struct completion last_eof_comp;
+};
+
+static void imx_smfc_put_ipu_resources(struct imx_smfc_priv *priv)
+{
+ if (!IS_ERR_OR_NULL(priv->smfc_ch))
+ ipu_idmac_put(priv->smfc_ch);
+ priv->smfc_ch = NULL;
+
+ if (!IS_ERR_OR_NULL(priv->smfc))
+ ipu_smfc_put(priv->smfc);
+ priv->smfc = NULL;
+}
+
+static int imx_smfc_get_ipu_resources(struct imx_smfc_priv *priv)
+{
+ int ch_num, ret;
+
+ priv->ipu = priv->md->ipu[priv->ipu_id];
+
+ ch_num = IPUV3_CHANNEL_CSI0 + priv->smfc_id;
+
+ priv->smfc = ipu_smfc_get(priv->ipu, ch_num);
+ if (IS_ERR(priv->smfc)) {
+ v4l2_err(&priv->sd, "failed to get SMFC\n");
+ ret = PTR_ERR(priv->smfc);
+ goto out;
+ }
+
+ priv->smfc_ch = ipu_idmac_get(priv->ipu, ch_num);
+ if (IS_ERR(priv->smfc_ch)) {
+ v4l2_err(&priv->sd, "could not get IDMAC channel %u\n", ch_num);
+ ret = PTR_ERR(priv->smfc_ch);
+ goto out;
+ }
+
+ return 0;
+out:
+ imx_smfc_put_ipu_resources(priv);
+ return ret;
+}
+
+static irqreturn_t imx_smfc_eof_interrupt(int irq, void *dev_id)
+{
+ struct imx_smfc_priv *priv = dev_id;
+ struct imx_media_dma_buf *done, *next;
+
+ spin_lock(&priv->irqlock);
+
+ if (priv->last_eof) {
+ complete(&priv->last_eof_comp);
+ priv->last_eof = false;
+ goto unlock;
+ }
+
+ /* inform CSI of this EOF so it can monitor frame intervals */
+ v4l2_subdev_call(priv->src_sd, core, interrupt_service_routine,
+ 0, NULL);
+
+ done = imx_media_dma_buf_get_active(priv->out_ring);
+ /* give the completed buffer to the sink */
+ if (!WARN_ON(!done))
+ imx_media_dma_buf_done(done, IMX_MEDIA_BUF_STATUS_DONE);
+
+ /* priv->next buffer is now the active one */
+ imx_media_dma_buf_set_active(priv->next);
+
+ /* bump the EOF timeout timer */
+ mod_timer(&priv->eof_timeout_timer,
+ jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
+
+ if (ipu_idmac_buffer_is_ready(priv->smfc_ch, priv->ipu_buf_num))
+ ipu_idmac_clear_buffer(priv->smfc_ch, priv->ipu_buf_num);
+
+ /* get next queued buffer */
+ next = imx_media_dma_buf_get_next_queued(priv->out_ring);
+
+ ipu_cpmem_set_buffer(priv->smfc_ch, priv->ipu_buf_num, next->phys);
+ ipu_idmac_select_buffer(priv->smfc_ch, priv->ipu_buf_num);
+
+ /* toggle IPU double-buffer index */
+ priv->ipu_buf_num ^= 1;
+ priv->next = next;
+
+unlock:
+ spin_unlock(&priv->irqlock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_smfc_nfb4eof_interrupt(int irq, void *dev_id)
+{
+ struct imx_smfc_priv *priv = dev_id;
+ static const struct v4l2_event ev = {
+ .type = V4L2_EVENT_IMX_NFB4EOF,
+ };
+
+ v4l2_err(&priv->sd, "NFB4EOF\n");
+
+ v4l2_subdev_notify_event(&priv->sd, &ev);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * EOF timeout timer function.
+ */
+static void imx_smfc_eof_timeout(unsigned long data)
+{
+ struct imx_smfc_priv *priv = (struct imx_smfc_priv *)data;
+ static const struct v4l2_event ev = {
+ .type = V4L2_EVENT_IMX_EOF_TIMEOUT,
+ };
+
+ v4l2_err(&priv->sd, "EOF timeout\n");
+
+ v4l2_subdev_notify_event(&priv->sd, &ev);
+}
+
+/* init the SMFC IDMAC channel */
+static void imx_smfc_setup_channel(struct imx_smfc_priv *priv)
+{
+ struct v4l2_mbus_framefmt *infmt, *outfmt;
+ struct imx_media_dma_buf *buf0, *buf1;
+ unsigned int burst_size;
+ struct ipu_image image;
+ bool passthrough;
+
+ infmt = &priv->format_mbus[priv->input_pad];
+ outfmt = &priv->format_mbus[priv->output_pad];
+
+ ipu_cpmem_zero(priv->smfc_ch);
+
+ imx_media_mbus_fmt_to_ipu_image(&image, outfmt);
+
+ buf0 = imx_media_dma_buf_get_next_queued(priv->out_ring);
+ imx_media_dma_buf_set_active(buf0);
+ buf1 = imx_media_dma_buf_get_next_queued(priv->out_ring);
+ priv->next = buf1;
+
+ image.phys0 = buf0->phys;
+ image.phys1 = buf1->phys;
+ ipu_cpmem_set_image(priv->smfc_ch, &image);
+
+ burst_size = (outfmt->width & 0xf) ? 8 : 16;
+
+ ipu_cpmem_set_burstsize(priv->smfc_ch, burst_size);
+
+ /*
+ * If the sensor uses 16-bit parallel CSI bus, we must handle
+ * the data internally in the IPU as 16-bit generic, aka
+ * passthrough mode.
+ */
+ passthrough = (priv->sensor_mbus_cfg.type != V4L2_MBUS_CSI2 &&
+ priv->sensor->sensor_ep.bus.parallel.bus_width >= 16);
+
+ if (passthrough)
+ ipu_cpmem_set_format_passthrough(priv->smfc_ch, 16);
+
+ /*
+ * Set the channel for the direct CSI-->memory via SMFC
+ * use-case to very high priority, by enabling the watermark
+ * signal in the SMFC, enabling WM in the channel, and setting
+ * the channel priority to high.
+ *
+ * Refer to the i.mx6 rev. D TRM Table 36-8: Calculated priority
+ * value.
+ *
+ * The WM's are set very low by intention here to ensure that
+ * the SMFC FIFOs do not overflow.
+ */
+ ipu_smfc_set_watermark(priv->smfc, 0x02, 0x01);
+ ipu_cpmem_set_high_priority(priv->smfc_ch);
+ ipu_idmac_enable_watermark(priv->smfc_ch, true);
+ ipu_cpmem_set_axi_id(priv->smfc_ch, 0);
+ ipu_idmac_lock_enable(priv->smfc_ch, 8);
+
+ burst_size = ipu_cpmem_get_burstsize(priv->smfc_ch);
+ burst_size = passthrough ?
+ (burst_size >> 3) - 1 : (burst_size >> 2) - 1;
+
+ ipu_smfc_set_burstsize(priv->smfc, burst_size);
+
+ if (outfmt->field == V4L2_FIELD_NONE &&
+ (V4L2_FIELD_HAS_BOTH(infmt->field) ||
+ infmt->field == V4L2_FIELD_ALTERNATE))
+ ipu_cpmem_interlaced_scan(priv->smfc_ch,
+ image.pix.bytesperline);
+
+ ipu_idmac_set_double_buffer(priv->smfc_ch, true);
+}
+
+static void imx_smfc_unsetup(struct imx_smfc_priv *priv)
+{
+ ipu_idmac_disable_channel(priv->smfc_ch);
+ ipu_smfc_disable(priv->smfc);
+}
+
+static void imx_smfc_setup(struct imx_smfc_priv *priv)
+{
+ imx_smfc_setup_channel(priv);
+
+ ipu_cpmem_dump(priv->smfc_ch);
+ ipu_dump(priv->ipu);
+
+ ipu_smfc_enable(priv->smfc);
+
+ /* set buffers ready */
+ ipu_idmac_select_buffer(priv->smfc_ch, 0);
+ ipu_idmac_select_buffer(priv->smfc_ch, 1);
+
+ /* enable the channels */
+ ipu_idmac_enable_channel(priv->smfc_ch);
+}
+
+static int imx_smfc_start(struct imx_smfc_priv *priv)
+{
+ int ret;
+
+ if (!priv->sensor) {
+ v4l2_err(&priv->sd, "no sensor attached\n");
+ return -EINVAL;
+ }
+
+ ret = imx_smfc_get_ipu_resources(priv);
+ if (ret)
+ return ret;
+
+ ipu_smfc_map_channel(priv->smfc, priv->csi_id, priv->vc_num);
+
+ /* ask the sink for the buffer ring */
+ ret = v4l2_subdev_call(priv->sink_sd, core, ioctl,
+ IMX_MEDIA_REQ_DMA_BUF_SINK_RING,
+ &priv->out_ring);
+ if (ret)
+ goto out_put_ipu;
+
+ priv->ipu_buf_num = 0;
+
+ /* init EOF completion waitq */
+ init_completion(&priv->last_eof_comp);
+ priv->last_eof = false;
+
+ imx_smfc_setup(priv);
+
+ priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu,
+ priv->smfc_ch,
+ IPU_IRQ_NFB4EOF);
+ ret = devm_request_irq(priv->dev, priv->nfb4eof_irq,
+ imx_smfc_nfb4eof_interrupt, 0,
+ "imx-smfc-nfb4eof", priv);
+ if (ret) {
+ v4l2_err(&priv->sd,
+ "Error registering NFB4EOF irq: %d\n", ret);
+ goto out_unsetup;
+ }
+
+ priv->eof_irq = ipu_idmac_channel_irq(priv->ipu, priv->smfc_ch,
+ IPU_IRQ_EOF);
+
+ ret = devm_request_irq(priv->dev, priv->eof_irq,
+ imx_smfc_eof_interrupt, 0,
+ "imx-smfc-eof", priv);
+ if (ret) {
+ v4l2_err(&priv->sd,
+ "Error registering eof irq: %d\n", ret);
+ goto out_free_nfb4eof_irq;
+ }
+
+ /* start the EOF timeout timer */
+ mod_timer(&priv->eof_timeout_timer,
+ jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
+
+ return 0;
+
+out_free_nfb4eof_irq:
+ devm_free_irq(priv->dev, priv->nfb4eof_irq, priv);
+out_unsetup:
+ imx_smfc_unsetup(priv);
+out_put_ipu:
+ imx_smfc_put_ipu_resources(priv);
+ return ret;
+}
+
+static void imx_smfc_stop(struct imx_smfc_priv *priv)
+{
+ unsigned long flags;
+ int ret;
+
+ /* mark next EOF interrupt as the last before stream off */
+ spin_lock_irqsave(&priv->irqlock, flags);
+ priv->last_eof = true;
+ spin_unlock_irqrestore(&priv->irqlock, flags);
+
+ /*
+ * and then wait for interrupt handler to mark completion.
+ */
+ ret = wait_for_completion_timeout(
+ &priv->last_eof_comp, msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
+ if (ret == 0)
+ v4l2_warn(&priv->sd, "wait last EOF timeout\n");
+
+ devm_free_irq(priv->dev, priv->eof_irq, priv);
+ devm_free_irq(priv->dev, priv->nfb4eof_irq, priv);
+
+ imx_smfc_unsetup(priv);
+
+ /* cancel the EOF timeout timer */
+ del_timer_sync(&priv->eof_timeout_timer);
+
+ priv->out_ring = NULL;
+
+ /* inform sink that the buffer ring can now be freed */
+ v4l2_subdev_call(priv->sink_sd, core, ioctl,
+ IMX_MEDIA_REL_DMA_BUF_SINK_RING, 0);
+
+ imx_smfc_put_ipu_resources(priv);
+}
+
+static int imx_smfc_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (!priv->src_sd || !priv->sink_sd)
+ return -EPIPE;
+
+ v4l2_info(sd, "stream %s\n", enable ? "ON" : "OFF");
+
+ if (enable && !priv->stream_on)
+ ret = imx_smfc_start(priv);
+ else if (!enable && priv->stream_on)
+ imx_smfc_stop(priv);
+
+ if (!ret)
+ priv->stream_on = enable;
+ return ret;
+}
+
+static int imx_smfc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+
+ if (code->pad >= SMFC_NUM_PADS)
+ return -EINVAL;
+
+ return imx_media_enum_format(&code->code, code->index,
+ true, code->pad == priv->output_pad);
+}
+
+static int imx_smfc_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+
+ if (sdformat->pad >= SMFC_NUM_PADS)
+ return -EINVAL;
+
+ sdformat->format = priv->format_mbus[sdformat->pad];
+
+ return 0;
+}
+
+static int imx_smfc_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *infmt, *outfmt;
+ const struct imx_media_pixfmt *cc, *incc;
+ bool allow_planar;
+ u32 code;
+
+ if (sdformat->pad >= SMFC_NUM_PADS)
+ return -EINVAL;
+
+ if (priv->stream_on)
+ return -EBUSY;
+
+ infmt = &priv->format_mbus[priv->input_pad];
+ outfmt = &priv->format_mbus[priv->output_pad];
+ allow_planar = (sdformat->pad == priv->output_pad);
+
+ cc = imx_media_find_format(0, sdformat->format.code,
+ true, allow_planar);
+ if (!cc) {
+ imx_media_enum_format(&code, 0, true, false);
+ cc = imx_media_find_format(0, code, true, false);
+ sdformat->format.code = cc->codes[0];
+ }
+
+ v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
+ W_ALIGN, &sdformat->format.height,
+ MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+
+ if (sdformat->pad == priv->output_pad) {
+ incc = priv->cc[priv->input_pad];
+ sdformat->format.width = infmt->width;
+ sdformat->format.height = infmt->height;
+ if (sdformat->format.field != V4L2_FIELD_NONE)
+ sdformat->format.field = infmt->field;
+ if (cc->cs != incc->cs) {
+ sdformat->format.code = infmt->code;
+ cc = imx_media_find_format(0, sdformat->format.code,
+ true, false);
+ }
+ }
+
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
+ cfg->try_fmt = sdformat->format;
+ } else {
+ priv->format_mbus[sdformat->pad] = sdformat->format;
+ priv->cc[sdformat->pad] = cc;
+ }
+
+ return 0;
+}
+
+static int imx_smfc_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 imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *remote_sd;
+
+ dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name,
+ local->entity->name);
+
+ remote_sd = media_entity_to_v4l2_subdev(remote->entity);
+
+ if (local->flags & MEDIA_PAD_FL_SOURCE) {
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (priv->sink_sd)
+ return -EBUSY;
+ priv->sink_sd = remote_sd;
+ } else {
+ priv->sink_sd = NULL;
+ }
+
+ return 0;
+ }
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (priv->src_sd)
+ return -EBUSY;
+ priv->src_sd = remote_sd;
+ } else {
+ priv->src_sd = NULL;
+ return 0;
+ }
+
+ /* must attach to CSI source */
+ if (!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_CSI))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int imx_smfc_link_validate(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt);
+ if (ret)
+ return ret;
+
+ switch (priv->src_sd->grp_id) {
+ case IMX_MEDIA_GRP_ID_CSI0:
+ priv->csi_id = 0;
+ break;
+ case IMX_MEDIA_GRP_ID_CSI1:
+ priv->csi_id = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priv->sensor = __imx_media_find_sensor(priv->md, &priv->sd.entity);
+ if (IS_ERR(priv->sensor)) {
+ v4l2_err(&priv->sd, "no sensor attached\n");
+ ret = PTR_ERR(priv->sensor);
+ priv->sensor = NULL;
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(priv->sensor->sd, video, g_mbus_config,
+ &priv->sensor_mbus_cfg);
+ if (ret)
+ return ret;
+
+ priv->vc_num = 0;
+ if (priv->sensor_mbus_cfg.type == V4L2_MBUS_CSI2) {
+ /* see NOTE in imx-csi.c */
+#if 0
+ priv->vc_num = imx_media_find_mipi_csi2_channel(
+ priv->md, &priv->sd.entity);
+ if (priv->vc_num < 0)
+ return vc_num;
+#endif
+ }
+
+ return 0;
+}
+
+/*
+ * retrieve our pads parsed from the OF graph by the media device
+ */
+static int imx_smfc_registered(struct v4l2_subdev *sd)
+{
+ struct imx_smfc_priv *priv = v4l2_get_subdevdata(sd);
+ struct imx_media_subdev *imxsd;
+ struct imx_media_pad *pad;
+ int i;
+
+ /* get media device */
+ priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
+
+ imxsd = imx_media_find_subdev_by_sd(priv->md, sd);
+ if (IS_ERR(imxsd))
+ return PTR_ERR(imxsd);
+
+ if (imxsd->num_sink_pads != 1 || imxsd->num_src_pads != 1)
+ return -EINVAL;
+
+ for (i = 0; i < SMFC_NUM_PADS; i++) {
+ pad = &imxsd->pad[i];
+ priv->pad[i] = pad->pad;
+ if (priv->pad[i].flags & MEDIA_PAD_FL_SINK)
+ priv->input_pad = i;
+ else
+ priv->output_pad = i;
+
+ /* set a default mbus format */
+ imx_media_init_mbus_fmt(&priv->format_mbus[i],
+ 640, 480, 0, V4L2_FIELD_NONE,
+ &priv->cc[i]);
+ }
+
+ return media_entity_pads_init(&sd->entity, SMFC_NUM_PADS, priv->pad);
+}
+
+static struct media_entity_operations imx_smfc_entity_ops = {
+ .link_setup = imx_smfc_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static struct v4l2_subdev_video_ops imx_smfc_video_ops = {
+ .s_stream = imx_smfc_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops imx_smfc_pad_ops = {
+ .enum_mbus_code = imx_smfc_enum_mbus_code,
+ .get_fmt = imx_smfc_get_fmt,
+ .set_fmt = imx_smfc_set_fmt,
+ .link_validate = imx_smfc_link_validate,
+};
+
+static struct v4l2_subdev_ops imx_smfc_subdev_ops = {
+ .video = &imx_smfc_video_ops,
+ .pad = &imx_smfc_pad_ops,
+};
+
+static struct v4l2_subdev_internal_ops imx_smfc_internal_ops = {
+ .registered = imx_smfc_registered,
+};
+
+static int imx_smfc_probe(struct platform_device *pdev)
+{
+ struct imx_media_internal_sd_platformdata *pdata;
+ struct imx_smfc_priv *priv;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, &priv->sd);
+ priv->dev = &pdev->dev;
+
+ pdata = priv->dev->platform_data;
+ priv->ipu_id = pdata->ipu_id;
+
+ init_timer(&priv->eof_timeout_timer);
+ priv->eof_timeout_timer.data = (unsigned long)priv;
+ priv->eof_timeout_timer.function = imx_smfc_eof_timeout;
+ spin_lock_init(&priv->irqlock);
+
+ v4l2_subdev_init(&priv->sd, &imx_smfc_subdev_ops);
+ v4l2_set_subdevdata(&priv->sd, priv);
+ priv->sd.internal_ops = &imx_smfc_internal_ops;
+ priv->sd.entity.ops = &imx_smfc_entity_ops;
+ /* FIXME: this the right function? */
+ priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ priv->sd.dev = &pdev->dev;
+ priv->sd.owner = THIS_MODULE;
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ /* get our group id and SMFC id */
+ priv->sd.grp_id = pdata->grp_id;
+ priv->smfc_id = (pdata->grp_id >> IMX_MEDIA_GRP_ID_SMFC_BIT) - 1;
+ strncpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
+
+ return v4l2_async_register_subdev(&priv->sd);
+}
+
+static int imx_smfc_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct imx_smfc_priv *priv = container_of(sd, struct imx_smfc_priv, sd);
+
+ v4l2_async_unregister_subdev(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_device_unregister_subdev(sd);
+
+ return 0;
+}
+
+static const struct platform_device_id imx_smfc_ids[] = {
+ { .name = "imx-ipuv3-smfc" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, imx_smfc_ids);
+
+static struct platform_driver imx_smfc_driver = {
+ .probe = imx_smfc_probe,
+ .remove = imx_smfc_remove,
+ .id_table = imx_smfc_ids,
+ .driver = {
+ .name = "imx-ipuv3-smfc",
+ },
+};
+module_platform_driver(imx_smfc_driver);
+
+MODULE_DESCRIPTION("i.MX SMFC subdev driver");
+MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ipuv3-smfc");
--
2.7.4
next prev parent reply other threads:[~2017-01-07 2:16 UTC|newest]
Thread overview: 185+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-07 2:11 [PATCH v3 00/24] i.MX Media Driver Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 01/24] [media] dt-bindings: Add bindings for i.MX media driver Steve Longerbeam
2017-01-13 11:55 ` Philipp Zabel
2017-01-13 19:03 ` Steve Longerbeam
2017-01-16 12:09 ` Philipp Zabel
2017-01-16 17:13 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 02/24] ARM: dts: imx6qdl: Add compatible, clocks, irqs to MIPI CSI-2 node Steve Longerbeam
2017-01-13 11:57 ` Philipp Zabel
2017-01-13 22:40 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 03/24] ARM: dts: imx6qdl: Add mipi_ipu1/2 multiplexers, mipi_csi, and their connections Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 04/24] ARM: dts: imx6qdl: add media device Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 05/24] ARM: dts: imx6qdl-sabrelite: remove erratum ERR006687 workaround Steve Longerbeam
2017-01-13 11:59 ` Philipp Zabel
2017-01-07 2:11 ` [PATCH v3 06/24] ARM: dts: imx6-sabrelite: add OV5642 and OV5640 camera sensors Steve Longerbeam
2017-01-13 12:03 ` Philipp Zabel
2017-01-13 23:04 ` Steve Longerbeam
2017-01-16 12:55 ` Philipp Zabel
2017-01-16 17:15 ` Steve Longerbeam
2017-02-05 15:17 ` Laurent Pinchart
2017-01-30 22:28 ` Russell King - ARM Linux
2017-01-30 22:51 ` Russell King - ARM Linux
2017-02-05 15:24 ` Laurent Pinchart
2017-02-05 15:37 ` Russell King - ARM Linux
2017-01-07 2:11 ` [PATCH v3 07/24] ARM: dts: imx6-sabresd: " Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 08/24] ARM: dts: imx6-sabreauto: create i2cmux for i2c3 Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 09/24] ARM: dts: imx6-sabreauto: add reset-gpios property for max7310_b Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 10/24] ARM: dts: imx6-sabreauto: add pinctrl for gpt input capture Steve Longerbeam
2017-01-12 19:37 ` Tim Harvey
2017-01-12 23:40 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 11/24] ARM: dts: imx6-sabreauto: add the ADV7180 video decoder Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 12/24] add mux and video interface bridge entity functions Steve Longerbeam
2017-01-20 13:56 ` Hans Verkuil
2017-02-05 15:36 ` Laurent Pinchart
2017-02-06 10:27 ` Philipp Zabel
2017-01-07 2:11 ` [PATCH v3 13/24] platform: add video-multiplexer subdevice driver Steve Longerbeam
2017-01-10 5:35 ` Rob Herring
2017-01-20 14:03 ` Hans Verkuil
2017-01-24 12:02 ` Philipp Zabel
2017-01-25 2:07 ` Steve Longerbeam
2017-02-05 15:48 ` Laurent Pinchart
2017-02-06 9:50 ` Hans Verkuil
2017-02-06 22:33 ` Laurent Pinchart
2017-02-06 23:10 ` Steve Longerbeam
2017-02-07 10:26 ` Laurent Pinchart
2017-02-07 10:41 ` Philipp Zabel
2017-02-07 14:11 ` Laurent Pinchart
2017-02-07 13:36 ` Benoit Parrot
2017-02-07 20:50 ` Sakari Ailus
2017-02-07 23:04 ` Laurent Pinchart
2017-01-24 12:44 ` Javier Martinez Canillas
2017-01-26 1:22 ` Steve Longerbeam
2017-02-07 20:46 ` Sakari Ailus
2017-02-08 9:47 ` Philipp Zabel
2017-02-08 10:05 ` Laurent Pinchart
2017-01-07 2:11 ` [PATCH v3 14/24] UAPI: Add media UAPI Kbuild file Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 15/24] media: Add userspace header file for i.MX Steve Longerbeam
2017-01-13 12:05 ` Philipp Zabel
2017-01-13 23:13 ` Steve Longerbeam
2017-02-05 15:50 ` Laurent Pinchart
2017-01-07 2:11 ` [PATCH v3 16/24] media: Add i.MX media core driver Steve Longerbeam
2017-01-13 15:20 ` Philipp Zabel
2017-01-14 22:46 ` Steve Longerbeam
2017-01-16 13:47 ` Philipp Zabel
2017-01-23 2:31 ` Steve Longerbeam
2017-01-23 11:13 ` Philipp Zabel
2017-01-24 1:38 ` Steve Longerbeam
2017-01-24 1:45 ` Steve Longerbeam
2017-01-24 11:37 ` Philipp Zabel
2017-01-30 15:28 ` Russell King - ARM Linux
[not found] ` <2b1d2418-1ad4-6373-cb07-c3aeab48187f@gmail.com>
2017-01-19 1:44 ` Steve Longerbeam
2017-01-24 11:39 ` Philipp Zabel
2017-01-30 22:29 ` Russell King - ARM Linux
2017-02-02 22:44 ` Russell King - ARM Linux
2017-02-02 22:50 ` Russell King - ARM Linux
2017-02-07 1:54 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 17/24] media: imx: Add CSI subdev driver Steve Longerbeam
2017-01-16 15:03 ` Philipp Zabel
2017-01-16 21:15 ` Steve Longerbeam
2017-01-30 22:29 ` Russell King - ARM Linux
2017-01-31 10:30 ` Russell King - ARM Linux
2017-01-31 11:20 ` Russell King - ARM Linux
2017-02-01 0:31 ` Steve Longerbeam
2017-02-01 0:58 ` Russell King - ARM Linux
2017-01-31 15:51 ` Philipp Zabel
2017-01-31 16:48 ` Philipp Zabel
2017-02-01 1:40 ` Steve Longerbeam
2017-02-07 16:18 ` [PATCH] media: imx: csi: fix crop rectangle reset in sink set_fmt Philipp Zabel
2017-01-07 2:11 ` Steve Longerbeam [this message]
2017-02-01 18:39 ` [PATCH v3 18/24] media: imx: Add SMFC subdev driver Russell King - ARM Linux
2017-02-01 18:52 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 19/24] media: imx: Add IC subdev drivers Steve Longerbeam
2017-01-20 14:29 ` Hans Verkuil
2017-01-25 2:39 ` Steve Longerbeam
2017-01-30 22:29 ` Russell King - ARM Linux
2017-01-07 2:11 ` [PATCH v3 20/24] media: imx: Add Camera Interface subdev driver Steve Longerbeam
2017-01-20 14:38 ` Hans Verkuil
2017-01-24 2:15 ` Steve Longerbeam
2017-01-31 13:42 ` Russell King - ARM Linux
2017-01-31 18:21 ` Steve Longerbeam
2017-01-31 20:33 ` Russell King - ARM Linux
2017-01-31 21:55 ` Ian Arkver
2017-01-31 22:04 ` Russell King - ARM Linux
2017-01-31 22:33 ` Ian Arkver
2017-01-31 22:36 ` Steve Longerbeam
2017-01-31 23:30 ` Russell King - ARM Linux
2017-01-31 23:41 ` Steve Longerbeam
2017-02-02 22:35 ` Russell King - ARM Linux
2017-02-07 1:52 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 21/24] media: imx: Add MIPI CSI-2 Receiver " Steve Longerbeam
2017-01-30 22:30 ` Russell King - ARM Linux
2017-01-31 0:01 ` Russell King - ARM Linux
2017-01-31 9:49 ` Philipp Zabel
2017-02-01 1:02 ` Steve Longerbeam
2017-02-01 1:13 ` Russell King - ARM Linux
2017-01-31 0:31 ` Russell King - ARM Linux
2017-01-31 2:11 ` Steve Longerbeam
2017-02-01 23:44 ` Russell King - ARM Linux
2017-02-02 0:04 ` Steve Longerbeam
2017-02-02 11:50 ` Philipp Zabel
2017-02-08 23:23 ` Steve Longerbeam
2017-02-08 23:42 ` Russell King - ARM Linux
2017-02-09 23:49 ` Steve Longerbeam
2017-02-09 23:51 ` Steve Longerbeam
2017-02-13 9:20 ` Philipp Zabel
2017-02-13 23:20 ` Steve Longerbeam
2017-02-14 16:59 ` Philipp Zabel
2017-02-09 9:43 ` Philipp Zabel
2017-01-07 2:11 ` [PATCH v3 22/24] media: imx: Add MIPI CSI-2 OV5640 sensor " Steve Longerbeam
2017-01-20 14:48 ` Hans Verkuil
2017-01-25 19:10 ` Steve Longerbeam
2017-01-30 23:29 ` Russell King - ARM Linux
2017-01-31 3:31 ` Steve Longerbeam
2017-02-02 10:36 ` Laurent Pinchart
2017-02-12 22:53 ` Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 23/24] media: imx: Add Parallel OV5642 " Steve Longerbeam
2017-01-07 2:11 ` [PATCH v3 24/24] ARM: imx_v6_v7_defconfig: Enable staging video4linux drivers Steve Longerbeam
2017-01-11 23:14 ` [PATCH v3 00/24] i.MX Media Driver Tim Harvey
2017-01-12 3:22 ` Steve Longerbeam
2017-01-20 13:52 ` Hans Verkuil
2017-01-20 16:31 ` Philipp Zabel
2017-01-20 18:40 ` Steve Longerbeam
2017-01-20 20:39 ` Hans Verkuil
2017-01-23 11:00 ` Philipp Zabel
2017-01-23 11:08 ` Hans Verkuil
2017-01-24 11:28 ` Philipp Zabel
2017-01-23 23:08 ` Steve Longerbeam
2017-01-24 11:27 ` Philipp Zabel
2017-01-28 19:27 ` Steve Longerbeam
2017-01-30 13:06 ` Russell King - ARM Linux
2017-01-31 10:09 ` Philipp Zabel
2017-01-31 13:14 ` Russell King - ARM Linux
2017-01-31 13:35 ` Philipp Zabel
2017-01-31 14:04 ` Russell King - ARM Linux
2017-01-31 0:45 ` Russell King - ARM Linux
2017-01-31 1:06 ` Russell King - ARM Linux
2017-01-31 2:06 ` Steve Longerbeam
2017-01-31 1:22 ` Steve Longerbeam
2017-01-31 9:49 ` Philipp Zabel
2017-01-31 10:21 ` Russell King - ARM Linux
2017-01-31 11:00 ` Russell King - ARM Linux
2017-01-31 23:43 ` Steve Longerbeam
2017-02-01 0:23 ` Russell King - ARM Linux
2017-02-01 1:54 ` Steve Longerbeam
2017-02-01 9:20 ` Russell King - ARM Linux
2017-01-31 13:54 ` Philipp Zabel
2017-01-31 14:25 ` Philipp Zabel
2017-01-31 15:03 ` Russell King - ARM Linux
2017-02-01 1:26 ` Steve Longerbeam
2017-02-01 9:30 ` Philipp Zabel
2017-02-01 10:11 ` Russell King - ARM Linux
2017-02-01 10:42 ` Philipp Zabel
2017-02-01 10:53 ` Russell King - ARM Linux
2017-02-02 0:19 ` Steve Longerbeam
2017-02-03 14:41 ` Laurent Pinchart
2017-02-03 17:56 ` Steve Longerbeam
2017-02-15 2:27 ` Steve Longerbeam
2017-02-15 9:33 ` Philipp Zabel
2017-02-02 17:22 ` Russell King - ARM Linux
2017-02-02 17:31 ` Steve Longerbeam
2017-02-02 17:56 ` Russell King - ARM Linux
2017-02-02 18:26 ` Steve Longerbeam
2017-02-02 18:58 ` Russell King - ARM Linux
2017-02-02 19:12 ` Steve Longerbeam
2017-02-02 22:29 ` Russell King - ARM Linux
2017-02-03 18:49 ` Steve Longerbeam
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=1483755102-24785-19-git-send-email-steve_longerbeam@mentor.com \
--to=slongerbeam@gmail.com \
--cc=andrew-ct.chen@mediatek.com \
--cc=arnd@arndb.de \
--cc=bparrot@ti.com \
--cc=devel@driverdev.osuosl.org \
--cc=devicetree@vger.kernel.org \
--cc=fabio.estevam@nxp.com \
--cc=geert@linux-m68k.org \
--cc=gregkh@linuxfoundation.org \
--cc=horms+renesas@verge.net.au \
--cc=hverkuil@xs4all.nl \
--cc=jean-christophe.trotin@st.com \
--cc=kernel@pengutronix.de \
--cc=laurent.pinchart+renesas@ideasonboard.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=mark.rutland@arm.com \
--cc=markus.heiser@darmarIT.de \
--cc=mchehab@kernel.org \
--cc=minghsiu.tsai@mediatek.com \
--cc=nick@shmanahar.org \
--cc=niklas.soderlund+renesas@ragnatech.se \
--cc=p.zabel@pengutronix.de \
--cc=robert.jarzmik@free.fr \
--cc=robh+dt@kernel.org \
--cc=shawnguo@kernel.org \
--cc=songjun.wu@microchip.com \
--cc=steve_longerbeam@mentor.com \
--cc=sudipm.mukherjee@gmail.com \
--cc=tiffany.lin@mediatek.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).