Message ID | 1526050178-31893-4-git-send-email-ryadav@codeaurora.org (mailing list archive) |
---|---|
State | Not Applicable, archived |
Delegated to: | Andy Gross |
Headers | show |
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 >
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
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
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 >> -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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);
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