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> 73e9c146fSBjorn Andersson #include <linux/delay.h> 8b9364eedSDouglas Anderson #include <linux/interconnect.h> 987729e2aSDmitry Baryshkov #include <linux/irq.h> 1087729e2aSDmitry Baryshkov #include <linux/irqchip.h> 1187729e2aSDmitry Baryshkov #include <linux/irqdesc.h> 1287729e2aSDmitry Baryshkov #include <linux/irqchip/chained_irq.h> 13722d4f06SRob Herring #include <linux/of_platform.h> 14722d4f06SRob Herring #include <linux/platform_device.h> 15e1072257SDmitry Baryshkov #include <linux/pm_runtime.h> 163e9c146fSBjorn Andersson #include <linux/reset.h> 1787729e2aSDmitry Baryshkov 1871e00fc0SDmitry Baryshkov #include "msm_mdss.h" 19ecb23f2eSDmitry Baryshkov #include "msm_kms.h" 20ecb23f2eSDmitry Baryshkov 2187729e2aSDmitry Baryshkov #define HW_REV 0x0 2287729e2aSDmitry Baryshkov #define HW_INTR_STATUS 0x0010 2387729e2aSDmitry Baryshkov 2492bab914SDmitry Baryshkov #define UBWC_DEC_HW_VERSION 0x58 2587729e2aSDmitry Baryshkov #define UBWC_STATIC 0x144 2687729e2aSDmitry Baryshkov #define UBWC_CTRL_2 0x150 2787729e2aSDmitry Baryshkov #define UBWC_PREDICTION_MODE 0x154 2887729e2aSDmitry Baryshkov 29b9364eedSDouglas Anderson #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ 30b9364eedSDouglas Anderson 31aba75693SDmitry Baryshkov #define DEFAULT_REG_BW 153600 /* Used in mdss fbdev driver */ 32aba75693SDmitry Baryshkov 33e1072257SDmitry Baryshkov struct msm_mdss { 34e1072257SDmitry Baryshkov struct device *dev; 35e1072257SDmitry Baryshkov 3687729e2aSDmitry Baryshkov void __iomem *mmio; 3787729e2aSDmitry Baryshkov struct clk_bulk_data *clocks; 3887729e2aSDmitry Baryshkov size_t num_clocks; 3987729e2aSDmitry Baryshkov bool is_mdp5; 4087729e2aSDmitry Baryshkov struct { 4187729e2aSDmitry Baryshkov unsigned long enabled_mask; 4287729e2aSDmitry Baryshkov struct irq_domain *domain; 4387729e2aSDmitry Baryshkov } irq_controller; 44d68db606SDmitry Baryshkov const struct msm_mdss_data *mdss_data; 45707601fcSKonrad Dybcio struct icc_path *mdp_path[2]; 46707601fcSKonrad Dybcio u32 num_mdp_paths; 47aba75693SDmitry Baryshkov struct icc_path *reg_bus_path; 4887729e2aSDmitry Baryshkov }; 4987729e2aSDmitry Baryshkov 50b9364eedSDouglas Anderson static int msm_mdss_parse_data_bus_icc_path(struct device *dev, 51b9364eedSDouglas Anderson struct msm_mdss *msm_mdss) 52b9364eedSDouglas Anderson { 5345dac135SMiaoqian Lin struct icc_path *path0; 5445dac135SMiaoqian Lin struct icc_path *path1; 55aba75693SDmitry Baryshkov struct icc_path *reg_bus_path; 56b9364eedSDouglas Anderson 579611899fSDmitry Baryshkov path0 = devm_of_icc_get(dev, "mdp0-mem"); 58b9364eedSDouglas Anderson if (IS_ERR_OR_NULL(path0)) 59b9364eedSDouglas Anderson return PTR_ERR_OR_ZERO(path0); 60b9364eedSDouglas Anderson 61707601fcSKonrad Dybcio msm_mdss->mdp_path[0] = path0; 62707601fcSKonrad Dybcio msm_mdss->num_mdp_paths = 1; 63b9364eedSDouglas Anderson 649611899fSDmitry Baryshkov path1 = devm_of_icc_get(dev, "mdp1-mem"); 65b9364eedSDouglas Anderson if (!IS_ERR_OR_NULL(path1)) { 66707601fcSKonrad Dybcio msm_mdss->mdp_path[1] = path1; 67707601fcSKonrad Dybcio msm_mdss->num_mdp_paths++; 68b9364eedSDouglas Anderson } 69b9364eedSDouglas Anderson 70aba75693SDmitry Baryshkov reg_bus_path = of_icc_get(dev, "cpu-cfg"); 71aba75693SDmitry Baryshkov if (!IS_ERR_OR_NULL(reg_bus_path)) 72aba75693SDmitry Baryshkov msm_mdss->reg_bus_path = reg_bus_path; 73aba75693SDmitry Baryshkov 74b9364eedSDouglas Anderson return 0; 75b9364eedSDouglas Anderson } 76b9364eedSDouglas Anderson 77b9364eedSDouglas Anderson static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) 78b9364eedSDouglas Anderson { 79b9364eedSDouglas Anderson int i; 80b9364eedSDouglas Anderson 81707601fcSKonrad Dybcio for (i = 0; i < msm_mdss->num_mdp_paths; i++) 82707601fcSKonrad Dybcio icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(bw)); 83b9364eedSDouglas Anderson } 84b9364eedSDouglas Anderson 8587729e2aSDmitry Baryshkov static void msm_mdss_irq(struct irq_desc *desc) 8687729e2aSDmitry Baryshkov { 87e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc); 8887729e2aSDmitry Baryshkov struct irq_chip *chip = irq_desc_get_chip(desc); 8987729e2aSDmitry Baryshkov u32 interrupts; 9087729e2aSDmitry Baryshkov 9187729e2aSDmitry Baryshkov chained_irq_enter(chip, desc); 9287729e2aSDmitry Baryshkov 93e1072257SDmitry Baryshkov interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS); 9487729e2aSDmitry Baryshkov 9587729e2aSDmitry Baryshkov while (interrupts) { 9687729e2aSDmitry Baryshkov irq_hw_number_t hwirq = fls(interrupts) - 1; 9787729e2aSDmitry Baryshkov int rc; 9887729e2aSDmitry Baryshkov 99e1072257SDmitry Baryshkov rc = generic_handle_domain_irq(msm_mdss->irq_controller.domain, 10087729e2aSDmitry Baryshkov hwirq); 10187729e2aSDmitry Baryshkov if (rc < 0) { 102e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "handle irq fail: irq=%lu rc=%d\n", 10387729e2aSDmitry Baryshkov hwirq, rc); 10487729e2aSDmitry Baryshkov break; 10587729e2aSDmitry Baryshkov } 10687729e2aSDmitry Baryshkov 10787729e2aSDmitry Baryshkov interrupts &= ~(1 << hwirq); 10887729e2aSDmitry Baryshkov } 10987729e2aSDmitry Baryshkov 11087729e2aSDmitry Baryshkov chained_irq_exit(chip, desc); 11187729e2aSDmitry Baryshkov } 11287729e2aSDmitry Baryshkov 11387729e2aSDmitry Baryshkov static void msm_mdss_irq_mask(struct irq_data *irqd) 11487729e2aSDmitry Baryshkov { 115e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 11687729e2aSDmitry Baryshkov 11787729e2aSDmitry Baryshkov /* memory barrier */ 11887729e2aSDmitry Baryshkov smp_mb__before_atomic(); 119e1072257SDmitry Baryshkov clear_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 12087729e2aSDmitry Baryshkov /* memory barrier */ 12187729e2aSDmitry Baryshkov smp_mb__after_atomic(); 12287729e2aSDmitry Baryshkov } 12387729e2aSDmitry Baryshkov 12487729e2aSDmitry Baryshkov static void msm_mdss_irq_unmask(struct irq_data *irqd) 12587729e2aSDmitry Baryshkov { 126e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 12787729e2aSDmitry Baryshkov 12887729e2aSDmitry Baryshkov /* memory barrier */ 12987729e2aSDmitry Baryshkov smp_mb__before_atomic(); 130e1072257SDmitry Baryshkov set_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 13187729e2aSDmitry Baryshkov /* memory barrier */ 13287729e2aSDmitry Baryshkov smp_mb__after_atomic(); 13387729e2aSDmitry Baryshkov } 13487729e2aSDmitry Baryshkov 13587729e2aSDmitry Baryshkov static struct irq_chip msm_mdss_irq_chip = { 136e1072257SDmitry Baryshkov .name = "msm_mdss", 13787729e2aSDmitry Baryshkov .irq_mask = msm_mdss_irq_mask, 13887729e2aSDmitry Baryshkov .irq_unmask = msm_mdss_irq_unmask, 13987729e2aSDmitry Baryshkov }; 14087729e2aSDmitry Baryshkov 14187729e2aSDmitry Baryshkov static struct lock_class_key msm_mdss_lock_key, msm_mdss_request_key; 14287729e2aSDmitry Baryshkov 14387729e2aSDmitry Baryshkov static int msm_mdss_irqdomain_map(struct irq_domain *domain, 14487729e2aSDmitry Baryshkov unsigned int irq, irq_hw_number_t hwirq) 14587729e2aSDmitry Baryshkov { 146e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = domain->host_data; 14787729e2aSDmitry Baryshkov 14887729e2aSDmitry Baryshkov irq_set_lockdep_class(irq, &msm_mdss_lock_key, &msm_mdss_request_key); 14987729e2aSDmitry Baryshkov irq_set_chip_and_handler(irq, &msm_mdss_irq_chip, handle_level_irq); 15087729e2aSDmitry Baryshkov 151e1072257SDmitry Baryshkov return irq_set_chip_data(irq, msm_mdss); 15287729e2aSDmitry Baryshkov } 15387729e2aSDmitry Baryshkov 15487729e2aSDmitry Baryshkov static const struct irq_domain_ops msm_mdss_irqdomain_ops = { 15587729e2aSDmitry Baryshkov .map = msm_mdss_irqdomain_map, 15687729e2aSDmitry Baryshkov .xlate = irq_domain_xlate_onecell, 15787729e2aSDmitry Baryshkov }; 15887729e2aSDmitry Baryshkov 159e1072257SDmitry Baryshkov static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss) 16087729e2aSDmitry Baryshkov { 16187729e2aSDmitry Baryshkov struct device *dev; 16287729e2aSDmitry Baryshkov struct irq_domain *domain; 16387729e2aSDmitry Baryshkov 164e1072257SDmitry Baryshkov dev = msm_mdss->dev; 16587729e2aSDmitry Baryshkov 16687729e2aSDmitry Baryshkov domain = irq_domain_add_linear(dev->of_node, 32, 167e1072257SDmitry Baryshkov &msm_mdss_irqdomain_ops, msm_mdss); 16887729e2aSDmitry Baryshkov if (!domain) { 169e1072257SDmitry Baryshkov dev_err(dev, "failed to add irq_domain\n"); 17087729e2aSDmitry Baryshkov return -EINVAL; 17187729e2aSDmitry Baryshkov } 17287729e2aSDmitry Baryshkov 173e1072257SDmitry Baryshkov msm_mdss->irq_controller.enabled_mask = 0; 174e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = domain; 17587729e2aSDmitry Baryshkov 17687729e2aSDmitry Baryshkov return 0; 17787729e2aSDmitry Baryshkov } 17887729e2aSDmitry Baryshkov 179d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss) 18092bab914SDmitry Baryshkov { 181d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 182d68db606SDmitry Baryshkov 183d68db606SDmitry Baryshkov writel_relaxed(data->ubwc_static, msm_mdss->mmio + UBWC_STATIC); 18492bab914SDmitry Baryshkov } 18592bab914SDmitry Baryshkov 186d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss) 18792bab914SDmitry Baryshkov { 188d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 189d68db606SDmitry Baryshkov u32 value = (data->ubwc_swizzle & 0x1) | 190d68db606SDmitry Baryshkov (data->highest_bank_bit & 0x3) << 4 | 191d68db606SDmitry Baryshkov (data->macrotile_mode & 0x1) << 12; 19292bab914SDmitry Baryshkov 193cab5b406SDmitry Baryshkov if (data->ubwc_enc_version == UBWC_3_0) 19492bab914SDmitry Baryshkov value |= BIT(10); 19592bab914SDmitry Baryshkov 196cab5b406SDmitry Baryshkov if (data->ubwc_enc_version == UBWC_1_0) 19792bab914SDmitry Baryshkov value |= BIT(8); 19892bab914SDmitry Baryshkov 19992bab914SDmitry Baryshkov writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); 20092bab914SDmitry Baryshkov } 20192bab914SDmitry Baryshkov 202d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss) 20392bab914SDmitry Baryshkov { 204d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 205d68db606SDmitry Baryshkov u32 value = (data->ubwc_swizzle & 0x7) | 206d68db606SDmitry Baryshkov (data->ubwc_static & 0x1) << 3 | 207d68db606SDmitry Baryshkov (data->highest_bank_bit & 0x7) << 4 | 208d68db606SDmitry Baryshkov (data->macrotile_mode & 0x1) << 12; 20992bab914SDmitry Baryshkov 21092bab914SDmitry Baryshkov writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); 21192bab914SDmitry Baryshkov 212cab5b406SDmitry Baryshkov if (data->ubwc_enc_version == UBWC_3_0) { 21392bab914SDmitry Baryshkov writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2); 21492bab914SDmitry Baryshkov writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE); 21592bab914SDmitry Baryshkov } else { 216a85c238cSDmitry Baryshkov if (data->ubwc_dec_version == UBWC_4_3) 217a85c238cSDmitry Baryshkov writel_relaxed(3, msm_mdss->mmio + UBWC_CTRL_2); 218a85c238cSDmitry Baryshkov else 21992bab914SDmitry Baryshkov writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); 22092bab914SDmitry Baryshkov writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); 22192bab914SDmitry Baryshkov } 22292bab914SDmitry Baryshkov } 22392bab914SDmitry Baryshkov 22471e00fc0SDmitry Baryshkov const struct msm_mdss_data *msm_mdss_get_mdss_data(struct device *dev) 22571e00fc0SDmitry Baryshkov { 22671e00fc0SDmitry Baryshkov struct msm_mdss *mdss; 22771e00fc0SDmitry Baryshkov 22871e00fc0SDmitry Baryshkov if (!dev) 22971e00fc0SDmitry Baryshkov return ERR_PTR(-EINVAL); 23071e00fc0SDmitry Baryshkov 23171e00fc0SDmitry Baryshkov mdss = dev_get_drvdata(dev); 23271e00fc0SDmitry Baryshkov 23371e00fc0SDmitry Baryshkov return mdss->mdss_data; 23471e00fc0SDmitry Baryshkov } 23571e00fc0SDmitry Baryshkov 236ecb23f2eSDmitry Baryshkov static int msm_mdss_enable(struct msm_mdss *msm_mdss) 23787729e2aSDmitry Baryshkov { 23887729e2aSDmitry Baryshkov int ret; 23987729e2aSDmitry Baryshkov 240b9364eedSDouglas Anderson /* 241b9364eedSDouglas Anderson * Several components have AXI clocks that can only be turned on if 242b9364eedSDouglas Anderson * the interconnect is enabled (non-zero bandwidth). Let's make sure 243b9364eedSDouglas Anderson * that the interconnects are at least at a minimum amount. 244b9364eedSDouglas Anderson */ 245b9364eedSDouglas Anderson msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW); 246b9364eedSDouglas Anderson 247aba75693SDmitry Baryshkov if (msm_mdss->mdss_data && msm_mdss->mdss_data->reg_bus_bw) 248aba75693SDmitry Baryshkov icc_set_bw(msm_mdss->reg_bus_path, 0, 249aba75693SDmitry Baryshkov msm_mdss->mdss_data->reg_bus_bw); 250aba75693SDmitry Baryshkov else 251aba75693SDmitry Baryshkov icc_set_bw(msm_mdss->reg_bus_path, 0, 252aba75693SDmitry Baryshkov DEFAULT_REG_BW); 253aba75693SDmitry Baryshkov 254e1072257SDmitry Baryshkov ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); 25587729e2aSDmitry Baryshkov if (ret) { 256e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); 25787729e2aSDmitry Baryshkov return ret; 25887729e2aSDmitry Baryshkov } 25987729e2aSDmitry Baryshkov 26087729e2aSDmitry Baryshkov /* 261d68db606SDmitry Baryshkov * Register access requires MDSS_MDP_CLK, which is not enabled by the 262d68db606SDmitry Baryshkov * mdss on mdp5 hardware. Skip it for now. 26387729e2aSDmitry Baryshkov */ 264d68db606SDmitry Baryshkov if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data) 26587729e2aSDmitry Baryshkov return 0; 26687729e2aSDmitry Baryshkov 26787729e2aSDmitry Baryshkov /* 26887729e2aSDmitry Baryshkov * ubwc config is part of the "mdss" region which is not accessible 26987729e2aSDmitry Baryshkov * from the rest of the driver. hardcode known configurations here 27092bab914SDmitry Baryshkov * 27192bab914SDmitry Baryshkov * Decoder version can be read from the UBWC_DEC_HW_VERSION reg, 272d68db606SDmitry Baryshkov * UBWC_n and the rest of params comes from hw data. 27387729e2aSDmitry Baryshkov */ 274d68db606SDmitry Baryshkov switch (msm_mdss->mdss_data->ubwc_dec_version) { 2756f410b24SDmitry Baryshkov case 0: /* no UBWC */ 2766f410b24SDmitry Baryshkov case UBWC_1_0: 2776f410b24SDmitry Baryshkov /* do nothing */ 2786f410b24SDmitry Baryshkov break; 279d68db606SDmitry Baryshkov case UBWC_2_0: 280d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_20(msm_mdss); 28187729e2aSDmitry Baryshkov break; 282d68db606SDmitry Baryshkov case UBWC_3_0: 283d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_30(msm_mdss); 28487729e2aSDmitry Baryshkov break; 285d68db606SDmitry Baryshkov case UBWC_4_0: 286a85c238cSDmitry Baryshkov case UBWC_4_3: 287d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_40(msm_mdss); 28887729e2aSDmitry Baryshkov break; 289d68db606SDmitry Baryshkov default: 2906ec59381SColin Ian King dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n", 291d68db606SDmitry Baryshkov msm_mdss->mdss_data->ubwc_dec_version); 292d68db606SDmitry Baryshkov dev_err(msm_mdss->dev, "HW_REV: 0x%x\n", 293d68db606SDmitry Baryshkov readl_relaxed(msm_mdss->mmio + HW_REV)); 294d68db606SDmitry Baryshkov dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n", 295d68db606SDmitry Baryshkov readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION)); 29680056d9aSDmitry Baryshkov break; 29787729e2aSDmitry Baryshkov } 29887729e2aSDmitry Baryshkov 29987729e2aSDmitry Baryshkov return ret; 30087729e2aSDmitry Baryshkov } 30187729e2aSDmitry Baryshkov 302ecb23f2eSDmitry Baryshkov static int msm_mdss_disable(struct msm_mdss *msm_mdss) 30387729e2aSDmitry Baryshkov { 304e1072257SDmitry Baryshkov clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); 305b9364eedSDouglas Anderson msm_mdss_icc_request_bw(msm_mdss, 0); 30687729e2aSDmitry Baryshkov 307aba75693SDmitry Baryshkov if (msm_mdss->reg_bus_path) 308aba75693SDmitry Baryshkov icc_set_bw(msm_mdss->reg_bus_path, 0, 0); 309aba75693SDmitry Baryshkov 31087729e2aSDmitry Baryshkov return 0; 31187729e2aSDmitry Baryshkov } 31287729e2aSDmitry Baryshkov 313ecb23f2eSDmitry Baryshkov static void msm_mdss_destroy(struct msm_mdss *msm_mdss) 31487729e2aSDmitry Baryshkov { 315e1072257SDmitry Baryshkov struct platform_device *pdev = to_platform_device(msm_mdss->dev); 31687729e2aSDmitry Baryshkov int irq; 31787729e2aSDmitry Baryshkov 318e1072257SDmitry Baryshkov pm_runtime_suspend(msm_mdss->dev); 319e1072257SDmitry Baryshkov pm_runtime_disable(msm_mdss->dev); 320e1072257SDmitry Baryshkov irq_domain_remove(msm_mdss->irq_controller.domain); 321e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = NULL; 32287729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 32387729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, NULL, NULL); 32487729e2aSDmitry Baryshkov } 32587729e2aSDmitry Baryshkov 3263e9c146fSBjorn Andersson static int msm_mdss_reset(struct device *dev) 3273e9c146fSBjorn Andersson { 3283e9c146fSBjorn Andersson struct reset_control *reset; 3293e9c146fSBjorn Andersson 3303e9c146fSBjorn Andersson reset = reset_control_get_optional_exclusive(dev, NULL); 3313e9c146fSBjorn Andersson if (!reset) { 3323e9c146fSBjorn Andersson /* Optional reset not specified */ 3333e9c146fSBjorn Andersson return 0; 3343e9c146fSBjorn Andersson } else if (IS_ERR(reset)) { 3353e9c146fSBjorn Andersson return dev_err_probe(dev, PTR_ERR(reset), 3363e9c146fSBjorn Andersson "failed to acquire mdss reset\n"); 3373e9c146fSBjorn Andersson } 3383e9c146fSBjorn Andersson 3393e9c146fSBjorn Andersson reset_control_assert(reset); 3403e9c146fSBjorn Andersson /* 3413e9c146fSBjorn Andersson * Tests indicate that reset has to be held for some period of time, 3423e9c146fSBjorn Andersson * make it one frame in a typical system 3433e9c146fSBjorn Andersson */ 3443e9c146fSBjorn Andersson msleep(20); 3453e9c146fSBjorn Andersson reset_control_deassert(reset); 3463e9c146fSBjorn Andersson 3473e9c146fSBjorn Andersson reset_control_put(reset); 3483e9c146fSBjorn Andersson 3493e9c146fSBjorn Andersson return 0; 3503e9c146fSBjorn Andersson } 3513e9c146fSBjorn Andersson 35287729e2aSDmitry Baryshkov /* 35387729e2aSDmitry Baryshkov * MDP5 MDSS uses at most three specified clocks. 35487729e2aSDmitry Baryshkov */ 35587729e2aSDmitry Baryshkov #define MDP5_MDSS_NUM_CLOCKS 3 35687729e2aSDmitry Baryshkov static int mdp5_mdss_parse_clock(struct platform_device *pdev, struct clk_bulk_data **clocks) 35787729e2aSDmitry Baryshkov { 35887729e2aSDmitry Baryshkov struct clk_bulk_data *bulk; 35987729e2aSDmitry Baryshkov int num_clocks = 0; 36087729e2aSDmitry Baryshkov int ret; 36187729e2aSDmitry Baryshkov 36287729e2aSDmitry Baryshkov if (!pdev) 36387729e2aSDmitry Baryshkov return -EINVAL; 36487729e2aSDmitry Baryshkov 36587729e2aSDmitry Baryshkov bulk = devm_kcalloc(&pdev->dev, MDP5_MDSS_NUM_CLOCKS, sizeof(struct clk_bulk_data), GFP_KERNEL); 36687729e2aSDmitry Baryshkov if (!bulk) 36787729e2aSDmitry Baryshkov return -ENOMEM; 36887729e2aSDmitry Baryshkov 36987729e2aSDmitry Baryshkov bulk[num_clocks++].id = "iface"; 37087729e2aSDmitry Baryshkov bulk[num_clocks++].id = "bus"; 37187729e2aSDmitry Baryshkov bulk[num_clocks++].id = "vsync"; 37287729e2aSDmitry Baryshkov 37387729e2aSDmitry Baryshkov ret = devm_clk_bulk_get_optional(&pdev->dev, num_clocks, bulk); 37487729e2aSDmitry Baryshkov if (ret) 37587729e2aSDmitry Baryshkov return ret; 37687729e2aSDmitry Baryshkov 37787729e2aSDmitry Baryshkov *clocks = bulk; 37887729e2aSDmitry Baryshkov 37987729e2aSDmitry Baryshkov return num_clocks; 38087729e2aSDmitry Baryshkov } 38187729e2aSDmitry Baryshkov 382ecb23f2eSDmitry Baryshkov static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5) 38387729e2aSDmitry Baryshkov { 384e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss; 38587729e2aSDmitry Baryshkov int ret; 38687729e2aSDmitry Baryshkov int irq; 38787729e2aSDmitry Baryshkov 3883e9c146fSBjorn Andersson ret = msm_mdss_reset(&pdev->dev); 3893e9c146fSBjorn Andersson if (ret) 3903e9c146fSBjorn Andersson return ERR_PTR(ret); 3913e9c146fSBjorn Andersson 392e1072257SDmitry Baryshkov msm_mdss = devm_kzalloc(&pdev->dev, sizeof(*msm_mdss), GFP_KERNEL); 393e1072257SDmitry Baryshkov if (!msm_mdss) 394e1072257SDmitry Baryshkov return ERR_PTR(-ENOMEM); 39587729e2aSDmitry Baryshkov 396aba75693SDmitry Baryshkov msm_mdss->mdss_data = of_device_get_match_data(&pdev->dev); 397aba75693SDmitry Baryshkov 398e1072257SDmitry Baryshkov msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); 399e1072257SDmitry Baryshkov if (IS_ERR(msm_mdss->mmio)) 400e1072257SDmitry Baryshkov return ERR_CAST(msm_mdss->mmio); 40187729e2aSDmitry Baryshkov 402e1072257SDmitry Baryshkov dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); 40387729e2aSDmitry Baryshkov 404b9364eedSDouglas Anderson ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); 405b9364eedSDouglas Anderson if (ret) 406b9364eedSDouglas Anderson return ERR_PTR(ret); 407b9364eedSDouglas Anderson 40887729e2aSDmitry Baryshkov if (is_mdp5) 409e1072257SDmitry Baryshkov ret = mdp5_mdss_parse_clock(pdev, &msm_mdss->clocks); 41087729e2aSDmitry Baryshkov else 411e1072257SDmitry Baryshkov ret = devm_clk_bulk_get_all(&pdev->dev, &msm_mdss->clocks); 41287729e2aSDmitry Baryshkov if (ret < 0) { 413e1072257SDmitry Baryshkov dev_err(&pdev->dev, "failed to parse clocks, ret=%d\n", ret); 414e1072257SDmitry Baryshkov return ERR_PTR(ret); 41587729e2aSDmitry Baryshkov } 416e1072257SDmitry Baryshkov msm_mdss->num_clocks = ret; 417e1072257SDmitry Baryshkov msm_mdss->is_mdp5 = is_mdp5; 41887729e2aSDmitry Baryshkov 419e1072257SDmitry Baryshkov msm_mdss->dev = &pdev->dev; 42087729e2aSDmitry Baryshkov 42187729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 42287729e2aSDmitry Baryshkov if (irq < 0) 423e1072257SDmitry Baryshkov return ERR_PTR(irq); 42487729e2aSDmitry Baryshkov 425e1072257SDmitry Baryshkov ret = _msm_mdss_irq_domain_add(msm_mdss); 42687729e2aSDmitry Baryshkov if (ret) 427e1072257SDmitry Baryshkov return ERR_PTR(ret); 42887729e2aSDmitry Baryshkov 42987729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, msm_mdss_irq, 430e1072257SDmitry Baryshkov msm_mdss); 43187729e2aSDmitry Baryshkov 43287729e2aSDmitry Baryshkov pm_runtime_enable(&pdev->dev); 43387729e2aSDmitry Baryshkov 434e1072257SDmitry Baryshkov return msm_mdss; 43587729e2aSDmitry Baryshkov } 436ecb23f2eSDmitry Baryshkov 437ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_suspend(struct device *dev) 438ecb23f2eSDmitry Baryshkov { 4396874f48bSDmitry Baryshkov struct msm_mdss *mdss = dev_get_drvdata(dev); 440ecb23f2eSDmitry Baryshkov 441ecb23f2eSDmitry Baryshkov DBG(""); 442ecb23f2eSDmitry Baryshkov 4436874f48bSDmitry Baryshkov return msm_mdss_disable(mdss); 444ecb23f2eSDmitry Baryshkov } 445ecb23f2eSDmitry Baryshkov 446ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_resume(struct device *dev) 447ecb23f2eSDmitry Baryshkov { 4486874f48bSDmitry Baryshkov struct msm_mdss *mdss = dev_get_drvdata(dev); 449ecb23f2eSDmitry Baryshkov 450ecb23f2eSDmitry Baryshkov DBG(""); 451ecb23f2eSDmitry Baryshkov 4526874f48bSDmitry Baryshkov return msm_mdss_enable(mdss); 453ecb23f2eSDmitry Baryshkov } 454ecb23f2eSDmitry Baryshkov 455ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_suspend(struct device *dev) 456ecb23f2eSDmitry Baryshkov { 457ecb23f2eSDmitry Baryshkov 458ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 459ecb23f2eSDmitry Baryshkov return 0; 460ecb23f2eSDmitry Baryshkov 461ecb23f2eSDmitry Baryshkov return mdss_runtime_suspend(dev); 462ecb23f2eSDmitry Baryshkov } 463ecb23f2eSDmitry Baryshkov 464ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_resume(struct device *dev) 465ecb23f2eSDmitry Baryshkov { 466ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 467ecb23f2eSDmitry Baryshkov return 0; 468ecb23f2eSDmitry Baryshkov 469ecb23f2eSDmitry Baryshkov return mdss_runtime_resume(dev); 470ecb23f2eSDmitry Baryshkov } 471ecb23f2eSDmitry Baryshkov 472ecb23f2eSDmitry Baryshkov static const struct dev_pm_ops mdss_pm_ops = { 473ecb23f2eSDmitry Baryshkov SET_SYSTEM_SLEEP_PM_OPS(mdss_pm_suspend, mdss_pm_resume) 474ecb23f2eSDmitry Baryshkov SET_RUNTIME_PM_OPS(mdss_runtime_suspend, mdss_runtime_resume, NULL) 475ecb23f2eSDmitry Baryshkov }; 476ecb23f2eSDmitry Baryshkov 477ecb23f2eSDmitry Baryshkov static int mdss_probe(struct platform_device *pdev) 478ecb23f2eSDmitry Baryshkov { 479ecb23f2eSDmitry Baryshkov struct msm_mdss *mdss; 4805d44531bSDmitry Baryshkov bool is_mdp5 = of_device_is_compatible(pdev->dev.of_node, "qcom,mdss"); 481ecb23f2eSDmitry Baryshkov struct device *dev = &pdev->dev; 482ecb23f2eSDmitry Baryshkov int ret; 483ecb23f2eSDmitry Baryshkov 4845d44531bSDmitry Baryshkov mdss = msm_mdss_init(pdev, is_mdp5); 485ecb23f2eSDmitry Baryshkov if (IS_ERR(mdss)) 486ecb23f2eSDmitry Baryshkov return PTR_ERR(mdss); 487ecb23f2eSDmitry Baryshkov 4886874f48bSDmitry Baryshkov platform_set_drvdata(pdev, mdss); 489ecb23f2eSDmitry Baryshkov 490ecb23f2eSDmitry Baryshkov /* 491ecb23f2eSDmitry Baryshkov * MDP5/DPU based devices don't have a flat hierarchy. There is a top 492ecb23f2eSDmitry Baryshkov * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc. 493ecb23f2eSDmitry Baryshkov * Populate the children devices, find the MDP5/DPU node, and then add 494ecb23f2eSDmitry Baryshkov * the interfaces to our components list. 495ecb23f2eSDmitry Baryshkov */ 496ecb23f2eSDmitry Baryshkov ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 497ecb23f2eSDmitry Baryshkov if (ret) { 498ecb23f2eSDmitry Baryshkov DRM_DEV_ERROR(dev, "failed to populate children devices\n"); 4996874f48bSDmitry Baryshkov msm_mdss_destroy(mdss); 5006874f48bSDmitry Baryshkov return ret; 501ecb23f2eSDmitry Baryshkov } 502ecb23f2eSDmitry Baryshkov 503ecb23f2eSDmitry Baryshkov return 0; 504ecb23f2eSDmitry Baryshkov } 505ecb23f2eSDmitry Baryshkov 506ecb23f2eSDmitry Baryshkov static int mdss_remove(struct platform_device *pdev) 507ecb23f2eSDmitry Baryshkov { 5086874f48bSDmitry Baryshkov struct msm_mdss *mdss = platform_get_drvdata(pdev); 509ecb23f2eSDmitry Baryshkov 510ecb23f2eSDmitry Baryshkov of_platform_depopulate(&pdev->dev); 511ecb23f2eSDmitry Baryshkov 512ecb23f2eSDmitry Baryshkov msm_mdss_destroy(mdss); 513ecb23f2eSDmitry Baryshkov 514ecb23f2eSDmitry Baryshkov return 0; 515ecb23f2eSDmitry Baryshkov } 516ecb23f2eSDmitry Baryshkov 5176f410b24SDmitry Baryshkov static const struct msm_mdss_data msm8998_data = { 5186f410b24SDmitry Baryshkov .ubwc_enc_version = UBWC_1_0, 5196f410b24SDmitry Baryshkov .ubwc_dec_version = UBWC_1_0, 520c0666d1dSDmitry Baryshkov .highest_bank_bit = 2, 521aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 5226f410b24SDmitry Baryshkov }; 5236f410b24SDmitry Baryshkov 5246f410b24SDmitry Baryshkov static const struct msm_mdss_data qcm2290_data = { 5256f410b24SDmitry Baryshkov /* no UBWC */ 5266f410b24SDmitry Baryshkov .highest_bank_bit = 0x2, 527aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 5286f410b24SDmitry Baryshkov }; 5296f410b24SDmitry Baryshkov 530d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7180_data = { 531cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_2_0, 532d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 533d68db606SDmitry Baryshkov .ubwc_static = 0x1e, 53488c232fdSAbhinav Kumar .highest_bank_bit = 0x1, 535aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 536d68db606SDmitry Baryshkov }; 537d68db606SDmitry Baryshkov 538d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7280_data = { 539cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_3_0, 540d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 541d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 542d68db606SDmitry Baryshkov .ubwc_static = 1, 543d68db606SDmitry Baryshkov .highest_bank_bit = 1, 544d68db606SDmitry Baryshkov .macrotile_mode = 1, 545aba75693SDmitry Baryshkov .reg_bus_bw = 74000, 546d68db606SDmitry Baryshkov }; 547d68db606SDmitry Baryshkov 548aeff6bb5SDmitry Baryshkov static const struct msm_mdss_data sc8180x_data = { 549cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_3_0, 550aeff6bb5SDmitry Baryshkov .ubwc_dec_version = UBWC_3_0, 551aeff6bb5SDmitry Baryshkov .highest_bank_bit = 3, 552aeff6bb5SDmitry Baryshkov .macrotile_mode = 1, 553aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 554aeff6bb5SDmitry Baryshkov }; 555aeff6bb5SDmitry Baryshkov 556d68db606SDmitry Baryshkov static const struct msm_mdss_data sc8280xp_data = { 557cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_4_0, 558d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 559d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 560d68db606SDmitry Baryshkov .ubwc_static = 1, 561d68db606SDmitry Baryshkov .highest_bank_bit = 2, 562d68db606SDmitry Baryshkov .macrotile_mode = 1, 563aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 564d68db606SDmitry Baryshkov }; 565d68db606SDmitry Baryshkov 5669cffae4aSDmitry Baryshkov static const struct msm_mdss_data sdm845_data = { 567cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_2_0, 5689cffae4aSDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 5699cffae4aSDmitry Baryshkov .highest_bank_bit = 2, 570aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 5719cffae4aSDmitry Baryshkov }; 5729cffae4aSDmitry Baryshkov 573c2c1217eSKonrad Dybcio static const struct msm_mdss_data sm6350_data = { 574cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_2_0, 575c2c1217eSKonrad Dybcio .ubwc_dec_version = UBWC_2_0, 576c2c1217eSKonrad Dybcio .ubwc_swizzle = 6, 577c2c1217eSKonrad Dybcio .ubwc_static = 0x1e, 578c2c1217eSKonrad Dybcio .highest_bank_bit = 1, 579aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 580c2c1217eSKonrad Dybcio }; 581c2c1217eSKonrad Dybcio 582d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8150_data = { 583cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_3_0, 584d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_3_0, 585d68db606SDmitry Baryshkov .highest_bank_bit = 2, 586aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 587d68db606SDmitry Baryshkov }; 588d68db606SDmitry Baryshkov 589d68db606SDmitry Baryshkov static const struct msm_mdss_data sm6115_data = { 590cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_1_0, 591d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 592d68db606SDmitry Baryshkov .ubwc_swizzle = 7, 593d68db606SDmitry Baryshkov .ubwc_static = 0x11f, 5946f410b24SDmitry Baryshkov .highest_bank_bit = 0x1, 595aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 596d68db606SDmitry Baryshkov }; 597d68db606SDmitry Baryshkov 59887aa3c9bSMarijn Suijten static const struct msm_mdss_data sm6125_data = { 599cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_1_0, 60087aa3c9bSMarijn Suijten .ubwc_dec_version = UBWC_3_0, 60187aa3c9bSMarijn Suijten .ubwc_swizzle = 1, 60287aa3c9bSMarijn Suijten .highest_bank_bit = 1, 603*ab7554fbSDmitry Baryshkov .reg_bus_bw = 76800, 604d68db606SDmitry Baryshkov }; 605d68db606SDmitry Baryshkov 606d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8250_data = { 607cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_4_0, 608d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 609d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 610d68db606SDmitry Baryshkov .ubwc_static = 1, 611d68db606SDmitry Baryshkov /* TODO: highest_bank_bit = 2 for LP_DDR4 */ 612d68db606SDmitry Baryshkov .highest_bank_bit = 3, 613d68db606SDmitry Baryshkov .macrotile_mode = 1, 614aba75693SDmitry Baryshkov .reg_bus_bw = 76800, 615aba75693SDmitry Baryshkov }; 616aba75693SDmitry Baryshkov 617aba75693SDmitry Baryshkov static const struct msm_mdss_data sm8350_data = { 618aba75693SDmitry Baryshkov .ubwc_enc_version = UBWC_4_0, 619aba75693SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 620aba75693SDmitry Baryshkov .ubwc_swizzle = 6, 621aba75693SDmitry Baryshkov .ubwc_static = 1, 622aba75693SDmitry Baryshkov /* TODO: highest_bank_bit = 2 for LP_DDR4 */ 623aba75693SDmitry Baryshkov .highest_bank_bit = 3, 624aba75693SDmitry Baryshkov .macrotile_mode = 1, 625aba75693SDmitry Baryshkov .reg_bus_bw = 74000, 626d68db606SDmitry Baryshkov }; 627d68db606SDmitry Baryshkov 628a85c238cSDmitry Baryshkov static const struct msm_mdss_data sm8550_data = { 629cab5b406SDmitry Baryshkov .ubwc_enc_version = UBWC_4_0, 630a85c238cSDmitry Baryshkov .ubwc_dec_version = UBWC_4_3, 631a85c238cSDmitry Baryshkov .ubwc_swizzle = 6, 632a85c238cSDmitry Baryshkov .ubwc_static = 1, 633a85c238cSDmitry Baryshkov /* TODO: highest_bank_bit = 2 for LP_DDR4 */ 634a85c238cSDmitry Baryshkov .highest_bank_bit = 3, 635a85c238cSDmitry Baryshkov .macrotile_mode = 1, 636aba75693SDmitry Baryshkov .reg_bus_bw = 57000, 637a85c238cSDmitry Baryshkov }; 638ecb23f2eSDmitry Baryshkov static const struct of_device_id mdss_dt_match[] = { 6395d44531bSDmitry Baryshkov { .compatible = "qcom,mdss" }, 6406f410b24SDmitry Baryshkov { .compatible = "qcom,msm8998-mdss", .data = &msm8998_data }, 6416f410b24SDmitry Baryshkov { .compatible = "qcom,qcm2290-mdss", .data = &qcm2290_data }, 6429cffae4aSDmitry Baryshkov { .compatible = "qcom,sdm845-mdss", .data = &sdm845_data }, 643d68db606SDmitry Baryshkov { .compatible = "qcom,sc7180-mdss", .data = &sc7180_data }, 644d68db606SDmitry Baryshkov { .compatible = "qcom,sc7280-mdss", .data = &sc7280_data }, 645aeff6bb5SDmitry Baryshkov { .compatible = "qcom,sc8180x-mdss", .data = &sc8180x_data }, 646d68db606SDmitry Baryshkov { .compatible = "qcom,sc8280xp-mdss", .data = &sc8280xp_data }, 647d68db606SDmitry Baryshkov { .compatible = "qcom,sm6115-mdss", .data = &sm6115_data }, 64887aa3c9bSMarijn Suijten { .compatible = "qcom,sm6125-mdss", .data = &sm6125_data }, 649c2c1217eSKonrad Dybcio { .compatible = "qcom,sm6350-mdss", .data = &sm6350_data }, 6505ff3d3a0SKonrad Dybcio { .compatible = "qcom,sm6375-mdss", .data = &sm6350_data }, 651d68db606SDmitry Baryshkov { .compatible = "qcom,sm8150-mdss", .data = &sm8150_data }, 652d68db606SDmitry Baryshkov { .compatible = "qcom,sm8250-mdss", .data = &sm8250_data }, 653aba75693SDmitry Baryshkov { .compatible = "qcom,sm8350-mdss", .data = &sm8350_data }, 654aba75693SDmitry Baryshkov { .compatible = "qcom,sm8450-mdss", .data = &sm8350_data }, 655a85c238cSDmitry Baryshkov { .compatible = "qcom,sm8550-mdss", .data = &sm8550_data }, 656ecb23f2eSDmitry Baryshkov {} 657ecb23f2eSDmitry Baryshkov }; 658ecb23f2eSDmitry Baryshkov MODULE_DEVICE_TABLE(of, mdss_dt_match); 659ecb23f2eSDmitry Baryshkov 660ecb23f2eSDmitry Baryshkov static struct platform_driver mdss_platform_driver = { 661ecb23f2eSDmitry Baryshkov .probe = mdss_probe, 662ecb23f2eSDmitry Baryshkov .remove = mdss_remove, 663ecb23f2eSDmitry Baryshkov .driver = { 664ecb23f2eSDmitry Baryshkov .name = "msm-mdss", 665ecb23f2eSDmitry Baryshkov .of_match_table = mdss_dt_match, 666ecb23f2eSDmitry Baryshkov .pm = &mdss_pm_ops, 667ecb23f2eSDmitry Baryshkov }, 668ecb23f2eSDmitry Baryshkov }; 669ecb23f2eSDmitry Baryshkov 670ecb23f2eSDmitry Baryshkov void __init msm_mdss_register(void) 671ecb23f2eSDmitry Baryshkov { 672ecb23f2eSDmitry Baryshkov platform_driver_register(&mdss_platform_driver); 673ecb23f2eSDmitry Baryshkov } 674ecb23f2eSDmitry Baryshkov 675ecb23f2eSDmitry Baryshkov void __exit msm_mdss_unregister(void) 676ecb23f2eSDmitry Baryshkov { 677ecb23f2eSDmitry Baryshkov platform_driver_unregister(&mdss_platform_driver); 678ecb23f2eSDmitry Baryshkov } 679