On Fri, May 11, 2018 at 11:05:24AM -0600, Jordan Crouse wrote:
> On Fri, May 11, 2018 at 08:19:29PM +0530, Rajesh Yadav wrote:
> > 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 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>
> 
> Reviewed-by: Jordan Crouse <jcro...@codeaurora.org>
> 
> I know you'll get a hundred different opinions from a hundred different people

I'll interpret this as solicitation of my opinion :-)

I find this level of detail _extremely_ useful when reviewing, especially on
sets as big as this one.

It's a pretty good strategy to make reviews go as smoothly as possible, since
it's generally more difficult to read code than to write it.

Sean

/opinion

> but you don't need to credit me for every change - just a single line "fixed
> bugs" works for me.
> 
> > ---
> >  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_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          | 254 
> > ++++++++++++++++++++++
> >  drivers/gpu/drm/msm/dpu_io_util.c                 |  57 +++++
> >  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 +
> >  16 files changed, 339 insertions(+), 226 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_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..ce680ea
> > --- /dev/null
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
> > @@ -0,0 +1,254 @@
> > +/*
> > + * 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)) {
> > +           ret = PTR_ERR(dpu_mdss->mmio);
> > +           DPU_ERROR("mdss register memory map failed: %d\n", ret);
> > +           dpu_mdss->mmio = NULL;
> > +           return ret;
> > +   }
> > +   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..c44f33f 100644
> > --- a/drivers/gpu/drm/msm/dpu_io_util.c
> > +++ b/drivers/gpu/drm/msm/dpu_io_util.c
> > @@ -448,6 +448,63 @@ 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, max_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));
> > +
> > +           rc = of_property_read_u32_index(pdev->dev.of_node,
> > +                                           "clock-rate", i,
> > +                                           &rate);
> > +           if (rc)
> > +                   break;
> > +           mp->clk_config[i].rate = rate;
> > +           if (!mp->clk_config[i].rate)
> > +                   mp->clk_config[i].type = DSS_CLK_AHB;
> > +           else
> > +                   mp->clk_config[i].type = DSS_CLK_PCLK;
> > +
> > +           rc = of_property_read_u32_index(pdev->dev.of_node,
> > +                                           "clock-max-rate", i,
> > +                                           &max_rate);
> > +           if (rc)
> > +                   break;
> > +           mp->clk_config[i].max_rate = max_rate;
> > +   }
> > +
> > +   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
> > 
> > _______________________________________________
> > Freedreno mailing list
> > freedr...@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/freedreno
> 
> -- 
> The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project

-- 
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to