]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/commitdiff
drm: xilinx: sdi: adding vblank support
authorSaurabh Sengar <saurabh.singh@xilinx.com>
Mon, 30 Oct 2017 18:16:41 +0000 (23:46 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Tue, 31 Oct 2017 15:36:46 +0000 (16:36 +0100)
Adding vblank support APIs in SDI drm driver.
In order to export these APIs added the header
file so that it can be used by crtc.

Signed-off-by: Saurabh Sengar <saurabhs@xilinx.com>
Acked-by: Hyun Kwon <hyun.kwon@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/gpu/drm/xilinx/xilinx_drm_sdi.c
drivers/gpu/drm/xilinx/xilinx_drm_sdi.h [new file with mode: 0644]

index d165f18fd8429c11a91377db2cdc323f9315b9d9..5f2099179525ce0c16af2735d0aba6a1d071db21 100644 (file)
 #include <drm/drmP.h>
 #include <linux/component.h>
 #include <linux/device.h>
+#include <linux/list.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/phy/phy.h>
 #include <video/videomode.h>
+#include "xilinx_drm_sdi.h"
 #include "xilinx_vtc.h"
 
 /* SDI register offsets */
 #define ST352_BYTE4                            0x01
 #define INVALID_VALUE                          -1
 #define GT_TIMEOUT                             500
+
+static LIST_HEAD(xilinx_sdi_list);
+static DEFINE_MUTEX(xilinx_sdi_lock);
 /**
  * enum payload_line_1 - Payload Ids Line 1 number
  * @PAYLD_LN1_HD_3_6_12G:      line 1 HD,3G,6G or 12G mode value
@@ -164,6 +169,9 @@ enum sdi_modes {
  * @mode_flags: SDI operation mode related flags
  * @wait_event: wait event
  * @event_received: wait event status
+ * @list: entry in the global SDI subsystem list
+ * @vblank_fn: vblank handler
+ * @vblank_data: vblank data to be used in vblank_fn
  * @sdi_mode: configurable SDI mode parameter, supported values are:
  *             0 - HD
  *             1 - SD
@@ -187,6 +195,9 @@ struct xilinx_sdi {
        u32 mode_flags;
        wait_queue_head_t wait_event;
        bool event_received;
+       struct list_head list;
+       void (*vblank_fn)(void *);
+       void *vblank_data;
        struct drm_property *sdi_mode;
        u32 sdi_mod_prop_val;
        struct drm_property *sdi_data_strm;
@@ -1233,6 +1244,121 @@ static const struct component_ops xilinx_sdi_component_ops = {
        .unbind = xilinx_sdi_unbind,
 };
 
+static irqreturn_t xilinx_sdi_vblank_handler(int irq, void *data)
+{
+       struct xilinx_sdi *sdi = (struct xilinx_sdi *)data;
+       u32 intr = xilinx_vtc_intr_get(sdi->vtc);
+
+       if (!intr)
+               return IRQ_NONE;
+
+       if (sdi->vblank_fn)
+               sdi->vblank_fn(sdi->vblank_data);
+
+       xilinx_vtc_intr_clear(sdi->vtc, intr);
+       return IRQ_HANDLED;
+}
+
+/**
+ * xilinx_drm_sdi_enable_vblank - Enable the vblank handling
+ * @sdi: SDI subsystem
+ * @vblank_fn: callback to be called on vblank event
+ * @vblank_data: data to be used in @vblank_fn
+ *
+ * This function register the vblank handler, and the handler will be triggered
+ * on vblank event after.
+ */
+void xilinx_drm_sdi_enable_vblank(struct xilinx_sdi *sdi,
+                                 void (*vblank_fn)(void *),
+                                 void *vblank_data)
+{
+       sdi->vblank_fn = vblank_fn;
+       sdi->vblank_data = vblank_data;
+       xilinx_vtc_vblank_enable(sdi->vtc);
+}
+EXPORT_SYMBOL_GPL(xilinx_drm_sdi_enable_vblank);
+
+/**
+ * xilinx_drm_sdi_disable_vblank - Disable the vblank handling
+ * @sdi: SDI subsystem
+ *
+ * Disable the vblank handler. The vblank handler and data are unregistered.
+ */
+void xilinx_drm_sdi_disable_vblank(struct xilinx_sdi *sdi)
+{
+       sdi->vblank_fn = NULL;
+       sdi->vblank_data = NULL;
+       xilinx_vtc_vblank_disable(sdi->vtc);
+}
+
+/**
+ * xilinx_sdi_register_device - Register the SDI subsystem to the global list
+ * @sdi: SDI subsystem
+ *
+ * Register the SDI subsystem instance to the global list
+ */
+static void xilinx_sdi_register_device(struct xilinx_sdi *sdi)
+{
+       mutex_lock(&xilinx_sdi_lock);
+       list_add_tail(&sdi->list, &xilinx_sdi_list);
+       mutex_unlock(&xilinx_sdi_lock);
+}
+
+/**
+ * xilinx_drm_sdi_of_get - Get the SDI subsystem instance
+ * @np: parent device node
+ *
+ * This function searches and returns a SDI subsystem structure for
+ * the parent device node, @np. The SDI subsystem node should be a child node
+ * of @np, with 'xlnx,v-smpte-uhdsdi-tx-ss' property pointing to the SDI
+ * device node. An instance can be shared by multiple users.
+ *
+ * Return: corresponding SDI subsystem structure if found. NULL if
+ * the device node doesn't have 'xlnx,v-smpte-uhdsdi-tx-ss' property, or
+ * -EPROBE_DEFER error pointer if the the SDI subsystem isn't found.
+ */
+struct xilinx_sdi *xilinx_drm_sdi_of_get(struct device_node *np)
+{
+       struct xilinx_sdi *found = NULL;
+       struct xilinx_sdi *sdi;
+       struct device_node *ep_node, *sdi_node;
+
+       ep_node = of_find_node_by_name(np, "endpoint");
+       if (!ep_node)
+               return NULL;
+       sdi_node = of_graph_get_remote_port_parent(ep_node);
+       of_node_put(ep_node);
+       if (!sdi_node)
+               return NULL;
+
+       mutex_lock(&xilinx_sdi_lock);
+       list_for_each_entry(sdi, &xilinx_sdi_list, list) {
+               if (sdi->dev->of_node == sdi_node) {
+                       found = sdi;
+                       break;
+               }
+       }
+       mutex_unlock(&xilinx_sdi_lock);
+
+       of_node_put(sdi_node);
+       if (!found)
+               return ERR_PTR(-EPROBE_DEFER);
+       return found;
+}
+
+/**
+ * xilinx_sdi_unregister_device - Unregister the SDI subsystem instance
+ * @sdi: SDI subsystem
+ *
+ * Unregister the SDI subsystem instance from the global list
+ */
+static void xilinx_sdi_unregister_device(struct xilinx_sdi *sdi)
+{
+       mutex_lock(&xilinx_sdi_lock);
+       list_del(&sdi->list);
+       mutex_unlock(&xilinx_sdi_lock);
+}
+
 static int xilinx_sdi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1279,14 +1405,27 @@ static int xilinx_sdi_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       irq = platform_get_irq(pdev, 1); /* vblank interrupt */
+       if (irq < 0)
+               return irq;
+       ret = devm_request_threaded_irq(sdi->dev, irq, NULL,
+                                       xilinx_sdi_vblank_handler, IRQF_ONESHOT,
+                                       "sdiTx-vblank", sdi);
+       if (ret < 0)
+               return ret;
+
        init_waitqueue_head(&sdi->wait_event);
        sdi->event_received = false;
 
+       xilinx_sdi_register_device(sdi);
        return component_add(dev, &xilinx_sdi_component_ops);
 }
 
 static int xilinx_sdi_remove(struct platform_device *pdev)
 {
+       struct xilinx_sdi *sdi = platform_get_drvdata(pdev);
+
+       xilinx_sdi_unregister_device(sdi);
        component_del(&pdev->dev, &xilinx_sdi_component_ops);
 
        return 0;
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_sdi.h b/drivers/gpu/drm/xilinx/xilinx_drm_sdi.h
new file mode 100644 (file)
index 0000000..b9a773e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SDI subsystem header for Xilinx DRM KMS
+ *
+ *  Copyright (C) 2017 Xilinx, Inc.
+ *
+ *  Author: Saurabh Sengar <saurabhs@xilinx.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _XILINX_DRM_SDI_H_
+#define _XILINX_DRM_SDI_H_
+
+struct xilinx_sdi;
+struct device_node;
+
+struct xilinx_sdi *xilinx_drm_sdi_of_get(struct device_node *np);
+void xilinx_drm_sdi_enable_vblank(struct xilinx_sdi *sdi,
+                                 void (*vblank_fn)(void *),
+                                 void *vblank_data);
+void xilinx_drm_sdi_disable_vblank(struct xilinx_sdi *sdi);
+#endif /* _XILINX_DRM_SDI_H_ */