SoCs containing dpu have a MDSS top level wrapper
which includes sub-blocks as dpu, dsi, phy, dp etc.
MDSS top level wrapper manages common resources like
common clocks, power and irq for its sub-blocks.

Currently, in dpu driver, all the power resource
management is part of power_handle which manages
these resources via a custom implementation. And
the resource relationships are not modelled properly
in dt.  Moreover the irq domain handling code is part
of dpu device (which is a child device) due to lack
of a dedicated driver for MDSS top level wrapper
device.

This change adds dpu_mdss top level driver to handle
common clock like - core clock, ahb clock
(for register access), main power supply (i.e. gdsc)
and irq management.
The top level mdss device/driver acts as an interrupt
controller and manage hwirq mapping for its child
devices.

It implements runtime_pm support for resource management.
Child nodes can control these resources via runtime_pm
get/put calls on their corresponding devices due to parent
child relationship defined in dt.

Changes in v3:
        - use "clock-frequency" dt-binding instead of "clock-rate",
          is it an optional binding (Sean Paul)
        - remove handling of "clock-max-rate" proprietary
          dt-binding (Sean Paul)
        - remove intermediate storing of msm_ioremap() retcode
          on failure instead return retcode directly (Sean Paul)
        - msm_ioremap() prints error log in case of failure,
          so remove additional log from it's caller
        - updated max core clock rate
        - dropped (Reviewed-by: Jordan Crouse) due to above changes

Changes in v2:
        - merge _dpu_mdss_hw_rev_init to dpu_mdss_init (Sean Paul)
        - merge _dpu_mdss_get_intr_sources to dpu_mdss_irq (Sean Paul)
        - fix indentation for irq_find_mapping call (Sean Paul)
        - remove unnecessary goto statements from dpu_mdss_irq (Sean Paul)
        - remove redundant param checks from
          dpu_mdss_irq_mask/unmask (Sean Paul/Jordan Crouse)
        - remove redundant param checks from
          dpu_mdss_irqdomain_map (Sean Paul/Jordan Crouse)
        - return error code from dpu_mdss_enable/disable (Sean Paul/Jordan 
Crouse)
        - remove redundant param check from dpu_mdss_destroy (Sean Paul)
        - remove explicit calls to devm_kfree (Sean Paul/Jordan Crouse)
        - remove compatibility check from dpu_mdss_init as
          it is conditionally called from msm_drv (Sean Paul)
        - reworked msm_dss_parse_clock() to add return checks for
          of_property_read_* calls, fix log message and
          fix alignment issues (Sean Paul/Jordan Crouse)
        - remove extra line before dpu_mdss_init (Sean Paul)
        - remove redundant param checks from __intr_offset and
          make it a void function to avoid unnecessary error
          handling from caller (Jordan Crouse)
        - remove redundant param check from dpu_mdss_irq (Jordan Crouse)
        - change mdss address space log message to debug and use %pK for
          kernel pointers (Jordan Crouse)
        - remove unnecessary log message from msm_dss_parse_clock (Jordan 
Crouse)
        - don't export msm_dss_parse_clock since it is used
          only by dpu driver (Jordan Crouse)

Signed-off-by: Rajesh Yadav <rya...@codeaurora.org>
---
 drivers/gpu/drm/msm/Makefile                      |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c      |  97 ---------
 drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h      |  14 --
 drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h     |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c    |   9 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h    |   7 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c |  28 +--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h |  11 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c           |  48 +----
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c           |   6 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h           |   2 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c          | 251 ++++++++++++++++++++++
 drivers/gpu/drm/msm/dpu_io_util.c                 |  49 +++++
 drivers/gpu/drm/msm/msm_drv.c                     |  26 ++-
 drivers/gpu/drm/msm/msm_drv.h                     |   2 +-
 drivers/gpu/drm/msm/msm_kms.h                     |   1 +
 include/linux/dpu_io_util.h                       |   2 +
 17 files changed, 329 insertions(+), 227 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d7558ed..d9826c1 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -81,6 +81,7 @@ msm-y := \
        disp/dpu1/dpu_reg_dma.o \
        disp/dpu1/dpu_rm.o \
        disp/dpu1/dpu_vbif.o \
+       disp/dpu1/dpu_mdss.o \
        dpu_dbg.o \
        dpu_io_util.o \
        dpu_dbg_evtlog.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
