187729e2aSDmitry Baryshkov /* 287729e2aSDmitry Baryshkov * SPDX-License-Identifier: GPL-2.0 387729e2aSDmitry Baryshkov * Copyright (c) 2018, The Linux Foundation 487729e2aSDmitry Baryshkov */ 587729e2aSDmitry Baryshkov 6e1072257SDmitry Baryshkov #include <linux/clk.h> 787729e2aSDmitry Baryshkov #include <linux/irq.h> 887729e2aSDmitry Baryshkov #include <linux/irqchip.h> 987729e2aSDmitry Baryshkov #include <linux/irqdesc.h> 1087729e2aSDmitry Baryshkov #include <linux/irqchip/chained_irq.h> 11e1072257SDmitry Baryshkov #include <linux/pm_runtime.h> 1287729e2aSDmitry Baryshkov 13*ecb23f2eSDmitry Baryshkov #include "msm_drv.h" 14*ecb23f2eSDmitry Baryshkov #include "msm_kms.h" 15*ecb23f2eSDmitry Baryshkov 1687729e2aSDmitry Baryshkov /* for DPU_HW_* defines */ 1787729e2aSDmitry Baryshkov #include "disp/dpu1/dpu_hw_catalog.h" 1887729e2aSDmitry Baryshkov 1987729e2aSDmitry Baryshkov #define HW_REV 0x0 2087729e2aSDmitry Baryshkov #define HW_INTR_STATUS 0x0010 2187729e2aSDmitry Baryshkov 2287729e2aSDmitry Baryshkov #define UBWC_STATIC 0x144 2387729e2aSDmitry Baryshkov #define UBWC_CTRL_2 0x150 2487729e2aSDmitry Baryshkov #define UBWC_PREDICTION_MODE 0x154 2587729e2aSDmitry Baryshkov 26e1072257SDmitry Baryshkov struct msm_mdss { 27e1072257SDmitry Baryshkov struct device *dev; 28e1072257SDmitry Baryshkov 2987729e2aSDmitry Baryshkov void __iomem *mmio; 3087729e2aSDmitry Baryshkov struct clk_bulk_data *clocks; 3187729e2aSDmitry Baryshkov size_t num_clocks; 3287729e2aSDmitry Baryshkov bool is_mdp5; 3387729e2aSDmitry Baryshkov struct { 3487729e2aSDmitry Baryshkov unsigned long enabled_mask; 3587729e2aSDmitry Baryshkov struct irq_domain *domain; 3687729e2aSDmitry Baryshkov } irq_controller; 3787729e2aSDmitry Baryshkov }; 3887729e2aSDmitry Baryshkov 3987729e2aSDmitry Baryshkov static void msm_mdss_irq(struct irq_desc *desc) 4087729e2aSDmitry Baryshkov { 41e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc); 4287729e2aSDmitry Baryshkov struct irq_chip *chip = irq_desc_get_chip(desc); 4387729e2aSDmitry Baryshkov u32 interrupts; 4487729e2aSDmitry Baryshkov 4587729e2aSDmitry Baryshkov chained_irq_enter(chip, desc); 4687729e2aSDmitry Baryshkov 47e1072257SDmitry Baryshkov interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS); 4887729e2aSDmitry Baryshkov 4987729e2aSDmitry Baryshkov while (interrupts) { 5087729e2aSDmitry Baryshkov irq_hw_number_t hwirq = fls(interrupts) - 1; 5187729e2aSDmitry Baryshkov int rc; 5287729e2aSDmitry Baryshkov 53e1072257SDmitry Baryshkov rc = generic_handle_domain_irq(msm_mdss->irq_controller.domain, 5487729e2aSDmitry Baryshkov hwirq); 5587729e2aSDmitry Baryshkov if (rc < 0) { 56e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "handle irq fail: irq=%lu rc=%d\n", 5787729e2aSDmitry Baryshkov hwirq, rc); 5887729e2aSDmitry Baryshkov break; 5987729e2aSDmitry Baryshkov } 6087729e2aSDmitry Baryshkov 6187729e2aSDmitry Baryshkov interrupts &= ~(1 << hwirq); 6287729e2aSDmitry Baryshkov } 6387729e2aSDmitry Baryshkov 6487729e2aSDmitry Baryshkov chained_irq_exit(chip, desc); 6587729e2aSDmitry Baryshkov } 6687729e2aSDmitry Baryshkov 6787729e2aSDmitry Baryshkov static void msm_mdss_irq_mask(struct irq_data *irqd) 6887729e2aSDmitry Baryshkov { 69e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 7087729e2aSDmitry Baryshkov 7187729e2aSDmitry Baryshkov /* memory barrier */ 7287729e2aSDmitry Baryshkov smp_mb__before_atomic(); 73e1072257SDmitry Baryshkov clear_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 7487729e2aSDmitry Baryshkov /* memory barrier */ 7587729e2aSDmitry Baryshkov smp_mb__after_atomic(); 7687729e2aSDmitry Baryshkov } 7787729e2aSDmitry Baryshkov 7887729e2aSDmitry Baryshkov static void msm_mdss_irq_unmask(struct irq_data *irqd) 7987729e2aSDmitry Baryshkov { 80e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 8187729e2aSDmitry Baryshkov 8287729e2aSDmitry Baryshkov /* memory barrier */ 8387729e2aSDmitry Baryshkov smp_mb__before_atomic(); 84e1072257SDmitry Baryshkov set_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 8587729e2aSDmitry Baryshkov /* memory barrier */ 8687729e2aSDmitry Baryshkov smp_mb__after_atomic(); 8787729e2aSDmitry Baryshkov } 8887729e2aSDmitry Baryshkov 8987729e2aSDmitry Baryshkov static struct irq_chip msm_mdss_irq_chip = { 90e1072257SDmitry Baryshkov .name = "msm_mdss", 9187729e2aSDmitry Baryshkov .irq_mask = msm_mdss_irq_mask, 9287729e2aSDmitry Baryshkov .irq_unmask = msm_mdss_irq_unmask, 9387729e2aSDmitry Baryshkov }; 9487729e2aSDmitry Baryshkov 9587729e2aSDmitry Baryshkov static struct lock_class_key msm_mdss_lock_key, msm_mdss_request_key; 9687729e2aSDmitry Baryshkov 9787729e2aSDmitry Baryshkov static int msm_mdss_irqdomain_map(struct irq_domain *domain, 9887729e2aSDmitry Baryshkov unsigned int irq, irq_hw_number_t hwirq) 9987729e2aSDmitry Baryshkov { 100e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = domain->host_data; 10187729e2aSDmitry Baryshkov 10287729e2aSDmitry Baryshkov irq_set_lockdep_class(irq, &msm_mdss_lock_key, &msm_mdss_request_key); 10387729e2aSDmitry Baryshkov irq_set_chip_and_handler(irq, &msm_mdss_irq_chip, handle_level_irq); 10487729e2aSDmitry Baryshkov 105e1072257SDmitry Baryshkov return irq_set_chip_data(irq, msm_mdss); 10687729e2aSDmitry Baryshkov } 10787729e2aSDmitry Baryshkov 10887729e2aSDmitry Baryshkov static const struct irq_domain_ops msm_mdss_irqdomain_ops = { 10987729e2aSDmitry Baryshkov .map = msm_mdss_irqdomain_map, 11087729e2aSDmitry Baryshkov .xlate = irq_domain_xlate_onecell, 11187729e2aSDmitry Baryshkov }; 11287729e2aSDmitry Baryshkov 113e1072257SDmitry Baryshkov static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss) 11487729e2aSDmitry Baryshkov { 11587729e2aSDmitry Baryshkov struct device *dev; 11687729e2aSDmitry Baryshkov struct irq_domain *domain; 11787729e2aSDmitry Baryshkov 118e1072257SDmitry Baryshkov dev = msm_mdss->dev; 11987729e2aSDmitry Baryshkov 12087729e2aSDmitry Baryshkov domain = irq_domain_add_linear(dev->of_node, 32, 121e1072257SDmitry Baryshkov &msm_mdss_irqdomain_ops, msm_mdss); 12287729e2aSDmitry Baryshkov if (!domain) { 123e1072257SDmitry Baryshkov dev_err(dev, "failed to add irq_domain\n"); 12487729e2aSDmitry Baryshkov return -EINVAL; 12587729e2aSDmitry Baryshkov } 12687729e2aSDmitry Baryshkov 127e1072257SDmitry Baryshkov msm_mdss->irq_controller.enabled_mask = 0; 128e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = domain; 12987729e2aSDmitry Baryshkov 13087729e2aSDmitry Baryshkov return 0; 13187729e2aSDmitry Baryshkov } 13287729e2aSDmitry Baryshkov 133*ecb23f2eSDmitry Baryshkov static int msm_mdss_enable(struct msm_mdss *msm_mdss) 13487729e2aSDmitry Baryshkov { 13587729e2aSDmitry Baryshkov int ret; 13687729e2aSDmitry Baryshkov 137e1072257SDmitry Baryshkov ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); 13887729e2aSDmitry Baryshkov if (ret) { 139e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); 14087729e2aSDmitry Baryshkov return ret; 14187729e2aSDmitry Baryshkov } 14287729e2aSDmitry Baryshkov 14387729e2aSDmitry Baryshkov /* 14487729e2aSDmitry Baryshkov * HW_REV requires MDSS_MDP_CLK, which is not enabled by the mdss on 14587729e2aSDmitry Baryshkov * mdp5 hardware. Skip reading it for now. 14687729e2aSDmitry Baryshkov */ 147e1072257SDmitry Baryshkov if (msm_mdss->is_mdp5) 14887729e2aSDmitry Baryshkov return 0; 14987729e2aSDmitry Baryshkov 15087729e2aSDmitry Baryshkov /* 15187729e2aSDmitry Baryshkov * ubwc config is part of the "mdss" region which is not accessible 15287729e2aSDmitry Baryshkov * from the rest of the driver. hardcode known configurations here 15387729e2aSDmitry Baryshkov */ 154e1072257SDmitry Baryshkov switch (readl_relaxed(msm_mdss->mmio + HW_REV)) { 15587729e2aSDmitry Baryshkov case DPU_HW_VER_500: 15687729e2aSDmitry Baryshkov case DPU_HW_VER_501: 157e1072257SDmitry Baryshkov writel_relaxed(0x420, msm_mdss->mmio + UBWC_STATIC); 15887729e2aSDmitry Baryshkov break; 15987729e2aSDmitry Baryshkov case DPU_HW_VER_600: 16087729e2aSDmitry Baryshkov /* TODO: 0x102e for LP_DDR4 */ 161e1072257SDmitry Baryshkov writel_relaxed(0x103e, msm_mdss->mmio + UBWC_STATIC); 162e1072257SDmitry Baryshkov writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); 163e1072257SDmitry Baryshkov writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); 16487729e2aSDmitry Baryshkov break; 16587729e2aSDmitry Baryshkov case DPU_HW_VER_620: 166e1072257SDmitry Baryshkov writel_relaxed(0x1e, msm_mdss->mmio + UBWC_STATIC); 16787729e2aSDmitry Baryshkov break; 16887729e2aSDmitry Baryshkov case DPU_HW_VER_720: 169e1072257SDmitry Baryshkov writel_relaxed(0x101e, msm_mdss->mmio + UBWC_STATIC); 17087729e2aSDmitry Baryshkov break; 17187729e2aSDmitry Baryshkov } 17287729e2aSDmitry Baryshkov 17387729e2aSDmitry Baryshkov return ret; 17487729e2aSDmitry Baryshkov } 17587729e2aSDmitry Baryshkov 176*ecb23f2eSDmitry Baryshkov static int msm_mdss_disable(struct msm_mdss *msm_mdss) 17787729e2aSDmitry Baryshkov { 178e1072257SDmitry Baryshkov clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); 17987729e2aSDmitry Baryshkov 18087729e2aSDmitry Baryshkov return 0; 18187729e2aSDmitry Baryshkov } 18287729e2aSDmitry Baryshkov 183*ecb23f2eSDmitry Baryshkov static void msm_mdss_destroy(struct msm_mdss *msm_mdss) 18487729e2aSDmitry Baryshkov { 185e1072257SDmitry Baryshkov struct platform_device *pdev = to_platform_device(msm_mdss->dev); 18687729e2aSDmitry Baryshkov int irq; 18787729e2aSDmitry Baryshkov 188e1072257SDmitry Baryshkov pm_runtime_suspend(msm_mdss->dev); 189e1072257SDmitry Baryshkov pm_runtime_disable(msm_mdss->dev); 190e1072257SDmitry Baryshkov irq_domain_remove(msm_mdss->irq_controller.domain); 191e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = NULL; 19287729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 19387729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, NULL, NULL); 19487729e2aSDmitry Baryshkov } 19587729e2aSDmitry Baryshkov 19687729e2aSDmitry Baryshkov /* 19787729e2aSDmitry Baryshkov * MDP5 MDSS uses at most three specified clocks. 19887729e2aSDmitry Baryshkov */ 19987729e2aSDmitry Baryshkov #define MDP5_MDSS_NUM_CLOCKS 3 20087729e2aSDmitry Baryshkov static int mdp5_mdss_parse_clock(struct platform_device *pdev, struct clk_bulk_data **clocks) 20187729e2aSDmitry Baryshkov { 20287729e2aSDmitry Baryshkov struct clk_bulk_data *bulk; 20387729e2aSDmitry Baryshkov int num_clocks = 0; 20487729e2aSDmitry Baryshkov int ret; 20587729e2aSDmitry Baryshkov 20687729e2aSDmitry Baryshkov if (!pdev) 20787729e2aSDmitry Baryshkov return -EINVAL; 20887729e2aSDmitry Baryshkov 20987729e2aSDmitry Baryshkov bulk = devm_kcalloc(&pdev->dev, MDP5_MDSS_NUM_CLOCKS, sizeof(struct clk_bulk_data), GFP_KERNEL); 21087729e2aSDmitry Baryshkov if (!bulk) 21187729e2aSDmitry Baryshkov return -ENOMEM; 21287729e2aSDmitry Baryshkov 21387729e2aSDmitry Baryshkov bulk[num_clocks++].id = "iface"; 21487729e2aSDmitry Baryshkov bulk[num_clocks++].id = "bus"; 21587729e2aSDmitry Baryshkov bulk[num_clocks++].id = "vsync"; 21687729e2aSDmitry Baryshkov 21787729e2aSDmitry Baryshkov ret = devm_clk_bulk_get_optional(&pdev->dev, num_clocks, bulk); 21887729e2aSDmitry Baryshkov if (ret) 21987729e2aSDmitry Baryshkov return ret; 22087729e2aSDmitry Baryshkov 22187729e2aSDmitry Baryshkov *clocks = bulk; 22287729e2aSDmitry Baryshkov 22387729e2aSDmitry Baryshkov return num_clocks; 22487729e2aSDmitry Baryshkov } 22587729e2aSDmitry Baryshkov 226*ecb23f2eSDmitry Baryshkov static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5) 22787729e2aSDmitry Baryshkov { 228e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss; 22987729e2aSDmitry Baryshkov int ret; 23087729e2aSDmitry Baryshkov int irq; 23187729e2aSDmitry Baryshkov 232e1072257SDmitry Baryshkov msm_mdss = devm_kzalloc(&pdev->dev, sizeof(*msm_mdss), GFP_KERNEL); 233e1072257SDmitry Baryshkov if (!msm_mdss) 234e1072257SDmitry Baryshkov return ERR_PTR(-ENOMEM); 23587729e2aSDmitry Baryshkov 236e1072257SDmitry Baryshkov msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); 237e1072257SDmitry Baryshkov if (IS_ERR(msm_mdss->mmio)) 238e1072257SDmitry Baryshkov return ERR_CAST(msm_mdss->mmio); 23987729e2aSDmitry Baryshkov 240e1072257SDmitry Baryshkov dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); 24187729e2aSDmitry Baryshkov 24287729e2aSDmitry Baryshkov if (is_mdp5) 243e1072257SDmitry Baryshkov ret = mdp5_mdss_parse_clock(pdev, &msm_mdss->clocks); 24487729e2aSDmitry Baryshkov else 245e1072257SDmitry Baryshkov ret = devm_clk_bulk_get_all(&pdev->dev, &msm_mdss->clocks); 24687729e2aSDmitry Baryshkov if (ret < 0) { 247e1072257SDmitry Baryshkov dev_err(&pdev->dev, "failed to parse clocks, ret=%d\n", ret); 248e1072257SDmitry Baryshkov return ERR_PTR(ret); 24987729e2aSDmitry Baryshkov } 250e1072257SDmitry Baryshkov msm_mdss->num_clocks = ret; 251e1072257SDmitry Baryshkov msm_mdss->is_mdp5 = is_mdp5; 25287729e2aSDmitry Baryshkov 253e1072257SDmitry Baryshkov msm_mdss->dev = &pdev->dev; 25487729e2aSDmitry Baryshkov 25587729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 25687729e2aSDmitry Baryshkov if (irq < 0) 257e1072257SDmitry Baryshkov return ERR_PTR(irq); 25887729e2aSDmitry Baryshkov 259e1072257SDmitry Baryshkov ret = _msm_mdss_irq_domain_add(msm_mdss); 26087729e2aSDmitry Baryshkov if (ret) 261e1072257SDmitry Baryshkov return ERR_PTR(ret); 26287729e2aSDmitry Baryshkov 26387729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, msm_mdss_irq, 264e1072257SDmitry Baryshkov msm_mdss); 26587729e2aSDmitry Baryshkov 26687729e2aSDmitry Baryshkov pm_runtime_enable(&pdev->dev); 26787729e2aSDmitry Baryshkov 268e1072257SDmitry Baryshkov return msm_mdss; 26987729e2aSDmitry Baryshkov } 270*ecb23f2eSDmitry Baryshkov 271*ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_suspend(struct device *dev) 272*ecb23f2eSDmitry Baryshkov { 273*ecb23f2eSDmitry Baryshkov struct msm_drm_private *priv = dev_get_drvdata(dev); 274*ecb23f2eSDmitry Baryshkov 275*ecb23f2eSDmitry Baryshkov DBG(""); 276*ecb23f2eSDmitry Baryshkov 277*ecb23f2eSDmitry Baryshkov return msm_mdss_disable(priv->mdss); 278*ecb23f2eSDmitry Baryshkov } 279*ecb23f2eSDmitry Baryshkov 280*ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_resume(struct device *dev) 281*ecb23f2eSDmitry Baryshkov { 282*ecb23f2eSDmitry Baryshkov struct msm_drm_private *priv = dev_get_drvdata(dev); 283*ecb23f2eSDmitry Baryshkov 284*ecb23f2eSDmitry Baryshkov DBG(""); 285*ecb23f2eSDmitry Baryshkov 286*ecb23f2eSDmitry Baryshkov return msm_mdss_enable(priv->mdss); 287*ecb23f2eSDmitry Baryshkov } 288*ecb23f2eSDmitry Baryshkov 289*ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_suspend(struct device *dev) 290*ecb23f2eSDmitry Baryshkov { 291*ecb23f2eSDmitry Baryshkov 292*ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 293*ecb23f2eSDmitry Baryshkov return 0; 294*ecb23f2eSDmitry Baryshkov 295*ecb23f2eSDmitry Baryshkov return mdss_runtime_suspend(dev); 296*ecb23f2eSDmitry Baryshkov } 297*ecb23f2eSDmitry Baryshkov 298*ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_resume(struct device *dev) 299*ecb23f2eSDmitry Baryshkov { 300*ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 301*ecb23f2eSDmitry Baryshkov return 0; 302*ecb23f2eSDmitry Baryshkov 303*ecb23f2eSDmitry Baryshkov return mdss_runtime_resume(dev); 304*ecb23f2eSDmitry Baryshkov } 305*ecb23f2eSDmitry Baryshkov 306*ecb23f2eSDmitry Baryshkov static const struct dev_pm_ops mdss_pm_ops = { 307*ecb23f2eSDmitry Baryshkov SET_SYSTEM_SLEEP_PM_OPS(mdss_pm_suspend, mdss_pm_resume) 308*ecb23f2eSDmitry Baryshkov SET_RUNTIME_PM_OPS(mdss_runtime_suspend, mdss_runtime_resume, NULL) 309*ecb23f2eSDmitry Baryshkov .prepare = msm_pm_prepare, 310*ecb23f2eSDmitry Baryshkov .complete = msm_pm_complete, 311*ecb23f2eSDmitry Baryshkov }; 312*ecb23f2eSDmitry Baryshkov 313*ecb23f2eSDmitry Baryshkov static int get_mdp_ver(struct platform_device *pdev) 314*ecb23f2eSDmitry Baryshkov { 315*ecb23f2eSDmitry Baryshkov struct device *dev = &pdev->dev; 316*ecb23f2eSDmitry Baryshkov 317*ecb23f2eSDmitry Baryshkov return (int) (unsigned long) of_device_get_match_data(dev); 318*ecb23f2eSDmitry Baryshkov } 319*ecb23f2eSDmitry Baryshkov 320*ecb23f2eSDmitry Baryshkov static int find_mdp_node(struct device *dev, void *data) 321*ecb23f2eSDmitry Baryshkov { 322*ecb23f2eSDmitry Baryshkov return of_match_node(dpu_dt_match, dev->of_node) || 323*ecb23f2eSDmitry Baryshkov of_match_node(mdp5_dt_match, dev->of_node); 324*ecb23f2eSDmitry Baryshkov } 325*ecb23f2eSDmitry Baryshkov 326*ecb23f2eSDmitry Baryshkov static int mdss_probe(struct platform_device *pdev) 327*ecb23f2eSDmitry Baryshkov { 328*ecb23f2eSDmitry Baryshkov struct msm_mdss *mdss; 329*ecb23f2eSDmitry Baryshkov struct msm_drm_private *priv; 330*ecb23f2eSDmitry Baryshkov int mdp_ver = get_mdp_ver(pdev); 331*ecb23f2eSDmitry Baryshkov struct device *mdp_dev; 332*ecb23f2eSDmitry Baryshkov struct device *dev = &pdev->dev; 333*ecb23f2eSDmitry Baryshkov int ret; 334*ecb23f2eSDmitry Baryshkov 335*ecb23f2eSDmitry Baryshkov mdss = msm_mdss_init(pdev, mdp_ver == KMS_MDP5); 336*ecb23f2eSDmitry Baryshkov if (IS_ERR(mdss)) 337*ecb23f2eSDmitry Baryshkov return PTR_ERR(mdss); 338*ecb23f2eSDmitry Baryshkov 339*ecb23f2eSDmitry Baryshkov priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 340*ecb23f2eSDmitry Baryshkov if (!priv) { 341*ecb23f2eSDmitry Baryshkov ret = -ENOMEM; 342*ecb23f2eSDmitry Baryshkov goto fail; 343*ecb23f2eSDmitry Baryshkov } 344*ecb23f2eSDmitry Baryshkov 345*ecb23f2eSDmitry Baryshkov priv->mdss = mdss; 346*ecb23f2eSDmitry Baryshkov platform_set_drvdata(pdev, priv); 347*ecb23f2eSDmitry Baryshkov 348*ecb23f2eSDmitry Baryshkov /* 349*ecb23f2eSDmitry Baryshkov * MDP5/DPU based devices don't have a flat hierarchy. There is a top 350*ecb23f2eSDmitry Baryshkov * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc. 351*ecb23f2eSDmitry Baryshkov * Populate the children devices, find the MDP5/DPU node, and then add 352*ecb23f2eSDmitry Baryshkov * the interfaces to our components list. 353*ecb23f2eSDmitry Baryshkov */ 354*ecb23f2eSDmitry Baryshkov ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 355*ecb23f2eSDmitry Baryshkov if (ret) { 356*ecb23f2eSDmitry Baryshkov DRM_DEV_ERROR(dev, "failed to populate children devices\n"); 357*ecb23f2eSDmitry Baryshkov goto fail; 358*ecb23f2eSDmitry Baryshkov } 359*ecb23f2eSDmitry Baryshkov 360*ecb23f2eSDmitry Baryshkov mdp_dev = device_find_child(dev, NULL, find_mdp_node); 361*ecb23f2eSDmitry Baryshkov if (!mdp_dev) { 362*ecb23f2eSDmitry Baryshkov DRM_DEV_ERROR(dev, "failed to find MDSS MDP node\n"); 363*ecb23f2eSDmitry Baryshkov of_platform_depopulate(dev); 364*ecb23f2eSDmitry Baryshkov ret = -ENODEV; 365*ecb23f2eSDmitry Baryshkov goto fail; 366*ecb23f2eSDmitry Baryshkov } 367*ecb23f2eSDmitry Baryshkov 368*ecb23f2eSDmitry Baryshkov /* 369*ecb23f2eSDmitry Baryshkov * on MDP5 based platforms, the MDSS platform device is the component 370*ecb23f2eSDmitry Baryshkov * that adds MDP5 and other display interface components to 371*ecb23f2eSDmitry Baryshkov * itself. 372*ecb23f2eSDmitry Baryshkov */ 373*ecb23f2eSDmitry Baryshkov ret = msm_drv_probe(dev, mdp_dev); 374*ecb23f2eSDmitry Baryshkov put_device(mdp_dev); 375*ecb23f2eSDmitry Baryshkov if (ret) 376*ecb23f2eSDmitry Baryshkov goto fail; 377*ecb23f2eSDmitry Baryshkov 378*ecb23f2eSDmitry Baryshkov return 0; 379*ecb23f2eSDmitry Baryshkov 380*ecb23f2eSDmitry Baryshkov fail: 381*ecb23f2eSDmitry Baryshkov of_platform_depopulate(dev); 382*ecb23f2eSDmitry Baryshkov msm_mdss_destroy(priv->mdss); 383*ecb23f2eSDmitry Baryshkov 384*ecb23f2eSDmitry Baryshkov return ret; 385*ecb23f2eSDmitry Baryshkov } 386*ecb23f2eSDmitry Baryshkov 387*ecb23f2eSDmitry Baryshkov static int mdss_remove(struct platform_device *pdev) 388*ecb23f2eSDmitry Baryshkov { 389*ecb23f2eSDmitry Baryshkov struct msm_drm_private *priv = platform_get_drvdata(pdev); 390*ecb23f2eSDmitry Baryshkov struct msm_mdss *mdss = priv->mdss; 391*ecb23f2eSDmitry Baryshkov 392*ecb23f2eSDmitry Baryshkov component_master_del(&pdev->dev, &msm_drm_ops); 393*ecb23f2eSDmitry Baryshkov of_platform_depopulate(&pdev->dev); 394*ecb23f2eSDmitry Baryshkov 395*ecb23f2eSDmitry Baryshkov msm_mdss_destroy(mdss); 396*ecb23f2eSDmitry Baryshkov 397*ecb23f2eSDmitry Baryshkov return 0; 398*ecb23f2eSDmitry Baryshkov } 399*ecb23f2eSDmitry Baryshkov 400*ecb23f2eSDmitry Baryshkov static const struct of_device_id mdss_dt_match[] = { 401*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, 402*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,msm8998-mdss", .data = (void *)KMS_DPU }, 403*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,qcm2290-mdss", .data = (void *)KMS_DPU }, 404*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU }, 405*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sc7180-mdss", .data = (void *)KMS_DPU }, 406*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sc7280-mdss", .data = (void *)KMS_DPU }, 407*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sc8180x-mdss", .data = (void *)KMS_DPU }, 408*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sm8150-mdss", .data = (void *)KMS_DPU }, 409*ecb23f2eSDmitry Baryshkov { .compatible = "qcom,sm8250-mdss", .data = (void *)KMS_DPU }, 410*ecb23f2eSDmitry Baryshkov {} 411*ecb23f2eSDmitry Baryshkov }; 412*ecb23f2eSDmitry Baryshkov MODULE_DEVICE_TABLE(of, mdss_dt_match); 413*ecb23f2eSDmitry Baryshkov 414*ecb23f2eSDmitry Baryshkov static struct platform_driver mdss_platform_driver = { 415*ecb23f2eSDmitry Baryshkov .probe = mdss_probe, 416*ecb23f2eSDmitry Baryshkov .remove = mdss_remove, 417*ecb23f2eSDmitry Baryshkov .shutdown = msm_drv_shutdown, 418*ecb23f2eSDmitry Baryshkov .driver = { 419*ecb23f2eSDmitry Baryshkov .name = "msm-mdss", 420*ecb23f2eSDmitry Baryshkov .of_match_table = mdss_dt_match, 421*ecb23f2eSDmitry Baryshkov .pm = &mdss_pm_ops, 422*ecb23f2eSDmitry Baryshkov }, 423*ecb23f2eSDmitry Baryshkov }; 424*ecb23f2eSDmitry Baryshkov 425*ecb23f2eSDmitry Baryshkov void __init msm_mdss_register(void) 426*ecb23f2eSDmitry Baryshkov { 427*ecb23f2eSDmitry Baryshkov platform_driver_register(&mdss_platform_driver); 428*ecb23f2eSDmitry Baryshkov } 429*ecb23f2eSDmitry Baryshkov 430*ecb23f2eSDmitry Baryshkov void __exit msm_mdss_unregister(void) 431*ecb23f2eSDmitry Baryshkov { 432*ecb23f2eSDmitry Baryshkov platform_driver_unregister(&mdss_platform_driver); 433*ecb23f2eSDmitry Baryshkov } 434