diff mbox

[DPU,v2,03/12] drm/msm/dpu: add MDSS top level driver for dpu

Message ID 1526050178-31893-4-git-send-email-ryadav@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Rajesh Yadav May 11, 2018, 2:49 p.m. UTC
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 <ryadav@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_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

Comments

Sean Paul May 11, 2018, 3:28 p.m. UTC | #1
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 <ryadav@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_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
> 

/snip

> 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

/snip

> +
> +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);

remove this ...

> +		DPU_ERROR("mdss register memory map failed: %d\n", ret);
> +		dpu_mdss->mmio = NULL;
> +		return ret;

... and replace with
                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..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);

Hmm, I missed these in my first review, these need new dt bindings. I'm
far from an expert on dt bindings, but I think you'll be asked to define these
are clocks, and get the rate/max rate information from the clock subsystem
instead of breaking it all out like this.

Sean

> +		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
>
Jordan Crouse May 11, 2018, 5:05 p.m. UTC | #2
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 <ryadav@codeaurora.org>

Reviewed-by: Jordan Crouse <jcrouse@codeaurora.org>

I know you'll get a hundred different opinions from a hundred different people
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
> Freedreno@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/freedreno
Sean Paul May 11, 2018, 6:32 p.m. UTC | #3
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 <ryadav@codeaurora.org>
> 
> Reviewed-by: Jordan Crouse <jcrouse@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
> > Freedreno@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
Rajesh Yadav May 14, 2018, 2:06 p.m. UTC | #4
On 2018-05-11 20:58, Sean Paul 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 <ryadav@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_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
>> 
> 
> /snip
> 
>> 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
> 
> /snip
> 
>> +
>> +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);
> 
> remove this ...
> 
>> +		DPU_ERROR("mdss register memory map failed: %d\n", ret);
>> +		dpu_mdss->mmio = NULL;
>> +		return ret;
> 
> ... and replace with
>                 return PTR_ERR(dpu_mdss->mmio);
> 
Sure, I'll update in v3.

>> +	}
>> +	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);
> 
> Hmm, I missed these in my first review, these need new dt bindings. I'm
> far from an expert on dt bindings, but I think you'll be asked to 
> define these
> are clocks, and get the rate/max rate information from the clock 
> subsystem
> instead of breaking it all out like this.
> 
> Sean
> 
I have checked the clock-bindings.txt and in the clock consumers example
I can see that clock-frequency binding is used, so I'll rename 
"clock-rate" to "clock-frequency".
Regarding max-rate/frequency, I have not see any references for it in 
clock-bindings.txt.
This properties is mainly used in downstream driver, i'll remove it.

Thanks,
Rajesh

>> +		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
>>
diff mbox

Patch

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);