index fe33013..977adc4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
@@ -515,103 +515,6 @@ void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms)
        dpu_kms->irq_obj.total_irqs = 0;
 }
 
-static void dpu_core_irq_mask(struct irq_data *irqd)
-{
-       struct dpu_kms *dpu_kms;
-
-       if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
-               DPU_ERROR("invalid parameters irqd %d\n", irqd != NULL);
-               return;
-       }
-       dpu_kms = irq_data_get_irq_chip_data(irqd);
-
-       /* memory barrier */
-       smp_mb__before_atomic();
-       clear_bit(irqd->hwirq, &dpu_kms->irq_controller.enabled_mask);
-       /* memory barrier */
-       smp_mb__after_atomic();
-}
-
-static void dpu_core_irq_unmask(struct irq_data *irqd)
-{
-       struct dpu_kms *dpu_kms;
-
-       if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
-               DPU_ERROR("invalid parameters irqd %d\n", irqd != NULL);
-               return;
-       }
-       dpu_kms = irq_data_get_irq_chip_data(irqd);
-
-       /* memory barrier */
-       smp_mb__before_atomic();
-       set_bit(irqd->hwirq, &dpu_kms->irq_controller.enabled_mask);
-       /* memory barrier */
-       smp_mb__after_atomic();
-}
-
-static struct irq_chip dpu_core_irq_chip = {
-       .name = "dpu",
-       .irq_mask = dpu_core_irq_mask,
-       .irq_unmask = dpu_core_irq_unmask,
-};
-
-static int dpu_core_irqdomain_map(struct irq_domain *domain,
-               unsigned int irq, irq_hw_number_t hwirq)
-{
-       struct dpu_kms *dpu_kms;
-       int rc;
-
-       if (!domain || !domain->host_data) {
-               DPU_ERROR("invalid parameters domain %d\n", domain != NULL);
-               return -EINVAL;
-       }
-       dpu_kms = domain->host_data;
-
-       irq_set_chip_and_handler(irq, &dpu_core_irq_chip, handle_level_irq);
-       rc = irq_set_chip_data(irq, dpu_kms);
-
-       return rc;
-}
-
-static const struct irq_domain_ops dpu_core_irqdomain_ops = {
-       .map = dpu_core_irqdomain_map,
-       .xlate = irq_domain_xlate_onecell,
-};
-
-int dpu_core_irq_domain_add(struct dpu_kms *dpu_kms)
-{
-       struct device *dev;
-       struct irq_domain *domain;
-
-       if (!dpu_kms->dev || !dpu_kms->dev->dev) {
-               pr_err("invalid device handles\n");
-               return -EINVAL;
-       }
-
-       dev = dpu_kms->dev->dev;
-
-       domain = irq_domain_add_linear(dev->of_node, 32,
-                       &dpu_core_irqdomain_ops, dpu_kms);
-       if (!domain) {
-               pr_err("failed to add irq_domain\n");
-               return -EINVAL;
-       }
-
-       dpu_kms->irq_controller.enabled_mask = 0;
-       dpu_kms->irq_controller.domain = domain;
-
-       return 0;
-}
-
-int dpu_core_irq_domain_fini(struct dpu_kms *dpu_kms)
-{
-       if (dpu_kms->irq_controller.domain) {
-               irq_domain_remove(dpu_kms->irq_controller.domain);
-               dpu_kms->irq_controller.domain = NULL;
-       }
-       return 0;
-}
-
 irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms)
 {
        /*
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
index 64a54fe..8fa59db 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
@@ -38,20 +38,6 @@
 void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms);
 
 /**
- * dpu_core_irq_domain_add - Add core IRQ domain for DPU
- * @dpu_kms:           DPU handle
- * @return:            none
- */
-int dpu_core_irq_domain_add(struct dpu_kms *dpu_kms);
-
-/**
- * dpu_core_irq_domain_fini - uninstall core IRQ domain
- * @dpu_kms:           DPU handle
- * @return:            0 if success; error code otherwise
- */
-int dpu_core_irq_domain_fini(struct dpu_kms *dpu_kms);
-
-/**
  * dpu_core_irq - core IRQ handler
  * @dpu_kms:           DPU handle
  * @return:            interrupt handling status
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
index 1965ff5..fe4d8ea 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
@@ -21,7 +21,7 @@
 #include "dpu_hw_catalog.h"
 #include "dpu_power_handle.h"
 
-#define        DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE      320000000
+#define        DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE      412500000
 
 /**
  * struct dpu_core_perf_params - definition of performance parameters
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 8e779c0..c5b370f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -77,13 +77,6 @@
        .has_idle_pc = true,
 };
 
-static struct dpu_mdss_base_cfg sdm845_mdss[] = {
-       {
-       .name = "mdss_0", .id = MDP_TOP,
-       .base = 0x0, .features = 0
-       },
-};
-
 static struct dpu_mdp_cfg sdm845_mdp[] = {
        {
        .name = "top_0", .id = MDP_TOP,
@@ -550,8 +543,6 @@ void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
 {
        *dpu_cfg = (struct dpu_mdss_cfg){
                .caps = &sdm845_dpu_caps,
-               .mdss_count = ARRAY_SIZE(sdm845_mdss),
-               .mdss = sdm845_mdss,
                .mdp_count = ARRAY_SIZE(sdm845_mdp),
                .mdp = sdm845_mdp,
                .ctl_count = ARRAY_SIZE(sdm845_ctl),
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 39bec0a..7084643 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -492,10 +492,6 @@ struct dpu_wb_sub_blocks {
        u32 maxlinewidth;
 };
 
-struct dpu_mdss_base_cfg {
-       DPU_HW_BLK_INFO;
-};
-
 /**
  * dpu_clk_ctrl_type - Defines top level clock control signals
  */
@@ -875,9 +871,6 @@ struct dpu_mdss_cfg {
 
        const struct dpu_caps *caps;
 
-       u32 mdss_count;
-       struct dpu_mdss_base_cfg *mdss;
-
        u32 mdp_count;
        struct dpu_mdp_cfg *mdp;
 
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 9767cc8..73f084c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -22,7 +22,6 @@
  * Register offsets in MDSS register file for the interrupt registers
  * w.r.t. to the MDSS base
  */
-#define HW_INTR_STATUS                 0x0010
 #define MDP_SSPP_TOP0_OFF              0x1000
 #define MDP_INTF_0_OFF                 0x6B000
 #define MDP_INTF_1_OFF                 0x6B800
@@ -1017,17 +1016,6 @@ static int dpu_hw_intr_get_valid_interrupts(struct 
dpu_hw_intr *intr,
        return 0;
 }
 
-static int dpu_hw_intr_get_interrupt_sources(struct dpu_hw_intr *intr,
-               uint32_t *sources)
-{
-       if (!intr || !sources)
-               return -EINVAL;
-
-       *sources = DPU_REG_READ(&intr->hw, HW_INTR_STATUS);
-
-       return 0;
-}
-
 static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr)
 {
        int i;
@@ -1162,7 +1150,6 @@ static void __setup_intr_ops(struct dpu_hw_intr_ops *ops)
        ops->clear_all_irqs = dpu_hw_intr_clear_irqs;
        ops->disable_all_irqs = dpu_hw_intr_disable_irqs;
        ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts;
-       ops->get_interrupt_sources = dpu_hw_intr_get_interrupt_sources;
        ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses;
        ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status;
        ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock;
@@ -1170,23 +1157,18 @@ static void __setup_intr_ops(struct dpu_hw_intr_ops 
*ops)
        ops->get_intr_status_nolock = dpu_hw_intr_get_intr_status_nolock;
 }
 
-static struct dpu_mdss_base_cfg *__intr_offset(struct dpu_mdss_cfg *m,
+static void __intr_offset(struct dpu_mdss_cfg *m,
                void __iomem *addr, struct dpu_hw_blk_reg_map *hw)
 {
-       if (!m || !addr || !hw || m->mdp_count == 0)
-               return NULL;
-
        hw->base_off = addr;
-       hw->blk_off = m->mdss[0].base;
+       hw->blk_off = m->mdp[0].base;
        hw->hwversion = m->hwversion;
-       return &m->mdss[0];
 }
 
 struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
                struct dpu_mdss_cfg *m)
 {
        struct dpu_hw_intr *intr;
-       struct dpu_mdss_base_cfg *cfg;
 
        if (!addr || !m)
                return ERR_PTR(-EINVAL);
@@ -1195,11 +1177,7 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr,
        if (!intr)
                return ERR_PTR(-ENOMEM);
 
-       cfg = __intr_offset(m, addr, &intr->hw);
-       if (!cfg) {
-               kfree(intr);
-               return ERR_PTR(-EINVAL);
-       }
+       __intr_offset(m, addr, &intr->hw);
        __setup_intr_ops(&intr->ops);
 
        intr->irq_idx_tbl_size = ARRAY_SIZE(dpu_irq_map);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 2f1a828..b52cdca 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -242,17 +242,6 @@ struct dpu_hw_intr_ops {
        int (*get_valid_interrupts)(
                        struct dpu_hw_intr *intr,
                        uint32_t *mask);
-
-       /**
-        * get_interrupt_sources - Gets the bitmask of the DPU interrupt
-        *                         source that are currently fired.
-        * @intr:       HW interrupt handle
-        * @sources:    Returning the DPU interrupt source status bit mask
-        * @return:     0 for success, otherwise failure
-        */
-       int (*get_interrupt_sources)(
-                       struct dpu_hw_intr *intr,
-                       uint32_t *sources);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c
index 19c0929..d5e6ce0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c
@@ -19,56 +19,11 @@
 #include "dpu_irq.h"
 #include "dpu_core_irq.h"
 
-static uint32_t g_dpu_irq_status;
-
 irqreturn_t dpu_irq(struct msm_kms *kms)
 {
        struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-       u32 interrupts;
-
-       dpu_kms->hw_intr->ops.get_interrupt_sources(dpu_kms->hw_intr,
-                       &interrupts);
-
-       /* store irq status in case of irq-storm debugging */
-       g_dpu_irq_status = interrupts;
-
-       /*
-        * Taking care of MDP interrupt
-        */
-       if (interrupts & IRQ_SOURCE_MDP) {
-               interrupts &= ~IRQ_SOURCE_MDP;
-               dpu_core_irq(dpu_kms);
-       }
-
-       /*
-        * Routing all other interrupts to external drivers
-        */
-       while (interrupts) {
-               irq_hw_number_t hwirq = fls(interrupts) - 1;
-               unsigned int mapping;
-               int rc;
-
-               mapping = irq_find_mapping(dpu_kms->irq_controller.domain,
-                               hwirq);
-               if (mapping == 0) {
-                       DPU_EVT32(hwirq, DPU_EVTLOG_ERROR);
-                       goto error;
-               }
-
-               rc = generic_handle_irq(mapping);
-               if (rc < 0) {
-                       DPU_EVT32(hwirq, mapping, rc, DPU_EVTLOG_ERROR);
-                       goto error;
-               }
-
-               interrupts &= ~(1 << hwirq);
-       }
-
-       return IRQ_HANDLED;
 
-error:
-       /* bad situation, inform irq system, it may disable overall MDSS irq */
-       return IRQ_NONE;
+       return dpu_core_irq(dpu_kms);
 }
 
 void dpu_irq_preinstall(struct msm_kms *kms)
@@ -108,5 +63,4 @@ void dpu_irq_uninstall(struct msm_kms *kms)
        }
 
        dpu_core_irq_uninstall(dpu_kms);
-       dpu_core_irq_domain_fini(dpu_kms);
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 06adb38..e4ab753 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -636,10 +636,6 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
        priv = dev->dev_private;
        catalog = dpu_kms->catalog;
 
-       ret = dpu_core_irq_domain_add(dpu_kms);
-       if (ret)
-               goto fail_irq;
-
        /*
         * Create encoder and query display drivers to create
         * bridges and connectors
@@ -716,8 +712,6 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
        return 0;
 fail:
        _dpu_kms_drm_obj_destroy(dpu_kms);
-fail_irq:
-       dpu_core_irq_domain_fini(dpu_kms);
        return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index 5b0c081..a1c0910 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -184,8 +184,6 @@ struct dpu_kms {
        struct regulator *mmagic;
        struct regulator *venus;
 
-       struct dpu_irq_controller irq_controller;
-
        struct dpu_hw_intr *hw_intr;
        struct dpu_irq irq_obj;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
new file mode 100644
index 0000000..04accdf
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
@@ -0,0 +1,251 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (c) 2018, The Linux Foundation
+ */
+
+#include "dpu_kms.h"
+
+#define to_dpu_mdss(x) container_of(x, struct dpu_mdss, base)
+
+#define HW_INTR_STATUS                 0x0010
+
+struct dpu_mdss {
+       struct msm_mdss base;
+       void __iomem *mmio;
+       unsigned long mmio_len;
+       u32 hwversion;
+       struct dss_module_power mp;
+       struct dpu_irq_controller irq_controller;
+};
+
+static irqreturn_t dpu_mdss_irq(int irq, void *arg)
+{
+       struct dpu_mdss *dpu_mdss = arg;
+       u32 interrupts;
+
+       interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS);
+
+       while (interrupts) {
+               irq_hw_number_t hwirq = fls(interrupts) - 1;
+               unsigned int mapping;
+               int rc;
+
+               mapping = irq_find_mapping(dpu_mdss->irq_controller.domain,
+                                          hwirq);
+               if (mapping == 0) {
+                       DPU_EVT32(hwirq, DPU_EVTLOG_ERROR);
+                       return IRQ_NONE;
+               }
+
+               rc = generic_handle_irq(mapping);
+               if (rc < 0) {
+                       DPU_EVT32(hwirq, mapping, rc, DPU_EVTLOG_ERROR);
+                       return IRQ_NONE;
+               }
+
+               interrupts &= ~(1 << hwirq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void dpu_mdss_irq_mask(struct irq_data *irqd)
+{
+       struct dpu_mdss *dpu_mdss = irq_data_get_irq_chip_data(irqd);
+
+       /* memory barrier */
+       smp_mb__before_atomic();
+       clear_bit(irqd->hwirq, &dpu_mdss->irq_controller.enabled_mask);
+       /* memory barrier */
+       smp_mb__after_atomic();
+}
+
+static void dpu_mdss_irq_unmask(struct irq_data *irqd)
+{
+       struct dpu_mdss *dpu_mdss = irq_data_get_irq_chip_data(irqd);
+
+       /* memory barrier */
+       smp_mb__before_atomic();
+       set_bit(irqd->hwirq, &dpu_mdss->irq_controller.enabled_mask);
+       /* memory barrier */
+       smp_mb__after_atomic();
+}
+
+static struct irq_chip dpu_mdss_irq_chip = {
+       .name = "dpu_mdss",
+       .irq_mask = dpu_mdss_irq_mask,
+       .irq_unmask = dpu_mdss_irq_unmask,
+};
+
+static int dpu_mdss_irqdomain_map(struct irq_domain *domain,
+               unsigned int irq, irq_hw_number_t hwirq)
+{
+       struct dpu_mdss *dpu_mdss = domain->host_data;
+       int ret;
+
+       irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq);
+       ret = irq_set_chip_data(irq, dpu_mdss);
+
+       return ret;
+}
+
+static const struct irq_domain_ops dpu_mdss_irqdomain_ops = {
+       .map = dpu_mdss_irqdomain_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss)
+{
+       struct device *dev;
+       struct irq_domain *domain;
+
+       dev = dpu_mdss->base.dev->dev;
+
+       domain = irq_domain_add_linear(dev->of_node, 32,
+                       &dpu_mdss_irqdomain_ops, dpu_mdss);
+       if (!domain) {
+               DPU_ERROR("failed to add irq_domain\n");
+               return -EINVAL;
+       }
+
+       dpu_mdss->irq_controller.enabled_mask = 0;
+       dpu_mdss->irq_controller.domain = domain;
+
+       return 0;
+}
+
+int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss)
+{
+       if (dpu_mdss->irq_controller.domain) {
+               irq_domain_remove(dpu_mdss->irq_controller.domain);
+               dpu_mdss->irq_controller.domain = NULL;
+       }
+       return 0;
+}
+static int dpu_mdss_enable(struct msm_mdss *mdss)
+{
+       struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss);
+       struct dss_module_power *mp = &dpu_mdss->mp;
+       int ret;
+
+       ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true);
+       if (ret)
+               DPU_ERROR("clock enable failed, ret:%d\n", ret);
+
+       return ret;
+}
+
+static int dpu_mdss_disable(struct msm_mdss *mdss)
+{
+       struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss);
+       struct dss_module_power *mp = &dpu_mdss->mp;
+       int ret;
+
+       ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false);
+       if (ret)
+               DPU_ERROR("clock disable failed, ret:%d\n", ret);
+
+       return ret;
+}
+
+static void dpu_mdss_destroy(struct drm_device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev->dev);
+       struct msm_drm_private *priv = dev->dev_private;
+       struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss);
+       struct dss_module_power *mp = &dpu_mdss->mp;
+
+       _dpu_mdss_irq_domain_fini(dpu_mdss);
+
+       msm_dss_put_clk(mp->clk_config, mp->num_clk);
+       devm_kfree(&pdev->dev, mp->clk_config);
+
+       if (dpu_mdss->mmio)
+               msm_iounmap(pdev, dpu_mdss->mmio);
+       dpu_mdss->mmio = NULL;
+
+       pm_runtime_disable(dev->dev);
+       priv->mdss = NULL;
+}
+
+static const struct msm_mdss_funcs mdss_funcs = {
+       .enable = dpu_mdss_enable,
+       .disable = dpu_mdss_disable,
+       .destroy = dpu_mdss_destroy,
+};
+
+int dpu_mdss_init(struct drm_device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev->dev);
+       struct msm_drm_private *priv = dev->dev_private;
+       struct dpu_mdss *dpu_mdss;
+       struct dss_module_power *mp;
+       int ret = 0;
+
+       dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL);
+       if (!dpu_mdss)
+               return -ENOMEM;
+
+       dpu_mdss->mmio = msm_ioremap(pdev, "mdss_phys", "mdss_phys");
+       if (IS_ERR(dpu_mdss->mmio))
+               return PTR_ERR(dpu_mdss->mmio);
+
+       DRM_DEBUG("mapped mdss address space @%pK\n", dpu_mdss->mmio);
+       dpu_mdss->mmio_len = msm_iomap_size(pdev, "mdss_phys");
+
+       mp = &dpu_mdss->mp;
+       ret = msm_dss_parse_clock(pdev, mp);
+       if (ret) {
+               DPU_ERROR("failed to parse clocks, ret=%d\n", ret);
+               goto clk_parse_err;
+       }
+
+       ret = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
+       if (ret) {
+               DPU_ERROR("failed to get clocks, ret=%d\n", ret);
+               goto clk_get_error;
+       }
+
+       ret = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
+       if (ret) {
+               DPU_ERROR("failed to set clock rate, ret=%d\n", ret);
+               goto clk_rate_error;
+       }
+
+       dpu_mdss->base.dev = dev;
+       dpu_mdss->base.funcs = &mdss_funcs;
+
+       ret = _dpu_mdss_irq_domain_add(dpu_mdss);
+       if (ret)
+               goto irq_domain_error;
+
+       ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0),
+                       dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss);
+       if (ret) {
+               DPU_ERROR("failed to init irq: %d\n", ret);
+               goto irq_error;
+       }
+
+       pm_runtime_enable(dev->dev);
+
+       pm_runtime_get_sync(dev->dev);
+       dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio);
+       pm_runtime_put_sync(dev->dev);
+
+       priv->mdss = &dpu_mdss->base;
+
+       return ret;
+
+irq_error:
+       _dpu_mdss_irq_domain_fini(dpu_mdss);
+irq_domain_error:
+clk_rate_error:
+       msm_dss_put_clk(mp->clk_config, mp->num_clk);
+clk_get_error:
+       devm_kfree(&pdev->dev, mp->clk_config);
+clk_parse_err:
+       if (dpu_mdss->mmio)
+               msm_iounmap(pdev, dpu_mdss->mmio);
+       dpu_mdss->mmio = NULL;
+       return ret;
+}
diff --git a/drivers/gpu/drm/msm/dpu_io_util.c 
b/drivers/gpu/drm/msm/dpu_io_util.c
index a18bc99..ecc297c 100644
--- a/drivers/gpu/drm/msm/dpu_io_util.c
+++ b/drivers/gpu/drm/msm/dpu_io_util.c
@@ -448,6 +448,55 @@ int msm_dss_enable_clk(struct dss_clk *clk_arry, int 
num_clk, int enable)
 } /* msm_dss_enable_clk */
 EXPORT_SYMBOL(msm_dss_enable_clk);
 
