summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAlan Kwong <akwong@codeaurora.org>2016-08-09 18:08:17 -0400
committerAlan Kwong <akwong@codeaurora.org>2016-09-21 18:25:05 -0400
commit86a6d482aca57c9481752a407d44a844be22e906 (patch)
tree1402a80dff54cf42e87f8a5e90c54897f758a7f5 /drivers/gpu
parent04495f87647dafca1c86c78a915108b16bdcd3b4 (diff)
drm/msm/sde: reorganize top level interrupt handling code
Re-organize interrupt handling code to match device hierarchy such that the top level handler maps to MDSS level, and core level handler maps to MDP level. They are moved to separate files corresponding to top and core respectively. This improves maintainability of the interrupt handling abstraction. Change-Id: Ib76cfa0f157722d9c1926bf21fc789c2be19b495 Signed-off-by: Alan Kwong <akwong@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/sde/sde_core_irq.c277
-rw-r--r--drivers/gpu/drm/msm/sde/sde_core_irq.h111
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c16
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c18
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c20
-rw-r--r--drivers/gpu/drm/msm/sde/sde_irq.c356
-rw-r--r--drivers/gpu/drm/msm/sde/sde_irq.h59
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c20
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.h104
10 files changed, 571 insertions, 411 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b8a2df8c16b3..d805d526f27d 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -36,6 +36,7 @@ msm-y := \
sde/sde_encoder_phys_vid.o \
sde/sde_encoder_phys_cmd.o \
sde/sde_irq.o \
+ sde/sde_core_irq.o \
sde/sde_rm.o \
sde/sde_kms_utils.o \
sde/sde_kms.o \
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
new file mode 100644
index 000000000000..6e3310165b36
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+
+#include "sde_core_irq.h"
+#include "sde_power_handle.h"
+
+static void sde_core_irq_callback_handler(void *arg, int irq_idx)
+{
+ struct sde_kms *sde_kms = arg;
+ struct sde_irq *irq_obj = &sde_kms->irq_obj;
+
+ /*
+ * Perform registered function callback
+ */
+ if (irq_obj->irq_cb_tbl && irq_obj->irq_cb_tbl[irq_idx].func)
+ irq_obj->irq_cb_tbl[irq_idx].func(
+ irq_obj->irq_cb_tbl[irq_idx].arg,
+ irq_idx);
+
+ /*
+ * Clear pending interrupt status in HW.
+ * NOTE: sde_core_irq_callback_handler is protected by top-level
+ * spinlock, so it is safe to clear any interrupt status here.
+ */
+ sde_kms->hw_intr->ops.clear_interrupt_status(
+ sde_kms->hw_intr,
+ irq_idx);
+}
+
+static void sde_core_irq_intf_error_handler(void *arg, int irq_idx)
+{
+ SDE_ERROR("INTF underrun detected, irq_idx=%d\n", irq_idx);
+}
+
+int sde_core_irq_idx_lookup(struct sde_kms *sde_kms,
+ enum sde_intr_type intr_type, u32 instance_idx)
+{
+ if (!sde_kms || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.irq_idx_lookup)
+ return -EINVAL;
+
+ return sde_kms->hw_intr->ops.irq_idx_lookup(intr_type,
+ instance_idx);
+}
+
+int sde_core_irq_enable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
+{
+ int i;
+ int ret = 0;
+
+ if (!sde_kms || !irq_idxs || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.enable_irq)
+ return -EINVAL;
+
+ for (i = 0; i < irq_count; i++) {
+ ret = sde_kms->hw_intr->ops.enable_irq(
+ sde_kms->hw_intr,
+ irq_idxs[i]);
+ if (ret) {
+ SDE_ERROR("Fail to enable IRQ for irq_idx:%d\n",
+ irq_idxs[i]);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+int sde_core_irq_disable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
+{
+ int i;
+ int ret = 0;
+
+ if (!sde_kms || !irq_idxs || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.disable_irq)
+ return -EINVAL;
+
+ for (i = 0; i < irq_count; i++) {
+ ret = sde_kms->hw_intr->ops.disable_irq(
+ sde_kms->hw_intr,
+ irq_idxs[i]);
+ if (ret) {
+ SDE_ERROR("Fail to disable IRQ for irq_idx:%d\n",
+ irq_idxs[i]);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+u32 sde_core_irq_read(struct sde_kms *sde_kms, int irq_idx, bool clear)
+{
+ if (!sde_kms || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.get_interrupt_status)
+ return 0;
+
+ return sde_kms->hw_intr->ops.get_interrupt_status(sde_kms->hw_intr,
+ irq_idx, clear);
+}
+
+int sde_core_irq_register_callback(struct sde_kms *sde_kms, int irq_idx,
+ struct sde_irq_callback *register_irq_cb)
+{
+ struct sde_irq_callback *irq_cb_tbl;
+ unsigned long irq_flags;
+
+ /*
+ * We allow NULL register_irq_cb as input for callback registration
+ */
+ if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl)
+ return -EINVAL;
+
+ if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
+ SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx);
+ return -EINVAL;
+ }
+
+ irq_cb_tbl = sde_kms->irq_obj.irq_cb_tbl;
+ spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
+ irq_cb_tbl[irq_idx].func = register_irq_cb ?
+ register_irq_cb->func : NULL;
+ irq_cb_tbl[irq_idx].arg = register_irq_cb ?
+ register_irq_cb->arg : NULL;
+ spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
+
+ return 0;
+}
+
+static void sde_clear_all_irqs(struct sde_kms *sde_kms)
+{
+ if (!sde_kms || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.clear_all_irqs)
+ return;
+
+ sde_kms->hw_intr->ops.clear_all_irqs(sde_kms->hw_intr);
+}
+
+static void sde_disable_all_irqs(struct sde_kms *sde_kms)
+{
+ if (!sde_kms || !sde_kms->hw_intr ||
+ !sde_kms->hw_intr->ops.disable_all_irqs)
+ return;
+
+ sde_kms->hw_intr->ops.disable_all_irqs(sde_kms->hw_intr);
+}
+
+void sde_core_irq_preinstall(struct sde_kms *sde_kms)
+{
+ struct msm_drm_private *priv;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ } else if (!sde_kms->dev) {
+ SDE_ERROR("invalid drm device\n");
+ return;
+ } else if (!sde_kms->dev->dev_private) {
+ SDE_ERROR("invalid device private\n");
+ return;
+ }
+ priv = sde_kms->dev->dev_private;
+
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+ sde_clear_all_irqs(sde_kms);
+ sde_disable_all_irqs(sde_kms);
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+
+ spin_lock_init(&sde_kms->irq_obj.cb_lock);
+
+ /* Create irq callbacks for all possible irq_idx */
+ sde_kms->irq_obj.total_irqs = sde_kms->hw_intr->irq_idx_tbl_size;
+ sde_kms->irq_obj.irq_cb_tbl = kcalloc(sde_kms->irq_obj.total_irqs,
+ sizeof(struct sde_irq_callback), GFP_KERNEL);
+}
+
+int sde_core_irq_postinstall(struct sde_kms *sde_kms)
+{
+ struct msm_drm_private *priv;
+ struct sde_irq_callback irq_cb;
+ int irq_idx;
+ int i;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return -EINVAL;
+ } else if (!sde_kms->dev) {
+ SDE_ERROR("invalid drm device\n");
+ return -EINVAL;
+ } else if (!sde_kms->dev->dev_private) {
+ SDE_ERROR("invalid device private\n");
+ return -EINVAL;
+ }
+ priv = sde_kms->dev->dev_private;
+
+ irq_cb.func = sde_core_irq_intf_error_handler;
+ irq_cb.arg = sde_kms;
+
+ /* Register interface underrun callback */
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+ for (i = 0; i < sde_kms->catalog->intf_count; i++) {
+ irq_idx = sde_core_irq_idx_lookup(sde_kms,
+ SDE_IRQ_TYPE_INTF_UNDER_RUN, i+INTF_0);
+ sde_core_irq_register_callback(sde_kms, irq_idx, &irq_cb);
+ sde_core_irq_enable(sde_kms, &irq_idx, 1);
+ }
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+
+ return 0;
+}
+
+void sde_core_irq_uninstall(struct sde_kms *sde_kms)
+{
+ struct msm_drm_private *priv;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ } else if (!sde_kms->dev) {
+ SDE_ERROR("invalid drm device\n");
+ return;
+ } else if (!sde_kms->dev->dev_private) {
+ SDE_ERROR("invalid device private\n");
+ return;
+ }
+ priv = sde_kms->dev->dev_private;
+
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+ sde_clear_all_irqs(sde_kms);
+ sde_disable_all_irqs(sde_kms);
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+
+ kfree(sde_kms->irq_obj.irq_cb_tbl);
+ sde_kms->irq_obj.irq_cb_tbl = NULL;
+}
+
+irqreturn_t sde_core_irq(struct sde_kms *sde_kms)
+{
+ /*
+ * Read interrupt status from all sources. Interrupt status are
+ * stored within hw_intr.
+ * Function will also clear the interrupt status after reading.
+ * Individual interrupt status bit will only get stored if it
+ * is enabled.
+ */
+ sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr);
+
+ /*
+ * Dispatch to HW driver to handle interrupt lookup that is being
+ * fired. When matching interrupt is located, HW driver will call to
+ * sde_core_irq_callback_handler with the irq_idx from the lookup table.
+ * sde_core_irq_callback_handler will perform the registered function
+ * callback, and do the interrupt status clearing once the registered
+ * callback is finished.
+ */
+ sde_kms->hw_intr->ops.dispatch_irqs(
+ sde_kms->hw_intr,
+ sde_core_irq_callback_handler,
+ sde_kms);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h
new file mode 100644
index 000000000000..5b5bdf1b70c5
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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 __SDE_CORE_IRQ_H__
+#define __SDE_CORE_IRQ_H__
+
+#include "sde_kms.h"
+#include "sde_hw_interrupts.h"
+
+/**
+ * sde_core_irq_preinstall - perform pre-installation of core IRQ handler
+ * @sde_kms: SDE handle
+ * @return: none
+ */
+void sde_core_irq_preinstall(struct sde_kms *sde_kms);
+
+/**
+ * sde_core_irq_postinstall - perform post-installation of core IRQ handler
+ * @sde_kms: SDE handle
+ * @return: 0 if success; error code otherwise
+ */
+int sde_core_irq_postinstall(struct sde_kms *sde_kms);
+
+/**
+ * sde_core_irq_uninstall - uninstall core IRQ handler
+ * @sde_kms: SDE handle
+ * @return: none
+ */
+void sde_core_irq_uninstall(struct sde_kms *sde_kms);
+
+/**
+ * sde_core_irq - core IRQ handler
+ * @sde_kms: SDE handle
+ * @return: interrupt handling status
+ */
+irqreturn_t sde_core_irq(struct sde_kms *sde_kms);
+
+/**
+ * sde_core_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW
+ * interrupt mapping table.
+ * @sde_kms: SDE handle
+ * @intr_type: SDE HW interrupt type for lookup
+ * @instance_idx: SDE HW block instance defined in sde_hw_mdss.h
+ * @return: irq_idx or -EINVAL when fail to lookup
+ */
+int sde_core_irq_idx_lookup(
+ struct sde_kms *sde_kms,
+ enum sde_intr_type intr_type,
+ uint32_t instance_idx);
+
+/**
+ * sde_core_irq_enable - IRQ helper function for enabling one or more IRQs
+ * @sde_kms: SDE handle
+ * @irq_idxs: Array of irq index
+ * @irq_count: Number of irq_idx provided in the array
+ * @return: 0 for success enabling IRQ, otherwise failure
+ */
+int sde_core_irq_enable(
+ struct sde_kms *sde_kms,
+ int *irq_idxs,
+ uint32_t irq_count);
+
+/**
+ * sde_core_irq_disable - IRQ helper function for disabling one of more IRQs
+ * @sde_kms: SDE handle
+ * @irq_idxs: Array of irq index
+ * @irq_count: Number of irq_idx provided in the array
+ * @return: 0 for success disabling IRQ, otherwise failure
+ */
+int sde_core_irq_disable(
+ struct sde_kms *sde_kms,
+ int *irq_idxs,
+ uint32_t irq_count);
+
+/**
+ * sde_core_irq_read - IRQ helper function for reading IRQ status
+ * @sde_kms: SDE handle
+ * @irq_idx: irq index
+ * @clear: True to clear the irq after read
+ * @return: non-zero if irq detected; otherwise no irq detected
+ */
+u32 sde_core_irq_read(
+ struct sde_kms *sde_kms,
+ int irq_idx,
+ bool clear);
+
+/**
+ * sde_core_irq_register_callback - For registering callback function on IRQ
+ * interrupt
+ * @sde_kms: SDE handle
+ * @irq_idx: irq index
+ * @irq_cb: IRQ callback structure, containing callback function
+ * and argument. Passing NULL for irq_cb will unregister
+ * the callback for the given irq_idx
+ * @return: 0 for success registering callback, otherwise failure
+ */
+int sde_core_irq_register_callback(
+ struct sde_kms *sde_kms,
+ int irq_idx,
+ struct sde_irq_callback *irq_cb);
+
+#endif /* __SDE_CORE_IRQ_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index fb7cc9b30efc..95011d963528 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -16,6 +16,7 @@
#include "sde_encoder_phys.h"
#include "sde_hw_interrupts.h"
+#include "sde_core_irq.h"
#include "sde_formats.h"
#define to_sde_encoder_phys_cmd(x) \
@@ -133,7 +134,7 @@ static int sde_encoder_phys_cmd_register_pp_irq(
struct sde_irq_callback irq_cb;
int ret = 0;
- *irq_idx = sde_irq_idx_lookup(phys_enc->sde_kms, intr_type,
+ *irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms, intr_type,
cmd_enc->hw_pp->idx);
if (*irq_idx < 0) {
DRM_ERROR(
@@ -145,13 +146,14 @@ static int sde_encoder_phys_cmd_register_pp_irq(
irq_cb.func = irq_func;
irq_cb.arg = cmd_enc;
- ret = sde_register_irq_callback(phys_enc->sde_kms, *irq_idx, &irq_cb);
+ ret = sde_core_irq_register_callback(phys_enc->sde_kms, *irq_idx,
+ &irq_cb);
if (ret) {
DRM_ERROR("Failed to register IRQ callback %s", irq_name);
return ret;
}
- ret = sde_enable_irq(phys_enc->sde_kms, irq_idx, 1);
+ ret = sde_core_irq_enable(phys_enc->sde_kms, irq_idx, 1);
if (ret) {
DRM_ERROR(
"Failed to enable IRQ for %s, pp %d, irq_idx=%d",
@@ -161,7 +163,8 @@ static int sde_encoder_phys_cmd_register_pp_irq(
*irq_idx = -EINVAL;
/* Unregister callback on IRQ enable failure */
- sde_register_irq_callback(phys_enc->sde_kms, *irq_idx, NULL);
+ sde_core_irq_register_callback(phys_enc->sde_kms, *irq_idx,
+ NULL);
return ret;
}
@@ -180,8 +183,9 @@ static int sde_encoder_phys_cmd_unregister_pp_irq(
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
- sde_disable_irq(phys_enc->sde_kms, &irq_idx, 1);
- sde_register_irq_callback(phys_enc->sde_kms, irq_idx, NULL);
+ sde_core_irq_disable(phys_enc->sde_kms, &irq_idx, 1);
+ sde_core_irq_register_callback(phys_enc->sde_kms, irq_idx,
+ NULL);
DBG("unregister IRQ for pp %d, irq_idx=%d\n",
cmd_enc->hw_pp->idx,
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 75575dbe79ac..0432b04d4a81 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -14,6 +14,7 @@
#include "sde_encoder_phys.h"
#include "sde_hw_interrupts.h"
+#include "sde_core_irq.h"
#include "sde_formats.h"
#define VBLANK_TIMEOUT msecs_to_jiffies(100)
@@ -318,7 +319,7 @@ static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc)
struct sde_irq_callback irq_cb;
int ret = 0;
- vid_enc->irq_idx = sde_irq_idx_lookup(phys_enc->sde_kms,
+ vid_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
SDE_IRQ_TYPE_INTF_VSYNC, vid_enc->hw_intf->idx);
if (vid_enc->irq_idx < 0) {
DRM_ERROR(
@@ -329,14 +330,14 @@ static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc)
irq_cb.func = sde_encoder_phys_vid_vblank_irq;
irq_cb.arg = vid_enc;
- ret = sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx,
- &irq_cb);
+ ret = sde_core_irq_register_callback(phys_enc->sde_kms,
+ vid_enc->irq_idx, &irq_cb);
if (ret) {
DRM_ERROR("failed to register IRQ callback INTF_VSYNC");
return ret;
}
- ret = sde_enable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1);
+ ret = sde_core_irq_enable(phys_enc->sde_kms, &vid_enc->irq_idx, 1);
if (ret) {
DRM_ERROR(
"failed to enable IRQ for INTF_VSYNC, intf %d, irq_idx=%d",
@@ -345,8 +346,8 @@ static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc)
vid_enc->irq_idx = -EINVAL;
/* Unregister callback on IRQ enable failure */
- sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx,
- NULL);
+ sde_core_irq_register_callback(phys_enc->sde_kms,
+ vid_enc->irq_idx, NULL);
return ret;
}
@@ -363,8 +364,9 @@ static int sde_encoder_phys_vid_unregister_irq(
struct sde_encoder_phys_vid *vid_enc =
to_sde_encoder_phys_vid(phys_enc);
- sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, NULL);
- sde_disable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1);
+ sde_core_irq_register_callback(phys_enc->sde_kms, vid_enc->irq_idx,
+ NULL);
+ sde_core_irq_disable(phys_enc->sde_kms, &vid_enc->irq_idx, 1);
DBG("unregister IRQ for intf %d, irq_idx=%d",
vid_enc->hw_intf->idx,
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index e935db7845fe..3681de54f19a 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -21,6 +21,7 @@
#include "sde_formats.h"
#include "sde_hw_top.h"
#include "sde_hw_interrupts.h"
+#include "sde_core_irq.h"
#include "sde_wb.h"
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
@@ -487,8 +488,9 @@ static int sde_encoder_phys_wb_unregister_irq(
if (wb_enc->bypass_irqreg)
return 0;
- sde_disable_irq(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
- sde_register_irq_callback(phys_enc->sde_kms, wb_enc->irq_idx, NULL);
+ sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
+ sde_core_irq_register_callback(phys_enc->sde_kms, wb_enc->irq_idx,
+ NULL);
SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n",
hw_wb->idx - WB_0,
@@ -532,7 +534,7 @@ static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
return 0;
intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb);
- wb_enc->irq_idx = sde_irq_idx_lookup(phys_enc->sde_kms,
+ wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
intr_type, hw_wb->idx);
if (wb_enc->irq_idx < 0) {
SDE_ERROR(
@@ -543,14 +545,14 @@ static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
irq_cb.func = sde_encoder_phys_wb_done_irq;
irq_cb.arg = wb_enc;
- ret = sde_register_irq_callback(phys_enc->sde_kms, wb_enc->irq_idx,
- &irq_cb);
+ ret = sde_core_irq_register_callback(phys_enc->sde_kms,
+ wb_enc->irq_idx, &irq_cb);
if (ret) {
SDE_ERROR("failed to register IRQ callback WB_DONE\n");
return ret;
}
- ret = sde_enable_irq(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
+ ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
if (ret) {
SDE_ERROR(
"failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n",
@@ -559,8 +561,8 @@ static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
wb_enc->irq_idx = -EINVAL;
/* Unregister callback on IRQ enable failure */
- sde_register_irq_callback(phys_enc->sde_kms, wb_enc->irq_idx,
- NULL);
+ sde_core_irq_register_callback(phys_enc->sde_kms,
+ wb_enc->irq_idx, NULL);
return ret;
}
@@ -679,7 +681,7 @@ static int sde_encoder_phys_wb_wait_for_commit_done(
if (!ret) {
MSM_EVT(DEV(phys_enc), wb_enc->frame_count, 0);
- irq_status = sde_read_irq(phys_enc->sde_kms,
+ irq_status = sde_core_irq_read(phys_enc->sde_kms,
wb_enc->irq_idx, true);
if (irq_status) {
SDE_DEBUG("wb:%d done but irq not triggered\n",
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c
index b0bf8dff3190..909d6df38260 100644
--- a/drivers/gpu/drm/msm/sde/sde_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_irq.c
@@ -10,248 +10,14 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <linux/kthread.h>
-#include "msm_drv.h"
-#include "sde_kms.h"
-
-static void sde_irq_callback_handler(void *arg, int irq_idx)
-{
- struct sde_kms *sde_kms = arg;
- struct sde_irq *irq_obj = &sde_kms->irq_obj;
-
- /*
- * Perform registered function callback
- */
- if (irq_obj->irq_cb_tbl && irq_obj->irq_cb_tbl[irq_idx].func)
- irq_obj->irq_cb_tbl[irq_idx].func(
- irq_obj->irq_cb_tbl[irq_idx].arg,
- irq_idx);
-
- /*
- * Clear pending interrupt status in HW.
- * NOTE: sde_irq_callback_handler is protected by top-level
- * spinlock, so it is safe to clear any interrupt status here.
- */
- sde_kms->hw_intr->ops.clear_interrupt_status(
- sde_kms->hw_intr,
- irq_idx);
-}
-
-static void sde_irq_intf_error_handler(void *arg, int irq_idx)
-{
- DRM_ERROR("INTF underrun detected, irq_idx=%d\n", irq_idx);
-}
-
-void sde_set_irqmask(struct sde_kms *sde_kms, uint32_t reg, uint32_t irqmask)
-{
- if (!sde_kms || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.set_mask)
- return;
-
- sde_kms->hw_intr->ops.set_mask(sde_kms->hw_intr, reg, irqmask);
-}
-
-int sde_irq_idx_lookup(struct sde_kms *sde_kms, enum sde_intr_type intr_type,
- u32 instance_idx)
-{
- if (!sde_kms || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.irq_idx_lookup)
- return -EINVAL;
-
- return sde_kms->hw_intr->ops.irq_idx_lookup(intr_type,
- instance_idx);
-}
-
-int sde_enable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
-{
- int i;
- int ret = 0;
-
- if (!sde_kms || !irq_idxs || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.enable_irq)
- return -EINVAL;
-
- for (i = 0; i < irq_count; i++) {
- ret = sde_kms->hw_intr->ops.enable_irq(
- sde_kms->hw_intr,
- irq_idxs[i]);
- if (ret) {
- DRM_ERROR("Fail to enable IRQ for irq_idx:%d\n",
- irq_idxs[i]);
- return ret;
- }
- }
-
- return ret;
-}
-
-int sde_disable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count)
-{
- int i;
- int ret = 0;
-
- if (!sde_kms || !irq_idxs || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.disable_irq)
- return -EINVAL;
-
- for (i = 0; i < irq_count; i++) {
- ret = sde_kms->hw_intr->ops.disable_irq(
- sde_kms->hw_intr,
- irq_idxs[i]);
- if (ret) {
- DRM_ERROR("Fail to disable IRQ for irq_idx:%d\n",
- irq_idxs[i]);
- return ret;
- }
- }
-
- return ret;
-}
-
-u32 sde_read_irq(struct sde_kms *sde_kms, int irq_idx, bool clear)
-{
- if (!sde_kms || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.get_interrupt_status)
- return 0;
-
- return sde_kms->hw_intr->ops.get_interrupt_status(sde_kms->hw_intr,
- irq_idx, clear);
-}
-
-int sde_register_irq_callback(struct sde_kms *sde_kms, int irq_idx,
- struct sde_irq_callback *register_irq_cb)
-{
- struct sde_irq_callback *irq_cb_tbl;
- unsigned long irq_flags;
-
- /*
- * We allow NULL register_irq_cb as input for callback registration
- */
- if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl)
- return -EINVAL;
-
- if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
- DRM_ERROR("invalid IRQ index: [%d]\n", irq_idx);
- return -EINVAL;
- }
-
- irq_cb_tbl = sde_kms->irq_obj.irq_cb_tbl;
- spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
- irq_cb_tbl[irq_idx].func = register_irq_cb ?
- register_irq_cb->func : NULL;
- irq_cb_tbl[irq_idx].arg = register_irq_cb ?
- register_irq_cb->arg : NULL;
- spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
-
- return 0;
-}
-
-void sde_clear_all_irqs(struct sde_kms *sde_kms)
-{
- if (!sde_kms || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.clear_all_irqs)
- return;
-
- sde_kms->hw_intr->ops.clear_all_irqs(sde_kms->hw_intr);
-}
-
-void sde_disable_all_irqs(struct sde_kms *sde_kms)
-{
- if (!sde_kms || !sde_kms->hw_intr ||
- !sde_kms->hw_intr->ops.disable_all_irqs)
- return;
-
- sde_kms->hw_intr->ops.disable_all_irqs(sde_kms->hw_intr);
-}
-
-void sde_irq_preinstall(struct msm_kms *kms)
-{
- struct sde_kms *sde_kms = to_sde_kms(kms);
- struct drm_device *dev = sde_kms->dev;
- struct msm_drm_private *priv = dev->dev_private;
-
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
- sde_clear_all_irqs(sde_kms);
- sde_disable_all_irqs(sde_kms);
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
-
- spin_lock_init(&sde_kms->irq_obj.cb_lock);
-
- /* Create irq callbacks for all possible irq_idx */
- sde_kms->irq_obj.total_irqs = sde_kms->hw_intr->irq_idx_tbl_size;
- sde_kms->irq_obj.irq_cb_tbl = kcalloc(sde_kms->irq_obj.total_irqs,
- sizeof(struct sde_irq_callback), GFP_KERNEL);
- if (!sde_kms->irq_obj.irq_cb_tbl)
- DRM_ERROR("Fail to allocate memory of IRQ callback list\n");
-
-}
-
-int sde_irq_postinstall(struct msm_kms *kms)
-{
- struct sde_kms *sde_kms = to_sde_kms(kms);
- struct drm_device *dev = sde_kms->dev;
- struct msm_drm_private *priv = dev->dev_private;
- struct sde_irq_callback irq_cb;
- int irq_idx;
- int i;
-
- irq_cb.func = sde_irq_intf_error_handler;
- irq_cb.arg = sde_kms;
-
- /* Register interface underrun callback */
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
- for (i = 0; i < sde_kms->catalog->intf_count; i++) {
- irq_idx = sde_irq_idx_lookup(sde_kms,
- SDE_IRQ_TYPE_INTF_UNDER_RUN, i+INTF_0);
- sde_register_irq_callback(sde_kms, irq_idx, &irq_cb);
- sde_enable_irq(sde_kms, &irq_idx, 1);
- }
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
-
- return 0;
-}
-
-void sde_irq_uninstall(struct msm_kms *kms)
-{
- struct sde_kms *sde_kms = to_sde_kms(kms);
- struct drm_device *dev = sde_kms->dev;
- struct msm_drm_private *priv = dev->dev_private;
-
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
- sde_clear_all_irqs(sde_kms);
- sde_disable_all_irqs(sde_kms);
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
-
- kfree(sde_kms->irq_obj.irq_cb_tbl);
-}
-
-static void _sde_irq_mdp_done(struct sde_kms *sde_kms)
-{
- /*
- * Read interrupt status from all sources. Interrupt status are
- * stored within hw_intr.
- * Function will also clear the interrupt status after reading.
- * Individual interrupt status bit will only get stored if it
- * is enabled.
- */
- sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr);
-
- /*
- * Dispatch to HW driver to handle interrupt lookup that is being
- * fired. When matching interrupt is located, HW driver will call to
- * sde_irq_callback_handler with the irq_idx from the lookup table.
- * sde_irq_callback_handler will perform the registered function
- * callback, and do the interrupt status clearing once the registered
- * callback is finished.
- */
- sde_kms->hw_intr->ops.dispatch_irqs(
- sde_kms->hw_intr,
- sde_irq_callback_handler,
- sde_kms);
-}
+#include "sde_irq.h"
+#include "sde_core_irq.h"
irqreturn_t sde_irq(struct msm_kms *kms)
{
@@ -266,7 +32,7 @@ irqreturn_t sde_irq(struct msm_kms *kms)
*/
if (interrupts & IRQ_SOURCE_MDP) {
interrupts &= ~IRQ_SOURCE_MDP;
- _sde_irq_mdp_done(sde_kms);
+ sde_core_irq(sde_kms);
}
/*
@@ -276,38 +42,40 @@ irqreturn_t sde_irq(struct msm_kms *kms)
irq_hw_number_t hwirq = fls(interrupts) - 1;
generic_handle_irq(irq_find_mapping(
- sde_kms->irqcontroller.domain, hwirq));
+ sde_kms->irq_controller.domain, hwirq));
interrupts &= ~(1 << hwirq);
}
return IRQ_HANDLED;
}
-int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
- return sde_crtc_vblank(crtc, true);
-}
-
-void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
- sde_crtc_vblank(crtc, false);
-}
-
static void sde_hw_irq_mask(struct irq_data *irqd)
{
- struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd);
+ struct sde_kms *sde_kms;
+
+ if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
+ SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
+ return;
+ }
+ sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
- clear_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask);
+ clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
static void sde_hw_irq_unmask(struct irq_data *irqd)
{
- struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd);
+ struct sde_kms *sde_kms;
+
+ if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
+ SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
+ return;
+ }
+ sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
- set_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask);
+ set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
@@ -317,22 +85,22 @@ static struct irq_chip sde_hw_irq_chip = {
.irq_unmask = sde_hw_irq_unmask,
};
-static int sde_hw_irqdomain_map(struct irq_domain *d,
+static int sde_hw_irqdomain_map(struct irq_domain *domain,
unsigned int irq, irq_hw_number_t hwirq)
{
- struct sde_kms *sde_kms = d->host_data;
- uint32_t valid_irqs;
-
- sde_kms->hw_intr->ops.get_valid_interrupts(sde_kms->hw_intr,
- &valid_irqs);
+ struct sde_kms *sde_kms;
+ int rc;
- if (!(valid_irqs & (1 << hwirq)))
- return -EPERM;
+ if (!domain || !domain->host_data) {
+ SDE_ERROR("invalid parameters domain %d\n", domain != 0);
+ return -EINVAL;
+ }
+ sde_kms = domain->host_data;
irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, sde_kms);
+ rc = irq_set_chip_data(irq, sde_kms);
- return 0;
+ return rc;
}
static struct irq_domain_ops sde_hw_irqdomain_ops = {
@@ -340,29 +108,59 @@ static struct irq_domain_ops sde_hw_irqdomain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-int sde_irq_domain_init(struct sde_kms *sde_kms)
+void sde_irq_preinstall(struct msm_kms *kms)
{
- struct device *dev = sde_kms->dev->dev;
- struct irq_domain *d;
+ struct sde_kms *sde_kms = to_sde_kms(kms);
+ struct device *dev;
+ struct irq_domain *domain;
- d = irq_domain_add_linear(dev->of_node, 32,
- &sde_hw_irqdomain_ops, sde_kms);
+ if (!sde_kms->dev || !sde_kms->dev->dev) {
+ pr_err("invalid device handles\n");
+ return;
+ }
+ dev = sde_kms->dev->dev;
- if (!d)
- return -ENXIO;
+ domain = irq_domain_add_linear(dev->of_node, 32,
+ &sde_hw_irqdomain_ops, sde_kms);
+ if (!domain) {
+ pr_err("failed to add irq_domain\n");
+ return;
+ }
- sde_kms->irqcontroller.enabled_mask = 0;
- sde_kms->irqcontroller.domain = d;
+ sde_kms->irq_controller.enabled_mask = 0;
+ sde_kms->irq_controller.domain = domain;
- return 0;
+ sde_core_irq_preinstall(sde_kms);
}
-int sde_irq_domain_fini(struct sde_kms *sde_kms)
+int sde_irq_postinstall(struct msm_kms *kms)
{
- if (sde_kms->irqcontroller.domain) {
- irq_domain_remove(sde_kms->irqcontroller.domain);
- sde_kms->irqcontroller.domain = NULL;
+ struct sde_kms *sde_kms = to_sde_kms(kms);
+ int rc;
+
+ if (!kms) {
+ SDE_ERROR("invalid parameters\n");
+ return -EINVAL;
}
- return 0;
+
+ rc = sde_core_irq_postinstall(sde_kms);
+
+ return rc;
}
+void sde_irq_uninstall(struct msm_kms *kms)
+{
+ struct sde_kms *sde_kms = to_sde_kms(kms);
+
+ if (!kms) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+
+ sde_core_irq_uninstall(sde_kms);
+
+ if (sde_kms->irq_controller.domain) {
+ irq_domain_remove(sde_kms->irq_controller.domain);
+ sde_kms->irq_controller.domain = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.h b/drivers/gpu/drm/msm/sde/sde_irq.h
new file mode 100644
index 000000000000..e10900719f3f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_irq.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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 __SDE_IRQ_H__
+#define __SDE_IRQ_H__
+
+#include <linux/kernel.h>
+#include <linux/irqdomain.h>
+
+#include "msm_kms.h"
+
+/**
+ * sde_irq_controller - define MDSS level interrupt controller context
+ * @enabled_mask: enable status of MDSS level interrupt
+ * @domain: interrupt domain of this controller
+ */
+struct sde_irq_controller {
+ unsigned long enabled_mask;
+ struct irq_domain *domain;
+};
+
+/**
+ * sde_irq_preinstall - perform pre-installation of MDSS IRQ handler
+ * @kms: pointer to kms context
+ * @return: none
+ */
+void sde_irq_preinstall(struct msm_kms *kms);
+
+/**
+ * sde_irq_postinstall - perform post-installation of MDSS IRQ handler
+ * @kms: pointer to kms context
+ * @return: 0 if success; error code otherwise
+ */
+int sde_irq_postinstall(struct msm_kms *kms);
+
+/**
+ * sde_irq_uninstall - uninstall MDSS IRQ handler
+ * @drm_dev: pointer to kms context
+ * @return: none
+ */
+void sde_irq_uninstall(struct msm_kms *kms);
+
+/**
+ * sde_irq - MDSS level IRQ handler
+ * @kms: pointer to kms context
+ * @return: interrupt handling status
+ */
+irqreturn_t sde_irq(struct msm_kms *kms);
+
+#endif /* __SDE_IRQ_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index c8fe90ac2c5a..2604000bb25c 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -18,6 +18,7 @@
#include "msm_drv.h"
#include "msm_mmu.h"
#include "sde_kms.h"
+#include "sde_core_irq.h"
#include "sde_formats.h"
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
@@ -134,6 +135,16 @@ static void sde_debugfs_destroy(struct sde_kms *sde_kms)
}
}
+static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+ return sde_crtc_vblank(crtc, true);
+}
+
+static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+ sde_crtc_vblank(crtc, false);
+}
+
static void sde_prepare_commit(struct msm_kms *kms,
struct drm_atomic_state *state)
{
@@ -237,10 +248,6 @@ static int modeset_init(struct sde_kms *sde_kms)
int primary_planes_idx = 0, i, ret, max_crtc_count;
int max_private_planes = catalog->mixer_count;
- ret = sde_irq_domain_init(sde_kms);
- if (ret)
- goto fail;
-
/* Create the planes */
for (i = 0; i < catalog->sspp_count; i++) {
bool primary = true;
@@ -337,7 +344,6 @@ static void sde_destroy(struct msm_kms *kms)
}
sde_debugfs_destroy(sde_kms);
- sde_irq_domain_fini(sde_kms);
sde_hw_intr_destroy(sde_kms->hw_intr);
sde_rm_destroy(&sde_kms->rm);
kfree(sde_kms);
@@ -354,8 +360,8 @@ static const struct msm_kms_funcs kms_funcs = {
.commit = sde_commit,
.complete_commit = sde_complete_commit,
.wait_for_crtc_commit_done = sde_wait_for_commit_done,
- .enable_vblank = sde_enable_vblank,
- .disable_vblank = sde_disable_vblank,
+ .enable_vblank = sde_kms_enable_vblank,
+ .disable_vblank = sde_kms_disable_vblank,
.check_modified_format = sde_format_check_modified_format,
.get_format = sde_get_msm_format,
.round_pixclk = sde_round_pixclk,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index e8a69888e800..46e23986e8fd 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -26,6 +26,7 @@
#include "sde_connector.h"
#include "sde_rm.h"
#include "sde_power_handle.h"
+#include "sde_irq.h"
/**
* SDE_DEBUG - macro for kms/plane/crtc/encoder/connector logs
@@ -131,10 +132,7 @@ struct sde_kms {
struct regulator *mmagic;
struct regulator *venus;
- struct {
- unsigned long enabled_mask;
- struct irq_domain *domain;
- } irqcontroller;
+ struct sde_irq_controller irq_controller;
struct sde_hw_intr *hw_intr;
struct sde_irq irq_obj;
@@ -404,104 +402,6 @@ void sde_kms_info_append_format(struct sde_kms_info *info,
void sde_kms_info_stop(struct sde_kms_info *info);
/**
- * IRQ functions
- */
-int sde_irq_domain_init(struct sde_kms *sde_kms);
-int sde_irq_domain_fini(struct sde_kms *sde_kms);
-void sde_irq_preinstall(struct msm_kms *kms);
-int sde_irq_postinstall(struct msm_kms *kms);
-void sde_irq_uninstall(struct msm_kms *kms);
-irqreturn_t sde_irq(struct msm_kms *kms);
-
-/**
- * sde_set_irqmask - IRQ helper function for writing IRQ mask
- * to SDE HW interrupt register.
- * @sde_kms: SDE handle
- * @reg_off: SDE HW interrupt register offset
- * @irqmask: IRQ mask
- */
-void sde_set_irqmask(
- struct sde_kms *sde_kms,
- uint32_t reg_off,
- uint32_t irqmask);
-
-/**
- * sde_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW
- * interrupt mapping table.
- * @sde_kms: SDE handle
- * @intr_type: SDE HW interrupt type for lookup
- * @instance_idx: SDE HW block instance defined in sde_hw_mdss.h
- * @return: irq_idx or -EINVAL when fail to lookup
- */
-int sde_irq_idx_lookup(
- struct sde_kms *sde_kms,
- enum sde_intr_type intr_type,
- uint32_t instance_idx);
-
-/**
- * sde_enable_irq - IRQ helper function for enabling one or more IRQs
- * @sde_kms: SDE handle
- * @irq_idxs: Array of irq index
- * @irq_count: Number of irq_idx provided in the array
- * @return: 0 for success enabling IRQ, otherwise failure
- */
-int sde_enable_irq(
- struct sde_kms *sde_kms,
- int *irq_idxs,
- uint32_t irq_count);
-
-/**
- * sde_disable_irq - IRQ helper function for diabling one of more IRQs
- * @sde_kms: SDE handle
- * @irq_idxs: Array of irq index
- * @irq_count: Number of irq_idx provided in the array
- * @return: 0 for success disabling IRQ, otherwise failure
- */
-int sde_disable_irq(
- struct sde_kms *sde_kms,
- int *irq_idxs,
- uint32_t irq_count);
-
-/**
- * sde_read_irq - IRQ helper function for reading IRQ status
- * @sde_kms: SDE handle
- * @irq_idx: irq index
- * @clear: True to clear the irq after read
- * @return: non-zero if irq detected; otherwise no irq detected
- */
-u32 sde_read_irq(
- struct sde_kms *sde_kms,
- int irq_idx,
- bool clear);
-
-/**
- * sde_register_irq_callback - For registering callback function on IRQ
- * interrupt
- * @sde_kms: SDE handle
- * @irq_idx: irq index
- * @irq_cb: IRQ callback structure, containing callback function
- * and argument. Passing NULL for irq_cb will unregister
- * the callback for the given irq_idx
- * @return: 0 for success registering callback, otherwise failure
- */
-int sde_register_irq_callback(
- struct sde_kms *sde_kms,
- int irq_idx,
- struct sde_irq_callback *irq_cb);
-
-/**
- * sde_clear_all_irqs - Clearing all SDE IRQ interrupt status
- * @sde_kms: SDE handle
- */
-void sde_clear_all_irqs(struct sde_kms *sde_kms);
-
-/**
- * sde_disable_all_irqs - Diabling all SDE IRQ interrupt
- * @sde_kms: SDE handle
- */
-void sde_disable_all_irqs(struct sde_kms *sde_kms);
-
-/**
* Vblank enable/disable functions
*/
int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);