summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c')
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c507
1 files changed, 323 insertions, 184 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index 53326f25e40e..49bd77a755aa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -6,6 +6,8 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
+#include <drm/drm_managed.h>
+
#include "dpu_core_irq.h"
#include "dpu_kms.h"
#include "dpu_hw_interrupts.h"
@@ -15,29 +17,28 @@
/*
* Register offsets in MDSS register file for the interrupt registers
- * w.r.t. to the MDP base
+ * w.r.t. the MDP base
*/
-#define MDP_SSPP_TOP0_OFF 0x0
-#define MDP_INTF_0_OFF 0x6A000
-#define MDP_INTF_1_OFF 0x6A800
-#define MDP_INTF_2_OFF 0x6B000
-#define MDP_INTF_3_OFF 0x6B800
-#define MDP_INTF_4_OFF 0x6C000
-#define MDP_INTF_5_OFF 0x6C800
-#define MDP_AD4_0_OFF 0x7C000
-#define MDP_AD4_1_OFF 0x7D000
-#define MDP_AD4_INTR_EN_OFF 0x41c
-#define MDP_AD4_INTR_CLEAR_OFF 0x424
-#define MDP_AD4_INTR_STATUS_OFF 0x420
-#define MDP_INTF_0_OFF_REV_7xxx 0x34000
-#define MDP_INTF_1_OFF_REV_7xxx 0x35000
-#define MDP_INTF_2_OFF_REV_7xxx 0x36000
-#define MDP_INTF_3_OFF_REV_7xxx 0x37000
-#define MDP_INTF_4_OFF_REV_7xxx 0x38000
-#define MDP_INTF_5_OFF_REV_7xxx 0x39000
-#define MDP_INTF_6_OFF_REV_7xxx 0x3a000
-#define MDP_INTF_7_OFF_REV_7xxx 0x3b000
-#define MDP_INTF_8_OFF_REV_7xxx 0x3c000
+#define MDP_INTF_OFF(intf) (0x6A000 + 0x800 * (intf))
+#define MDP_INTF_INTR_EN(intf) (MDP_INTF_OFF(intf) + 0x1c0)
+#define MDP_INTF_INTR_STATUS(intf) (MDP_INTF_OFF(intf) + 0x1c4)
+#define MDP_INTF_INTR_CLEAR(intf) (MDP_INTF_OFF(intf) + 0x1c8)
+#define MDP_INTF_TEAR_OFF(intf) (0x6D700 + 0x100 * (intf))
+#define MDP_INTF_INTR_TEAR_EN(intf) (MDP_INTF_TEAR_OFF(intf) + 0x000)
+#define MDP_INTF_INTR_TEAR_STATUS(intf) (MDP_INTF_TEAR_OFF(intf) + 0x004)
+#define MDP_INTF_INTR_TEAR_CLEAR(intf) (MDP_INTF_TEAR_OFF(intf) + 0x008)
+#define MDP_AD4_OFF(ad4) (0x7C000 + 0x1000 * (ad4))
+#define MDP_AD4_INTR_EN_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x41c)
+#define MDP_AD4_INTR_CLEAR_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x424)
+#define MDP_AD4_INTR_STATUS_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x420)
+#define MDP_INTF_REV_7xxx_OFF(intf) (0x34000 + 0x1000 * (intf))
+#define MDP_INTF_REV_7xxx_INTR_EN(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c0)
+#define MDP_INTF_REV_7xxx_INTR_STATUS(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c4)
+#define MDP_INTF_REV_7xxx_INTR_CLEAR(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c8)
+#define MDP_INTF_REV_7xxx_TEAR_OFF(intf) (0x34800 + 0x1000 * (intf))
+#define MDP_INTF_REV_7xxx_INTR_TEAR_EN(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x000)
+#define MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x004)
+#define MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x008)
/**
* struct dpu_intr_reg - array of DPU register sets
@@ -52,142 +53,201 @@ struct dpu_intr_reg {
};
/*
- * struct dpu_intr_reg - List of DPU interrupt registers
- *
- * When making changes be sure to sync with dpu_hw_intr_reg
+ * dpu_intr_set_legacy - List of DPU interrupt registers for DPU <= 6.x
*/
-static const struct dpu_intr_reg dpu_intr_set[] = {
+static const struct dpu_intr_reg dpu_intr_set_legacy[] = {
[MDP_SSPP_TOP0_INTR] = {
- MDP_SSPP_TOP0_OFF+INTR_CLEAR,
- MDP_SSPP_TOP0_OFF+INTR_EN,
- MDP_SSPP_TOP0_OFF+INTR_STATUS
+ INTR_CLEAR,
+ INTR_EN,
+ INTR_STATUS
},
[MDP_SSPP_TOP0_INTR2] = {
- MDP_SSPP_TOP0_OFF+INTR2_CLEAR,
- MDP_SSPP_TOP0_OFF+INTR2_EN,
- MDP_SSPP_TOP0_OFF+INTR2_STATUS
+ INTR2_CLEAR,
+ INTR2_EN,
+ INTR2_STATUS
},
[MDP_SSPP_TOP0_HIST_INTR] = {
- MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR,
- MDP_SSPP_TOP0_OFF+HIST_INTR_EN,
- MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS
+ HIST_INTR_CLEAR,
+ HIST_INTR_EN,
+ HIST_INTR_STATUS
},
[MDP_INTF0_INTR] = {
- MDP_INTF_0_OFF+INTF_INTR_CLEAR,
- MDP_INTF_0_OFF+INTF_INTR_EN,
- MDP_INTF_0_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(0),
+ MDP_INTF_INTR_EN(0),
+ MDP_INTF_INTR_STATUS(0)
},
[MDP_INTF1_INTR] = {
- MDP_INTF_1_OFF+INTF_INTR_CLEAR,
- MDP_INTF_1_OFF+INTF_INTR_EN,
- MDP_INTF_1_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(1),
+ MDP_INTF_INTR_EN(1),
+ MDP_INTF_INTR_STATUS(1)
},
[MDP_INTF2_INTR] = {
- MDP_INTF_2_OFF+INTF_INTR_CLEAR,
- MDP_INTF_2_OFF+INTF_INTR_EN,
- MDP_INTF_2_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(2),
+ MDP_INTF_INTR_EN(2),
+ MDP_INTF_INTR_STATUS(2)
},
[MDP_INTF3_INTR] = {
- MDP_INTF_3_OFF+INTF_INTR_CLEAR,
- MDP_INTF_3_OFF+INTF_INTR_EN,
- MDP_INTF_3_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(3),
+ MDP_INTF_INTR_EN(3),
+ MDP_INTF_INTR_STATUS(3)
},
[MDP_INTF4_INTR] = {
- MDP_INTF_4_OFF+INTF_INTR_CLEAR,
- MDP_INTF_4_OFF+INTF_INTR_EN,
- MDP_INTF_4_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(4),
+ MDP_INTF_INTR_EN(4),
+ MDP_INTF_INTR_STATUS(4)
},
[MDP_INTF5_INTR] = {
- MDP_INTF_5_OFF+INTF_INTR_CLEAR,
- MDP_INTF_5_OFF+INTF_INTR_EN,
- MDP_INTF_5_OFF+INTF_INTR_STATUS
+ MDP_INTF_INTR_CLEAR(5),
+ MDP_INTF_INTR_EN(5),
+ MDP_INTF_INTR_STATUS(5)
+ },
+ [MDP_INTF1_TEAR_INTR] = {
+ MDP_INTF_INTR_TEAR_CLEAR(1),
+ MDP_INTF_INTR_TEAR_EN(1),
+ MDP_INTF_INTR_TEAR_STATUS(1)
+ },
+ [MDP_INTF2_TEAR_INTR] = {
+ MDP_INTF_INTR_TEAR_CLEAR(2),
+ MDP_INTF_INTR_TEAR_EN(2),
+ MDP_INTF_INTR_TEAR_STATUS(2)
},
[MDP_AD4_0_INTR] = {
- MDP_AD4_0_OFF + MDP_AD4_INTR_CLEAR_OFF,
- MDP_AD4_0_OFF + MDP_AD4_INTR_EN_OFF,
- MDP_AD4_0_OFF + MDP_AD4_INTR_STATUS_OFF,
+ MDP_AD4_INTR_CLEAR_OFF(0),
+ MDP_AD4_INTR_EN_OFF(0),
+ MDP_AD4_INTR_STATUS_OFF(0),
},
[MDP_AD4_1_INTR] = {
- MDP_AD4_1_OFF + MDP_AD4_INTR_CLEAR_OFF,
- MDP_AD4_1_OFF + MDP_AD4_INTR_EN_OFF,
- MDP_AD4_1_OFF + MDP_AD4_INTR_STATUS_OFF,
+ MDP_AD4_INTR_CLEAR_OFF(1),
+ MDP_AD4_INTR_EN_OFF(1),
+ MDP_AD4_INTR_STATUS_OFF(1),
+ },
+};
+
+/*
+ * dpu_intr_set_7xxx - List of DPU interrupt registers for DPU >= 7.0
+ */
+static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {
+ [MDP_SSPP_TOP0_INTR] = {
+ INTR_CLEAR,
+ INTR_EN,
+ INTR_STATUS
+ },
+ [MDP_SSPP_TOP0_INTR2] = {
+ INTR2_CLEAR,
+ INTR2_EN,
+ INTR2_STATUS
+ },
+ [MDP_SSPP_TOP0_HIST_INTR] = {
+ HIST_INTR_CLEAR,
+ HIST_INTR_EN,
+ HIST_INTR_STATUS
+ },
+ [MDP_INTF0_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(0),
+ MDP_INTF_REV_7xxx_INTR_EN(0),
+ MDP_INTF_REV_7xxx_INTR_STATUS(0)
+ },
+ [MDP_INTF1_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(1),
+ MDP_INTF_REV_7xxx_INTR_EN(1),
+ MDP_INTF_REV_7xxx_INTR_STATUS(1)
},
- [MDP_INTF0_7xxx_INTR] = {
- MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF1_TEAR_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(1),
+ MDP_INTF_REV_7xxx_INTR_TEAR_EN(1),
+ MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(1)
},
- [MDP_INTF1_7xxx_INTR] = {
- MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF2_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(2),
+ MDP_INTF_REV_7xxx_INTR_EN(2),
+ MDP_INTF_REV_7xxx_INTR_STATUS(2)
},
- [MDP_INTF2_7xxx_INTR] = {
- MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF2_TEAR_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(2),
+ MDP_INTF_REV_7xxx_INTR_TEAR_EN(2),
+ MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(2)
},
- [MDP_INTF3_7xxx_INTR] = {
- MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF3_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(3),
+ MDP_INTF_REV_7xxx_INTR_EN(3),
+ MDP_INTF_REV_7xxx_INTR_STATUS(3)
},
- [MDP_INTF4_7xxx_INTR] = {
- MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF4_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(4),
+ MDP_INTF_REV_7xxx_INTR_EN(4),
+ MDP_INTF_REV_7xxx_INTR_STATUS(4)
},
- [MDP_INTF5_7xxx_INTR] = {
- MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF5_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(5),
+ MDP_INTF_REV_7xxx_INTR_EN(5),
+ MDP_INTF_REV_7xxx_INTR_STATUS(5)
},
- [MDP_INTF6_7xxx_INTR] = {
- MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF6_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(6),
+ MDP_INTF_REV_7xxx_INTR_EN(6),
+ MDP_INTF_REV_7xxx_INTR_STATUS(6)
},
- [MDP_INTF7_7xxx_INTR] = {
- MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF7_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(7),
+ MDP_INTF_REV_7xxx_INTR_EN(7),
+ MDP_INTF_REV_7xxx_INTR_STATUS(7)
},
- [MDP_INTF8_7xxx_INTR] = {
- MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_CLEAR,
- MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_EN,
- MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_STATUS
+ [MDP_INTF8_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(8),
+ MDP_INTF_REV_7xxx_INTR_EN(8),
+ MDP_INTF_REV_7xxx_INTR_STATUS(8)
},
};
-#define DPU_IRQ_REG(irq_idx) (irq_idx / 32)
-#define DPU_IRQ_MASK(irq_idx) (BIT(irq_idx % 32))
+#define DPU_IRQ_MASK(irq_idx) (BIT(DPU_IRQ_BIT(irq_idx)))
+
+static inline bool dpu_core_irq_is_valid(unsigned int irq_idx)
+{
+ return irq_idx && irq_idx <= DPU_NUM_IRQS;
+}
+
+static inline struct dpu_hw_intr_entry *dpu_core_irq_get_entry(struct dpu_hw_intr *intr,
+ unsigned int irq_idx)
+{
+ return &intr->irq_tbl[irq_idx - 1];
+}
/**
* dpu_core_irq_callback_handler - dispatch core interrupts
* @dpu_kms: Pointer to DPU's KMS structure
* @irq_idx: interrupt index
*/
-static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx)
+static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, unsigned int irq_idx)
{
- VERB("irq_idx=%d\n", irq_idx);
+ struct dpu_hw_intr_entry *irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);
- if (!dpu_kms->hw_intr->irq_tbl[irq_idx].cb)
- DRM_ERROR("no registered cb, idx:%d\n", irq_idx);
+ VERB("IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
+
+ if (!irq_entry->cb) {
+ DRM_ERROR("no registered cb, IRQ=[%d, %d]\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
+ return;
+ }
- atomic_inc(&dpu_kms->hw_intr->irq_tbl[irq_idx].count);
+ atomic_inc(&irq_entry->count);
/*
* Perform registered function callback
*/
- dpu_kms->hw_intr->irq_tbl[irq_idx].cb(dpu_kms->hw_intr->irq_tbl[irq_idx].arg, irq_idx);
+ irq_entry->cb(irq_entry->arg);
}
+/**
+ * dpu_core_irq - core IRQ handler
+ * @kms: MSM KMS handle
+ * @return: interrupt handling status
+ */
irqreturn_t dpu_core_irq(struct msm_kms *kms)
{
struct dpu_kms *dpu_kms = to_dpu_kms(kms);
struct dpu_hw_intr *intr = dpu_kms->hw_intr;
int reg_idx;
- int irq_idx;
+ unsigned int irq_idx;
u32 irq_status;
u32 enable_mask;
int bit;
@@ -197,19 +257,19 @@ irqreturn_t dpu_core_irq(struct msm_kms *kms)
return IRQ_NONE;
spin_lock_irqsave(&intr->irq_lock, irq_flags);
- for (reg_idx = 0; reg_idx < ARRAY_SIZE(dpu_intr_set); reg_idx++) {
+ for (reg_idx = 0; reg_idx < MDP_INTR_MAX; reg_idx++) {
if (!test_bit(reg_idx, &intr->irq_mask))
continue;
/* Read interrupt status */
- irq_status = DPU_REG_READ(&intr->hw, dpu_intr_set[reg_idx].status_off);
+ irq_status = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].status_off);
/* Read enable mask */
- enable_mask = DPU_REG_READ(&intr->hw, dpu_intr_set[reg_idx].en_off);
+ enable_mask = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].en_off);
/* and clear the interrupt */
if (irq_status)
- DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off,
+ DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,
irq_status);
/* Finally update IRQ status based on enable mask */
@@ -243,7 +303,8 @@ irqreturn_t dpu_core_irq(struct msm_kms *kms)
return IRQ_HANDLED;
}
-static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
+static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr,
+ unsigned int irq_idx)
{
int reg_idx;
const struct dpu_intr_reg *reg;
@@ -253,8 +314,9 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
if (!intr)
return -EINVAL;
- if (irq_idx < 0 || irq_idx >= intr->total_irqs) {
- pr_err("invalid IRQ index: [%d]\n", irq_idx);
+ if (!dpu_core_irq_is_valid(irq_idx)) {
+ pr_err("invalid IRQ=[%d, %d]\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return -EINVAL;
}
@@ -266,7 +328,11 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
assert_spin_locked(&intr->irq_lock);
reg_idx = DPU_IRQ_REG(irq_idx);
- reg = &dpu_intr_set[reg_idx];
+ reg = &intr->intr_set[reg_idx];
+
+ /* Is this interrupt register supported on the platform */
+ if (WARN_ON(!reg->en_off))
+ return -EINVAL;
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) {
@@ -286,13 +352,15 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr,
+ pr_debug("DPU IRQ=[%d, %d] %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,
DPU_IRQ_MASK(irq_idx), cache_irq_mask);
return 0;
}
-static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
+static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr,
+ unsigned int irq_idx)
{
int reg_idx;
const struct dpu_intr_reg *reg;
@@ -302,8 +370,9 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
if (!intr)
return -EINVAL;
- if (irq_idx < 0 || irq_idx >= intr->total_irqs) {
- pr_err("invalid IRQ index: [%d]\n", irq_idx);
+ if (!dpu_core_irq_is_valid(irq_idx)) {
+ pr_err("invalid IRQ=[%d, %d]\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return -EINVAL;
}
@@ -315,7 +384,7 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
assert_spin_locked(&intr->irq_lock);
reg_idx = DPU_IRQ_REG(irq_idx);
- reg = &dpu_intr_set[reg_idx];
+ reg = &intr->intr_set[reg_idx];
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) {
@@ -335,7 +404,8 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr,
+ pr_debug("DPU IRQ=[%d, %d] %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,
DPU_IRQ_MASK(irq_idx), cache_irq_mask);
return 0;
@@ -349,10 +419,10 @@ static void dpu_clear_irqs(struct dpu_kms *dpu_kms)
if (!intr)
return;
- for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) {
+ for (i = 0; i < MDP_INTR_MAX; i++) {
if (test_bit(i, &intr->irq_mask))
DPU_REG_WRITE(&intr->hw,
- dpu_intr_set[i].clr_off, 0xffffffff);
+ intr->intr_set[i].clr_off, 0xffffffff);
}
/* ensure register writes go through */
@@ -367,17 +437,24 @@ static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms)
if (!intr)
return;
- for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) {
+ for (i = 0; i < MDP_INTR_MAX; i++) {
if (test_bit(i, &intr->irq_mask))
DPU_REG_WRITE(&intr->hw,
- dpu_intr_set[i].en_off, 0x00000000);
+ intr->intr_set[i].en_off, 0x00000000);
}
/* ensure register writes go through */
wmb();
}
-u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx)
+/**
+ * dpu_core_irq_read - IRQ helper function for reading IRQ status
+ * @dpu_kms: DPU handle
+ * @irq_idx: irq index
+ * @return: non-zero if irq detected; otherwise no irq detected
+ */
+u32 dpu_core_irq_read(struct dpu_kms *dpu_kms,
+ unsigned int irq_idx)
{
struct dpu_hw_intr *intr = dpu_kms->hw_intr;
int reg_idx;
@@ -387,14 +464,8 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx)
if (!intr)
return 0;
- if (irq_idx < 0) {
- DPU_ERROR("[%pS] invalid irq_idx=%d\n",
- __builtin_return_address(0), irq_idx);
- return 0;
- }
-
- if (irq_idx < 0 || irq_idx >= intr->total_irqs) {
- pr_err("invalid IRQ index: [%d]\n", irq_idx);
+ if (!dpu_core_irq_is_valid(irq_idx)) {
+ pr_err("invalid IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return 0;
}
@@ -402,10 +473,10 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx)
reg_idx = DPU_IRQ_REG(irq_idx);
intr_status = DPU_REG_READ(&intr->hw,
- dpu_intr_set[reg_idx].status_off) &
+ intr->intr_set[reg_idx].status_off) &
DPU_IRQ_MASK(irq_idx);
if (intr_status)
- DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off,
+ DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,
intr_status);
/* ensure register writes go through */
@@ -416,111 +487,154 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx)
return intr_status;
}
-static void __intr_offset(const struct dpu_mdss_cfg *m,
- void __iomem *addr, struct dpu_hw_blk_reg_map *hw)
-{
- hw->blk_addr = addr + m->mdp[0].base;
-}
-
-struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
- const struct dpu_mdss_cfg *m)
+/**
+ * dpu_hw_intr_init(): Initializes the interrupts hw object
+ * @dev: Corresponding device for devres management
+ * @addr: mapped register io address of MDP
+ * @m: pointer to MDSS catalog data
+ */
+struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev,
+ void __iomem *addr,
+ const struct dpu_mdss_cfg *m)
{
struct dpu_hw_intr *intr;
- int nirq = MDP_INTR_MAX * 32;
+ unsigned int i;
if (!addr || !m)
return ERR_PTR(-EINVAL);
- intr = kzalloc(struct_size(intr, irq_tbl, nirq), GFP_KERNEL);
+ intr = drmm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);
if (!intr)
return ERR_PTR(-ENOMEM);
- __intr_offset(m, addr, &intr->hw);
+ if (m->mdss_ver->core_major_ver >= 7)
+ intr->intr_set = dpu_intr_set_7xxx;
+ else
+ intr->intr_set = dpu_intr_set_legacy;
+
+ intr->hw.blk_addr = addr + m->mdp[0].base;
+
+ intr->irq_mask = BIT(MDP_SSPP_TOP0_INTR) |
+ BIT(MDP_SSPP_TOP0_INTR2) |
+ BIT(MDP_SSPP_TOP0_HIST_INTR);
+ for (i = 0; i < m->intf_count; i++) {
+ const struct dpu_intf_cfg *intf = &m->intf[i];
- intr->total_irqs = nirq;
+ if (intf->type == INTF_NONE)
+ continue;
+
+ intr->irq_mask |= BIT(MDP_INTFn_INTR(intf->id));
- intr->irq_mask = m->mdss_irqs;
+ if (intf->intr_tear_rd_ptr)
+ intr->irq_mask |= BIT(DPU_IRQ_REG(intf->intr_tear_rd_ptr));
+ }
spin_lock_init(&intr->irq_lock);
return intr;
}
-void dpu_hw_intr_destroy(struct dpu_hw_intr *intr)
-{
- kfree(intr);
-}
-
-int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx,
- void (*irq_cb)(void *arg, int irq_idx),
- void *irq_arg)
+/**
+ * dpu_core_irq_register_callback - For registering callback function on IRQ
+ * interrupt
+ * @dpu_kms: DPU handle
+ * @irq_idx: irq index
+ * @irq_cb: IRQ callback function.
+ * @irq_arg: IRQ callback argument.
+ * @return: 0 for success registering callback, otherwise failure
+ *
+ * This function supports registration of multiple callbacks for each interrupt.
+ */
+int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms,
+ unsigned int irq_idx,
+ void (*irq_cb)(void *arg),
+ void *irq_arg)
{
+ struct dpu_hw_intr_entry *irq_entry;
unsigned long irq_flags;
int ret;
if (!irq_cb) {
- DPU_ERROR("invalid ird_idx:%d irq_cb:%ps\n", irq_idx, irq_cb);
+ DPU_ERROR("IRQ=[%d, %d] NULL callback\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return -EINVAL;
}
- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) {
- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
+ if (!dpu_core_irq_is_valid(irq_idx)) {
+ DPU_ERROR("invalid IRQ=[%d, %d] irq_cb:%ps\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);
return -EINVAL;
}
- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
+ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
- if (unlikely(WARN_ON(dpu_kms->hw_intr->irq_tbl[irq_idx].cb))) {
+ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);
+ if (unlikely(WARN_ON(irq_entry->cb))) {
spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
return -EBUSY;
}
- trace_dpu_core_irq_register_callback(irq_idx, irq_cb);
- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = irq_arg;
- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = irq_cb;
+ trace_dpu_core_irq_register_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);
+ irq_entry->arg = irq_arg;
+ irq_entry->cb = irq_cb;
ret = dpu_hw_intr_enable_irq_locked(
dpu_kms->hw_intr,
irq_idx);
if (ret)
- DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n",
- irq_idx);
+ DPU_ERROR("Failed/ to enable IRQ=[%d, %d]\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
- trace_dpu_irq_register_success(irq_idx);
+ trace_dpu_irq_register_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return 0;
}
-int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx)
+/**
+ * dpu_core_irq_unregister_callback - For unregistering callback function on IRQ
+ * interrupt
+ * @dpu_kms: DPU handle
+ * @irq_idx: irq index
+ * @return: 0 for success registering callback, otherwise failure
+ *
+ * This function supports registration of multiple callbacks for each interrupt.
+ */
+int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms,
+ unsigned int irq_idx)
{
+ struct dpu_hw_intr_entry *irq_entry;
unsigned long irq_flags;
int ret;
- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) {
- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx);
+ if (!dpu_core_irq_is_valid(irq_idx)) {
+ DPU_ERROR("invalid IRQ=[%d, %d]\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return -EINVAL;
}
- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
+ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
- trace_dpu_core_irq_unregister_callback(irq_idx);
+ trace_dpu_core_irq_unregister_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx);
if (ret)
- DPU_ERROR("Fail to disable IRQ for irq_idx:%d: %d\n",
- irq_idx, ret);
+ DPU_ERROR("Failed to disable IRQ=[%d, %d]: %d\n",
+ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), ret);
- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = NULL;
- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = NULL;
+ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);
+ irq_entry->cb = NULL;
+ irq_entry->arg = NULL;
spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
- trace_dpu_irq_unregister_success(irq_idx);
+ trace_dpu_irq_unregister_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
return 0;
}
@@ -529,18 +643,21 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx)
static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
{
struct dpu_kms *dpu_kms = s->private;
+ struct dpu_hw_intr_entry *irq_entry;
unsigned long irq_flags;
int i, irq_count;
void *cb;
- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) {
+ for (i = 1; i <= DPU_NUM_IRQS; i++) {
spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
- irq_count = atomic_read(&dpu_kms->hw_intr->irq_tbl[i].count);
- cb = dpu_kms->hw_intr->irq_tbl[i].cb;
+ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
+ irq_count = atomic_read(&irq_entry->count);
+ cb = irq_entry->cb;
spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
if (irq_count || cb)
- seq_printf(s, "idx:%d irq:%d cb:%ps\n", i, irq_count, cb);
+ seq_printf(s, "IRQ=[%d, %d] count:%d cb:%ps\n",
+ DPU_IRQ_REG(i), DPU_IRQ_BIT(i), irq_count, cb);
}
return 0;
@@ -548,6 +665,11 @@ static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq);
+/**
+ * dpu_debugfs_core_irq_init - register core irq debugfs
+ * @dpu_kms: pointer to kms
+ * @parent: debugfs directory root
+ */
void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
struct dentry *parent)
{
@@ -556,9 +678,15 @@ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
}
#endif
+/**
+ * dpu_core_irq_preinstall - perform pre-installation of core IRQ handler
+ * @kms: MSM KMS handle
+ * @return: none
+ */
void dpu_core_irq_preinstall(struct msm_kms *kms)
{
struct dpu_kms *dpu_kms = to_dpu_kms(kms);
+ struct dpu_hw_intr_entry *irq_entry;
int i;
pm_runtime_get_sync(&dpu_kms->pdev->dev);
@@ -566,22 +694,33 @@ void dpu_core_irq_preinstall(struct msm_kms *kms)
dpu_disable_all_irqs(dpu_kms);
pm_runtime_put_sync(&dpu_kms->pdev->dev);
- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++)
- atomic_set(&dpu_kms->hw_intr->irq_tbl[i].count, 0);
+ for (i = 1; i <= DPU_NUM_IRQS; i++) {
+ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
+ atomic_set(&irq_entry->count, 0);
+ }
}
+/**
+ * dpu_core_irq_uninstall - uninstall core IRQ handler
+ * @kms: MSM KMS handle
+ * @return: none
+ */
void dpu_core_irq_uninstall(struct msm_kms *kms)
{
struct dpu_kms *dpu_kms = to_dpu_kms(kms);
+ struct dpu_hw_intr_entry *irq_entry;
int i;
if (!dpu_kms->hw_intr)
return;
pm_runtime_get_sync(&dpu_kms->pdev->dev);
- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++)
- if (dpu_kms->hw_intr->irq_tbl[i].cb)
- DPU_ERROR("irq_idx=%d still enabled/registered\n", i);
+ for (i = 1; i <= DPU_NUM_IRQS; i++) {
+ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
+ if (irq_entry->cb)
+ DPU_ERROR("IRQ=[%d, %d] still enabled/registered\n",
+ DPU_IRQ_REG(i), DPU_IRQ_BIT(i));
+ }
dpu_clear_irqs(dpu_kms);
dpu_disable_all_irqs(dpu_kms);