+int msm_dss_parse_clock(struct platform_device *pdev,
+               struct dss_module_power *mp)
+{
+       u32 i, rc = 0;
+       const char *clock_name;
+       u32 rate = 0;
+       int num_clk = 0;
+
+       if (!pdev || !mp)
+               return -EINVAL;
+
+       mp->num_clk = 0;
+       num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names");
+       if (num_clk <= 0) {
+               pr_debug("clocks are not defined\n");
+               return 0;
+       }
+
+       mp->clk_config = devm_kzalloc(&pdev->dev,
+                                     sizeof(struct dss_clk) * num_clk,
+                                     GFP_KERNEL);
+       if (!mp->clk_config)
+               return -ENOMEM;
+
+       for (i = 0; i < num_clk; i++) {
+               rc = of_property_read_string_index(pdev->dev.of_node,
+                                                  "clock-names", i,
+                                                  &clock_name);
+               if (rc)
+                       break;
+               strlcpy(mp->clk_config[i].clk_name, clock_name,
+                       sizeof(mp->clk_config[i].clk_name));
+
+               mp->clk_config[i].type = DSS_CLK_AHB;
+               rc = of_property_read_u32_index(pdev->dev.of_node,
+                                               "clock-frequency", i,
+                                               &rate);
+               if (rc)
+                       continue;
+               mp->clk_config[i].rate = rate;
+               if (rate)
+                       mp->clk_config[i].type = DSS_CLK_PCLK;
+       }
+
+       if (!rc)
+               mp->num_clk = num_clk;
+
+       return rc;
+}
 
 int dpu_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
                        uint8_t reg_offset, uint8_t *read_buf)
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 5d8f1b6..a0e73ea 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -503,7 +503,18 @@ static int msm_drm_init(struct device *dev, struct 
drm_driver *drv)
        ddev->dev_private = priv;
        priv->dev = ddev;
 
-       ret = mdp5_mdss_init(ddev);
+       switch (get_mdp_ver(pdev)) {
+       case KMS_MDP5:
+               ret = mdp5_mdss_init(ddev);
+               break;
+       case KMS_DPU:
+               ret = dpu_mdss_init(ddev);
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
        if (ret)
                goto mdss_init_fail;
 
@@ -1539,12 +1550,13 @@ static int add_display_components(struct device *dev,
        int ret;
 
        /*
-        * MDP5 based devices don't have a flat hierarchy. There is a top level
-        * parent: MDSS, and children: MDP5, DSI, HDMI, eDP etc. Populate the
-        * children devices, find the MDP5 node, and then add the interfaces
-        * to our components list.
+        * MDP5/DPU based devices don't have a flat hierarchy. There is a top
+        * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc.
+        * Populate the children devices, find the MDP5/DPU node, and then add
+        * the interfaces to our components list.
         */
-       if (of_device_is_compatible(dev->of_node, "qcom,mdss")) {
+       if (of_device_is_compatible(dev->of_node, "qcom,mdss") ||
+               of_device_is_compatible(dev->of_node, "qcom,dpu-mdss")) {
                ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
                if (ret) {
                        dev_err(dev, "failed to populate children devices\n");
@@ -1686,7 +1698,7 @@ static int msm_pdev_remove(struct platform_device *pdev)
        { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
        { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
 #ifdef CONFIG_DRM_MSM_DPU
-       { .compatible = "qcom,dpu-kms", .data = (void *)KMS_DPU },
+       { .compatible = "qcom,dpu-mdss", .data = (void *)KMS_DPU },
 #endif
        {}
 };
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 90a2521..e8e5e73 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -381,7 +381,7 @@ struct msm_drm_private {
        /* subordinate devices, if present: */
        struct platform_device *gpu_pdev;
 
-       /* top level MDSS wrapper device (for MDP5 only) */
+       /* top level MDSS wrapper device (for MDP5/DPU only) */
        struct msm_mdss *mdss;
 
        /* possibly this should be in the kms component, but it is
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 9a7bc7d..5e1de85 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -144,6 +144,7 @@ struct msm_mdss {
 };
 
 int mdp5_mdss_init(struct drm_device *dev);
+int dpu_mdss_init(struct drm_device *dev);
 
 /**
  * Mode Set Utility Functions
diff --git a/include/linux/dpu_io_util.h b/include/linux/dpu_io_util.h
index 7c73899..45e606f 100644
--- a/include/linux/dpu_io_util.h
+++ b/include/linux/dpu_io_util.h
@@ -104,6 +104,8 @@ int msm_dss_config_vreg(struct device *dev, struct dss_vreg 
*in_vreg,
 void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
 int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
 int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
+int msm_dss_parse_clock(struct platform_device *pdev,
+               struct dss_module_power *mp);
 
 int dpu_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
                       uint8_t reg_offset, uint8_t *read_buf);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to