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> 13e1072257SDmitry Baryshkov #include <linux/pm_runtime.h> 143e9c146fSBjorn Andersson #include <linux/reset.h> 1587729e2aSDmitry Baryshkov 16ecb23f2eSDmitry Baryshkov #include "msm_drv.h" 17ecb23f2eSDmitry Baryshkov #include "msm_kms.h" 18ecb23f2eSDmitry Baryshkov 1987729e2aSDmitry Baryshkov #define HW_REV 0x0 2087729e2aSDmitry Baryshkov #define HW_INTR_STATUS 0x0010 2187729e2aSDmitry Baryshkov 2292bab914SDmitry Baryshkov #define UBWC_DEC_HW_VERSION 0x58 2387729e2aSDmitry Baryshkov #define UBWC_STATIC 0x144 2487729e2aSDmitry Baryshkov #define UBWC_CTRL_2 0x150 2587729e2aSDmitry Baryshkov #define UBWC_PREDICTION_MODE 0x154 2687729e2aSDmitry Baryshkov 27b9364eedSDouglas Anderson #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ 28b9364eedSDouglas Anderson 29d68db606SDmitry Baryshkov struct msm_mdss_data { 30d68db606SDmitry Baryshkov u32 ubwc_version; 31d68db606SDmitry Baryshkov /* can be read from register 0x58 */ 32d68db606SDmitry Baryshkov u32 ubwc_dec_version; 33d68db606SDmitry Baryshkov u32 ubwc_swizzle; 34d68db606SDmitry Baryshkov u32 ubwc_static; 35d68db606SDmitry Baryshkov u32 highest_bank_bit; 36d68db606SDmitry Baryshkov u32 macrotile_mode; 37d68db606SDmitry Baryshkov }; 38d68db606SDmitry Baryshkov 39e1072257SDmitry Baryshkov struct msm_mdss { 40e1072257SDmitry Baryshkov struct device *dev; 41e1072257SDmitry Baryshkov 4287729e2aSDmitry Baryshkov void __iomem *mmio; 4387729e2aSDmitry Baryshkov struct clk_bulk_data *clocks; 4487729e2aSDmitry Baryshkov size_t num_clocks; 4587729e2aSDmitry Baryshkov bool is_mdp5; 4687729e2aSDmitry Baryshkov struct { 4787729e2aSDmitry Baryshkov unsigned long enabled_mask; 4887729e2aSDmitry Baryshkov struct irq_domain *domain; 4987729e2aSDmitry Baryshkov } irq_controller; 50d68db606SDmitry Baryshkov const struct msm_mdss_data *mdss_data; 51b9364eedSDouglas Anderson struct icc_path *path[2]; 52b9364eedSDouglas Anderson u32 num_paths; 5387729e2aSDmitry Baryshkov }; 5487729e2aSDmitry Baryshkov 55b9364eedSDouglas Anderson static int msm_mdss_parse_data_bus_icc_path(struct device *dev, 56b9364eedSDouglas Anderson struct msm_mdss *msm_mdss) 57b9364eedSDouglas Anderson { 5845dac135SMiaoqian Lin struct icc_path *path0; 5945dac135SMiaoqian Lin struct icc_path *path1; 60b9364eedSDouglas Anderson 6145dac135SMiaoqian Lin path0 = of_icc_get(dev, "mdp0-mem"); 62b9364eedSDouglas Anderson if (IS_ERR_OR_NULL(path0)) 63b9364eedSDouglas Anderson return PTR_ERR_OR_ZERO(path0); 64b9364eedSDouglas Anderson 65b9364eedSDouglas Anderson msm_mdss->path[0] = path0; 66b9364eedSDouglas Anderson msm_mdss->num_paths = 1; 67b9364eedSDouglas Anderson 6845dac135SMiaoqian Lin path1 = of_icc_get(dev, "mdp1-mem"); 69b9364eedSDouglas Anderson if (!IS_ERR_OR_NULL(path1)) { 70b9364eedSDouglas Anderson msm_mdss->path[1] = path1; 71b9364eedSDouglas Anderson msm_mdss->num_paths++; 72b9364eedSDouglas Anderson } 73b9364eedSDouglas Anderson 74b9364eedSDouglas Anderson return 0; 75b9364eedSDouglas Anderson } 76b9364eedSDouglas Anderson 77b9364eedSDouglas Anderson static void msm_mdss_put_icc_path(void *data) 78b9364eedSDouglas Anderson { 79b9364eedSDouglas Anderson struct msm_mdss *msm_mdss = data; 80b9364eedSDouglas Anderson int i; 81b9364eedSDouglas Anderson 82b9364eedSDouglas Anderson for (i = 0; i < msm_mdss->num_paths; i++) 83b9364eedSDouglas Anderson icc_put(msm_mdss->path[i]); 84b9364eedSDouglas Anderson } 85b9364eedSDouglas Anderson 86b9364eedSDouglas Anderson static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) 87b9364eedSDouglas Anderson { 88b9364eedSDouglas Anderson int i; 89b9364eedSDouglas Anderson 90b9364eedSDouglas Anderson for (i = 0; i < msm_mdss->num_paths; i++) 91b9364eedSDouglas Anderson icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw)); 92b9364eedSDouglas Anderson } 93b9364eedSDouglas Anderson 9487729e2aSDmitry Baryshkov static void msm_mdss_irq(struct irq_desc *desc) 9587729e2aSDmitry Baryshkov { 96e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc); 9787729e2aSDmitry Baryshkov struct irq_chip *chip = irq_desc_get_chip(desc); 9887729e2aSDmitry Baryshkov u32 interrupts; 9987729e2aSDmitry Baryshkov 10087729e2aSDmitry Baryshkov chained_irq_enter(chip, desc); 10187729e2aSDmitry Baryshkov 102e1072257SDmitry Baryshkov interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS); 10387729e2aSDmitry Baryshkov 10487729e2aSDmitry Baryshkov while (interrupts) { 10587729e2aSDmitry Baryshkov irq_hw_number_t hwirq = fls(interrupts) - 1; 10687729e2aSDmitry Baryshkov int rc; 10787729e2aSDmitry Baryshkov 108e1072257SDmitry Baryshkov rc = generic_handle_domain_irq(msm_mdss->irq_controller.domain, 10987729e2aSDmitry Baryshkov hwirq); 11087729e2aSDmitry Baryshkov if (rc < 0) { 111e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "handle irq fail: irq=%lu rc=%d\n", 11287729e2aSDmitry Baryshkov hwirq, rc); 11387729e2aSDmitry Baryshkov break; 11487729e2aSDmitry Baryshkov } 11587729e2aSDmitry Baryshkov 11687729e2aSDmitry Baryshkov interrupts &= ~(1 << hwirq); 11787729e2aSDmitry Baryshkov } 11887729e2aSDmitry Baryshkov 11987729e2aSDmitry Baryshkov chained_irq_exit(chip, desc); 12087729e2aSDmitry Baryshkov } 12187729e2aSDmitry Baryshkov 12287729e2aSDmitry Baryshkov static void msm_mdss_irq_mask(struct irq_data *irqd) 12387729e2aSDmitry Baryshkov { 124e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 12587729e2aSDmitry Baryshkov 12687729e2aSDmitry Baryshkov /* memory barrier */ 12787729e2aSDmitry Baryshkov smp_mb__before_atomic(); 128e1072257SDmitry Baryshkov clear_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 12987729e2aSDmitry Baryshkov /* memory barrier */ 13087729e2aSDmitry Baryshkov smp_mb__after_atomic(); 13187729e2aSDmitry Baryshkov } 13287729e2aSDmitry Baryshkov 13387729e2aSDmitry Baryshkov static void msm_mdss_irq_unmask(struct irq_data *irqd) 13487729e2aSDmitry Baryshkov { 135e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd); 13687729e2aSDmitry Baryshkov 13787729e2aSDmitry Baryshkov /* memory barrier */ 13887729e2aSDmitry Baryshkov smp_mb__before_atomic(); 139e1072257SDmitry Baryshkov set_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask); 14087729e2aSDmitry Baryshkov /* memory barrier */ 14187729e2aSDmitry Baryshkov smp_mb__after_atomic(); 14287729e2aSDmitry Baryshkov } 14387729e2aSDmitry Baryshkov 14487729e2aSDmitry Baryshkov static struct irq_chip msm_mdss_irq_chip = { 145e1072257SDmitry Baryshkov .name = "msm_mdss", 14687729e2aSDmitry Baryshkov .irq_mask = msm_mdss_irq_mask, 14787729e2aSDmitry Baryshkov .irq_unmask = msm_mdss_irq_unmask, 14887729e2aSDmitry Baryshkov }; 14987729e2aSDmitry Baryshkov 15087729e2aSDmitry Baryshkov static struct lock_class_key msm_mdss_lock_key, msm_mdss_request_key; 15187729e2aSDmitry Baryshkov 15287729e2aSDmitry Baryshkov static int msm_mdss_irqdomain_map(struct irq_domain *domain, 15387729e2aSDmitry Baryshkov unsigned int irq, irq_hw_number_t hwirq) 15487729e2aSDmitry Baryshkov { 155e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss = domain->host_data; 15687729e2aSDmitry Baryshkov 15787729e2aSDmitry Baryshkov irq_set_lockdep_class(irq, &msm_mdss_lock_key, &msm_mdss_request_key); 15887729e2aSDmitry Baryshkov irq_set_chip_and_handler(irq, &msm_mdss_irq_chip, handle_level_irq); 15987729e2aSDmitry Baryshkov 160e1072257SDmitry Baryshkov return irq_set_chip_data(irq, msm_mdss); 16187729e2aSDmitry Baryshkov } 16287729e2aSDmitry Baryshkov 16387729e2aSDmitry Baryshkov static const struct irq_domain_ops msm_mdss_irqdomain_ops = { 16487729e2aSDmitry Baryshkov .map = msm_mdss_irqdomain_map, 16587729e2aSDmitry Baryshkov .xlate = irq_domain_xlate_onecell, 16687729e2aSDmitry Baryshkov }; 16787729e2aSDmitry Baryshkov 168e1072257SDmitry Baryshkov static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss) 16987729e2aSDmitry Baryshkov { 17087729e2aSDmitry Baryshkov struct device *dev; 17187729e2aSDmitry Baryshkov struct irq_domain *domain; 17287729e2aSDmitry Baryshkov 173e1072257SDmitry Baryshkov dev = msm_mdss->dev; 17487729e2aSDmitry Baryshkov 17587729e2aSDmitry Baryshkov domain = irq_domain_add_linear(dev->of_node, 32, 176e1072257SDmitry Baryshkov &msm_mdss_irqdomain_ops, msm_mdss); 17787729e2aSDmitry Baryshkov if (!domain) { 178e1072257SDmitry Baryshkov dev_err(dev, "failed to add irq_domain\n"); 17987729e2aSDmitry Baryshkov return -EINVAL; 18087729e2aSDmitry Baryshkov } 18187729e2aSDmitry Baryshkov 182e1072257SDmitry Baryshkov msm_mdss->irq_controller.enabled_mask = 0; 183e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = domain; 18487729e2aSDmitry Baryshkov 18587729e2aSDmitry Baryshkov return 0; 18687729e2aSDmitry Baryshkov } 18787729e2aSDmitry Baryshkov 18892bab914SDmitry Baryshkov #define UBWC_1_0 0x10000000 18992bab914SDmitry Baryshkov #define UBWC_2_0 0x20000000 19092bab914SDmitry Baryshkov #define UBWC_3_0 0x30000000 19192bab914SDmitry Baryshkov #define UBWC_4_0 0x40000000 19292bab914SDmitry Baryshkov 193d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss) 19492bab914SDmitry Baryshkov { 195d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 196d68db606SDmitry Baryshkov 197d68db606SDmitry Baryshkov writel_relaxed(data->ubwc_static, msm_mdss->mmio + UBWC_STATIC); 19892bab914SDmitry Baryshkov } 19992bab914SDmitry Baryshkov 200d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss) 20192bab914SDmitry Baryshkov { 202d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 203d68db606SDmitry Baryshkov u32 value = (data->ubwc_swizzle & 0x1) | 204d68db606SDmitry Baryshkov (data->highest_bank_bit & 0x3) << 4 | 205d68db606SDmitry Baryshkov (data->macrotile_mode & 0x1) << 12; 20692bab914SDmitry Baryshkov 207d68db606SDmitry Baryshkov if (data->ubwc_version == UBWC_3_0) 20892bab914SDmitry Baryshkov value |= BIT(10); 20992bab914SDmitry Baryshkov 210d68db606SDmitry Baryshkov if (data->ubwc_version == UBWC_1_0) 21192bab914SDmitry Baryshkov value |= BIT(8); 21292bab914SDmitry Baryshkov 21392bab914SDmitry Baryshkov writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); 21492bab914SDmitry Baryshkov } 21592bab914SDmitry Baryshkov 216d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss) 21792bab914SDmitry Baryshkov { 218d68db606SDmitry Baryshkov const struct msm_mdss_data *data = msm_mdss->mdss_data; 219d68db606SDmitry Baryshkov u32 value = (data->ubwc_swizzle & 0x7) | 220d68db606SDmitry Baryshkov (data->ubwc_static & 0x1) << 3 | 221d68db606SDmitry Baryshkov (data->highest_bank_bit & 0x7) << 4 | 222d68db606SDmitry Baryshkov (data->macrotile_mode & 0x1) << 12; 22392bab914SDmitry Baryshkov 22492bab914SDmitry Baryshkov writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); 22592bab914SDmitry Baryshkov 226d68db606SDmitry Baryshkov if (data->ubwc_version == UBWC_3_0) { 22792bab914SDmitry Baryshkov writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2); 22892bab914SDmitry Baryshkov writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE); 22992bab914SDmitry Baryshkov } else { 23092bab914SDmitry Baryshkov writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); 23192bab914SDmitry Baryshkov writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); 23292bab914SDmitry Baryshkov } 23392bab914SDmitry Baryshkov } 23492bab914SDmitry Baryshkov 235ecb23f2eSDmitry Baryshkov static int msm_mdss_enable(struct msm_mdss *msm_mdss) 23687729e2aSDmitry Baryshkov { 23787729e2aSDmitry Baryshkov int ret; 23887729e2aSDmitry Baryshkov 239b9364eedSDouglas Anderson /* 240b9364eedSDouglas Anderson * Several components have AXI clocks that can only be turned on if 241b9364eedSDouglas Anderson * the interconnect is enabled (non-zero bandwidth). Let's make sure 242b9364eedSDouglas Anderson * that the interconnects are at least at a minimum amount. 243b9364eedSDouglas Anderson */ 244b9364eedSDouglas Anderson msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW); 245b9364eedSDouglas Anderson 246e1072257SDmitry Baryshkov ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); 24787729e2aSDmitry Baryshkov if (ret) { 248e1072257SDmitry Baryshkov dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); 24987729e2aSDmitry Baryshkov return ret; 25087729e2aSDmitry Baryshkov } 25187729e2aSDmitry Baryshkov 25287729e2aSDmitry Baryshkov /* 253d68db606SDmitry Baryshkov * Register access requires MDSS_MDP_CLK, which is not enabled by the 254d68db606SDmitry Baryshkov * mdss on mdp5 hardware. Skip it for now. 25587729e2aSDmitry Baryshkov */ 256d68db606SDmitry Baryshkov if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data) 25787729e2aSDmitry Baryshkov return 0; 25887729e2aSDmitry Baryshkov 25987729e2aSDmitry Baryshkov /* 26087729e2aSDmitry Baryshkov * ubwc config is part of the "mdss" region which is not accessible 26187729e2aSDmitry Baryshkov * from the rest of the driver. hardcode known configurations here 26292bab914SDmitry Baryshkov * 26392bab914SDmitry Baryshkov * Decoder version can be read from the UBWC_DEC_HW_VERSION reg, 264d68db606SDmitry Baryshkov * UBWC_n and the rest of params comes from hw data. 26587729e2aSDmitry Baryshkov */ 266d68db606SDmitry Baryshkov switch (msm_mdss->mdss_data->ubwc_dec_version) { 267d68db606SDmitry Baryshkov case UBWC_2_0: 268d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_20(msm_mdss); 26987729e2aSDmitry Baryshkov break; 270d68db606SDmitry Baryshkov case UBWC_3_0: 271d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_30(msm_mdss); 27287729e2aSDmitry Baryshkov break; 273d68db606SDmitry Baryshkov case UBWC_4_0: 274d68db606SDmitry Baryshkov msm_mdss_setup_ubwc_dec_40(msm_mdss); 27587729e2aSDmitry Baryshkov break; 276d68db606SDmitry Baryshkov default: 2776ec59381SColin Ian King dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n", 278d68db606SDmitry Baryshkov msm_mdss->mdss_data->ubwc_dec_version); 279d68db606SDmitry Baryshkov dev_err(msm_mdss->dev, "HW_REV: 0x%x\n", 280d68db606SDmitry Baryshkov readl_relaxed(msm_mdss->mmio + HW_REV)); 281d68db606SDmitry Baryshkov dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n", 282d68db606SDmitry Baryshkov readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION)); 28380056d9aSDmitry Baryshkov break; 28487729e2aSDmitry Baryshkov } 28587729e2aSDmitry Baryshkov 28687729e2aSDmitry Baryshkov return ret; 28787729e2aSDmitry Baryshkov } 28887729e2aSDmitry Baryshkov 289ecb23f2eSDmitry Baryshkov static int msm_mdss_disable(struct msm_mdss *msm_mdss) 29087729e2aSDmitry Baryshkov { 291e1072257SDmitry Baryshkov clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); 292b9364eedSDouglas Anderson msm_mdss_icc_request_bw(msm_mdss, 0); 29387729e2aSDmitry Baryshkov 29487729e2aSDmitry Baryshkov return 0; 29587729e2aSDmitry Baryshkov } 29687729e2aSDmitry Baryshkov 297ecb23f2eSDmitry Baryshkov static void msm_mdss_destroy(struct msm_mdss *msm_mdss) 29887729e2aSDmitry Baryshkov { 299e1072257SDmitry Baryshkov struct platform_device *pdev = to_platform_device(msm_mdss->dev); 30087729e2aSDmitry Baryshkov int irq; 30187729e2aSDmitry Baryshkov 302e1072257SDmitry Baryshkov pm_runtime_suspend(msm_mdss->dev); 303e1072257SDmitry Baryshkov pm_runtime_disable(msm_mdss->dev); 304e1072257SDmitry Baryshkov irq_domain_remove(msm_mdss->irq_controller.domain); 305e1072257SDmitry Baryshkov msm_mdss->irq_controller.domain = NULL; 30687729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 30787729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, NULL, NULL); 30887729e2aSDmitry Baryshkov } 30987729e2aSDmitry Baryshkov 3103e9c146fSBjorn Andersson static int msm_mdss_reset(struct device *dev) 3113e9c146fSBjorn Andersson { 3123e9c146fSBjorn Andersson struct reset_control *reset; 3133e9c146fSBjorn Andersson 3143e9c146fSBjorn Andersson reset = reset_control_get_optional_exclusive(dev, NULL); 3153e9c146fSBjorn Andersson if (!reset) { 3163e9c146fSBjorn Andersson /* Optional reset not specified */ 3173e9c146fSBjorn Andersson return 0; 3183e9c146fSBjorn Andersson } else if (IS_ERR(reset)) { 3193e9c146fSBjorn Andersson return dev_err_probe(dev, PTR_ERR(reset), 3203e9c146fSBjorn Andersson "failed to acquire mdss reset\n"); 3213e9c146fSBjorn Andersson } 3223e9c146fSBjorn Andersson 3233e9c146fSBjorn Andersson reset_control_assert(reset); 3243e9c146fSBjorn Andersson /* 3253e9c146fSBjorn Andersson * Tests indicate that reset has to be held for some period of time, 3263e9c146fSBjorn Andersson * make it one frame in a typical system 3273e9c146fSBjorn Andersson */ 3283e9c146fSBjorn Andersson msleep(20); 3293e9c146fSBjorn Andersson reset_control_deassert(reset); 3303e9c146fSBjorn Andersson 3313e9c146fSBjorn Andersson reset_control_put(reset); 3323e9c146fSBjorn Andersson 3333e9c146fSBjorn Andersson return 0; 3343e9c146fSBjorn Andersson } 3353e9c146fSBjorn Andersson 33687729e2aSDmitry Baryshkov /* 33787729e2aSDmitry Baryshkov * MDP5 MDSS uses at most three specified clocks. 33887729e2aSDmitry Baryshkov */ 33987729e2aSDmitry Baryshkov #define MDP5_MDSS_NUM_CLOCKS 3 34087729e2aSDmitry Baryshkov static int mdp5_mdss_parse_clock(struct platform_device *pdev, struct clk_bulk_data **clocks) 34187729e2aSDmitry Baryshkov { 34287729e2aSDmitry Baryshkov struct clk_bulk_data *bulk; 34387729e2aSDmitry Baryshkov int num_clocks = 0; 34487729e2aSDmitry Baryshkov int ret; 34587729e2aSDmitry Baryshkov 34687729e2aSDmitry Baryshkov if (!pdev) 34787729e2aSDmitry Baryshkov return -EINVAL; 34887729e2aSDmitry Baryshkov 34987729e2aSDmitry Baryshkov bulk = devm_kcalloc(&pdev->dev, MDP5_MDSS_NUM_CLOCKS, sizeof(struct clk_bulk_data), GFP_KERNEL); 35087729e2aSDmitry Baryshkov if (!bulk) 35187729e2aSDmitry Baryshkov return -ENOMEM; 35287729e2aSDmitry Baryshkov 35387729e2aSDmitry Baryshkov bulk[num_clocks++].id = "iface"; 35487729e2aSDmitry Baryshkov bulk[num_clocks++].id = "bus"; 35587729e2aSDmitry Baryshkov bulk[num_clocks++].id = "vsync"; 35687729e2aSDmitry Baryshkov 35787729e2aSDmitry Baryshkov ret = devm_clk_bulk_get_optional(&pdev->dev, num_clocks, bulk); 35887729e2aSDmitry Baryshkov if (ret) 35987729e2aSDmitry Baryshkov return ret; 36087729e2aSDmitry Baryshkov 36187729e2aSDmitry Baryshkov *clocks = bulk; 36287729e2aSDmitry Baryshkov 36387729e2aSDmitry Baryshkov return num_clocks; 36487729e2aSDmitry Baryshkov } 36587729e2aSDmitry Baryshkov 366ecb23f2eSDmitry Baryshkov static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5) 36787729e2aSDmitry Baryshkov { 368e1072257SDmitry Baryshkov struct msm_mdss *msm_mdss; 36987729e2aSDmitry Baryshkov int ret; 37087729e2aSDmitry Baryshkov int irq; 37187729e2aSDmitry Baryshkov 3723e9c146fSBjorn Andersson ret = msm_mdss_reset(&pdev->dev); 3733e9c146fSBjorn Andersson if (ret) 3743e9c146fSBjorn Andersson return ERR_PTR(ret); 3753e9c146fSBjorn Andersson 376e1072257SDmitry Baryshkov msm_mdss = devm_kzalloc(&pdev->dev, sizeof(*msm_mdss), GFP_KERNEL); 377e1072257SDmitry Baryshkov if (!msm_mdss) 378e1072257SDmitry Baryshkov return ERR_PTR(-ENOMEM); 37987729e2aSDmitry Baryshkov 380e1072257SDmitry Baryshkov msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); 381e1072257SDmitry Baryshkov if (IS_ERR(msm_mdss->mmio)) 382e1072257SDmitry Baryshkov return ERR_CAST(msm_mdss->mmio); 38387729e2aSDmitry Baryshkov 384e1072257SDmitry Baryshkov dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); 38587729e2aSDmitry Baryshkov 386b9364eedSDouglas Anderson ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); 387b9364eedSDouglas Anderson if (ret) 388b9364eedSDouglas Anderson return ERR_PTR(ret); 389b9364eedSDouglas Anderson ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss); 390b9364eedSDouglas Anderson if (ret) 391b9364eedSDouglas Anderson return ERR_PTR(ret); 392b9364eedSDouglas Anderson 39387729e2aSDmitry Baryshkov if (is_mdp5) 394e1072257SDmitry Baryshkov ret = mdp5_mdss_parse_clock(pdev, &msm_mdss->clocks); 39587729e2aSDmitry Baryshkov else 396e1072257SDmitry Baryshkov ret = devm_clk_bulk_get_all(&pdev->dev, &msm_mdss->clocks); 39787729e2aSDmitry Baryshkov if (ret < 0) { 398e1072257SDmitry Baryshkov dev_err(&pdev->dev, "failed to parse clocks, ret=%d\n", ret); 399e1072257SDmitry Baryshkov return ERR_PTR(ret); 40087729e2aSDmitry Baryshkov } 401e1072257SDmitry Baryshkov msm_mdss->num_clocks = ret; 402e1072257SDmitry Baryshkov msm_mdss->is_mdp5 = is_mdp5; 40387729e2aSDmitry Baryshkov 404e1072257SDmitry Baryshkov msm_mdss->dev = &pdev->dev; 40587729e2aSDmitry Baryshkov 40687729e2aSDmitry Baryshkov irq = platform_get_irq(pdev, 0); 40787729e2aSDmitry Baryshkov if (irq < 0) 408e1072257SDmitry Baryshkov return ERR_PTR(irq); 40987729e2aSDmitry Baryshkov 410e1072257SDmitry Baryshkov ret = _msm_mdss_irq_domain_add(msm_mdss); 41187729e2aSDmitry Baryshkov if (ret) 412e1072257SDmitry Baryshkov return ERR_PTR(ret); 41387729e2aSDmitry Baryshkov 41487729e2aSDmitry Baryshkov irq_set_chained_handler_and_data(irq, msm_mdss_irq, 415e1072257SDmitry Baryshkov msm_mdss); 41687729e2aSDmitry Baryshkov 41787729e2aSDmitry Baryshkov pm_runtime_enable(&pdev->dev); 41887729e2aSDmitry Baryshkov 419e1072257SDmitry Baryshkov return msm_mdss; 42087729e2aSDmitry Baryshkov } 421ecb23f2eSDmitry Baryshkov 422ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_suspend(struct device *dev) 423ecb23f2eSDmitry Baryshkov { 4246874f48bSDmitry Baryshkov struct msm_mdss *mdss = dev_get_drvdata(dev); 425ecb23f2eSDmitry Baryshkov 426ecb23f2eSDmitry Baryshkov DBG(""); 427ecb23f2eSDmitry Baryshkov 4286874f48bSDmitry Baryshkov return msm_mdss_disable(mdss); 429ecb23f2eSDmitry Baryshkov } 430ecb23f2eSDmitry Baryshkov 431ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_resume(struct device *dev) 432ecb23f2eSDmitry Baryshkov { 4336874f48bSDmitry Baryshkov struct msm_mdss *mdss = dev_get_drvdata(dev); 434ecb23f2eSDmitry Baryshkov 435ecb23f2eSDmitry Baryshkov DBG(""); 436ecb23f2eSDmitry Baryshkov 4376874f48bSDmitry Baryshkov return msm_mdss_enable(mdss); 438ecb23f2eSDmitry Baryshkov } 439ecb23f2eSDmitry Baryshkov 440ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_suspend(struct device *dev) 441ecb23f2eSDmitry Baryshkov { 442ecb23f2eSDmitry Baryshkov 443ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 444ecb23f2eSDmitry Baryshkov return 0; 445ecb23f2eSDmitry Baryshkov 446ecb23f2eSDmitry Baryshkov return mdss_runtime_suspend(dev); 447ecb23f2eSDmitry Baryshkov } 448ecb23f2eSDmitry Baryshkov 449ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_resume(struct device *dev) 450ecb23f2eSDmitry Baryshkov { 451ecb23f2eSDmitry Baryshkov if (pm_runtime_suspended(dev)) 452ecb23f2eSDmitry Baryshkov return 0; 453ecb23f2eSDmitry Baryshkov 454ecb23f2eSDmitry Baryshkov return mdss_runtime_resume(dev); 455ecb23f2eSDmitry Baryshkov } 456ecb23f2eSDmitry Baryshkov 457ecb23f2eSDmitry Baryshkov static const struct dev_pm_ops mdss_pm_ops = { 458ecb23f2eSDmitry Baryshkov SET_SYSTEM_SLEEP_PM_OPS(mdss_pm_suspend, mdss_pm_resume) 459ecb23f2eSDmitry Baryshkov SET_RUNTIME_PM_OPS(mdss_runtime_suspend, mdss_runtime_resume, NULL) 460ecb23f2eSDmitry Baryshkov }; 461ecb23f2eSDmitry Baryshkov 462ecb23f2eSDmitry Baryshkov static int mdss_probe(struct platform_device *pdev) 463ecb23f2eSDmitry Baryshkov { 464ecb23f2eSDmitry Baryshkov struct msm_mdss *mdss; 4655d44531bSDmitry Baryshkov bool is_mdp5 = of_device_is_compatible(pdev->dev.of_node, "qcom,mdss"); 466ecb23f2eSDmitry Baryshkov struct device *dev = &pdev->dev; 467ecb23f2eSDmitry Baryshkov int ret; 468ecb23f2eSDmitry Baryshkov 4695d44531bSDmitry Baryshkov mdss = msm_mdss_init(pdev, is_mdp5); 470ecb23f2eSDmitry Baryshkov if (IS_ERR(mdss)) 471ecb23f2eSDmitry Baryshkov return PTR_ERR(mdss); 472ecb23f2eSDmitry Baryshkov 473d68db606SDmitry Baryshkov mdss->mdss_data = of_device_get_match_data(&pdev->dev); 474d68db606SDmitry Baryshkov 4756874f48bSDmitry Baryshkov platform_set_drvdata(pdev, mdss); 476ecb23f2eSDmitry Baryshkov 477ecb23f2eSDmitry Baryshkov /* 478ecb23f2eSDmitry Baryshkov * MDP5/DPU based devices don't have a flat hierarchy. There is a top 479ecb23f2eSDmitry Baryshkov * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc. 480ecb23f2eSDmitry Baryshkov * Populate the children devices, find the MDP5/DPU node, and then add 481ecb23f2eSDmitry Baryshkov * the interfaces to our components list. 482ecb23f2eSDmitry Baryshkov */ 483ecb23f2eSDmitry Baryshkov ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 484ecb23f2eSDmitry Baryshkov if (ret) { 485ecb23f2eSDmitry Baryshkov DRM_DEV_ERROR(dev, "failed to populate children devices\n"); 4866874f48bSDmitry Baryshkov msm_mdss_destroy(mdss); 4876874f48bSDmitry Baryshkov return ret; 488ecb23f2eSDmitry Baryshkov } 489ecb23f2eSDmitry Baryshkov 490ecb23f2eSDmitry Baryshkov return 0; 491ecb23f2eSDmitry Baryshkov } 492ecb23f2eSDmitry Baryshkov 493ecb23f2eSDmitry Baryshkov static int mdss_remove(struct platform_device *pdev) 494ecb23f2eSDmitry Baryshkov { 4956874f48bSDmitry Baryshkov struct msm_mdss *mdss = platform_get_drvdata(pdev); 496ecb23f2eSDmitry Baryshkov 497ecb23f2eSDmitry Baryshkov of_platform_depopulate(&pdev->dev); 498ecb23f2eSDmitry Baryshkov 499ecb23f2eSDmitry Baryshkov msm_mdss_destroy(mdss); 500ecb23f2eSDmitry Baryshkov 501ecb23f2eSDmitry Baryshkov return 0; 502ecb23f2eSDmitry Baryshkov } 503ecb23f2eSDmitry Baryshkov 504d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7180_data = { 505d68db606SDmitry Baryshkov .ubwc_version = UBWC_2_0, 506d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 507d68db606SDmitry Baryshkov .ubwc_static = 0x1e, 508d68db606SDmitry Baryshkov }; 509d68db606SDmitry Baryshkov 510d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7280_data = { 511d68db606SDmitry Baryshkov .ubwc_version = UBWC_3_0, 512d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 513d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 514d68db606SDmitry Baryshkov .ubwc_static = 1, 515d68db606SDmitry Baryshkov .highest_bank_bit = 1, 516d68db606SDmitry Baryshkov .macrotile_mode = 1, 517d68db606SDmitry Baryshkov }; 518d68db606SDmitry Baryshkov 519aeff6bb5SDmitry Baryshkov static const struct msm_mdss_data sc8180x_data = { 520aeff6bb5SDmitry Baryshkov .ubwc_version = UBWC_3_0, 521aeff6bb5SDmitry Baryshkov .ubwc_dec_version = UBWC_3_0, 522aeff6bb5SDmitry Baryshkov .highest_bank_bit = 3, 523aeff6bb5SDmitry Baryshkov .macrotile_mode = 1, 524aeff6bb5SDmitry Baryshkov }; 525aeff6bb5SDmitry Baryshkov 526d68db606SDmitry Baryshkov static const struct msm_mdss_data sc8280xp_data = { 527d68db606SDmitry Baryshkov .ubwc_version = UBWC_4_0, 528d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 529d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 530d68db606SDmitry Baryshkov .ubwc_static = 1, 531d68db606SDmitry Baryshkov .highest_bank_bit = 2, 532d68db606SDmitry Baryshkov .macrotile_mode = 1, 533d68db606SDmitry Baryshkov }; 534d68db606SDmitry Baryshkov 5359cffae4aSDmitry Baryshkov static const struct msm_mdss_data sdm845_data = { 5369cffae4aSDmitry Baryshkov .ubwc_version = UBWC_2_0, 5379cffae4aSDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 5389cffae4aSDmitry Baryshkov .highest_bank_bit = 2, 5399cffae4aSDmitry Baryshkov }; 5409cffae4aSDmitry Baryshkov 541c2c1217eSKonrad Dybcio static const struct msm_mdss_data sm6350_data = { 542c2c1217eSKonrad Dybcio .ubwc_version = UBWC_2_0, 543c2c1217eSKonrad Dybcio .ubwc_dec_version = UBWC_2_0, 544c2c1217eSKonrad Dybcio .ubwc_swizzle = 6, 545c2c1217eSKonrad Dybcio .ubwc_static = 0x1e, 546c2c1217eSKonrad Dybcio .highest_bank_bit = 1, 547c2c1217eSKonrad Dybcio }; 548c2c1217eSKonrad Dybcio 549d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8150_data = { 550d68db606SDmitry Baryshkov .ubwc_version = UBWC_3_0, 551d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_3_0, 552d68db606SDmitry Baryshkov .highest_bank_bit = 2, 553d68db606SDmitry Baryshkov }; 554d68db606SDmitry Baryshkov 555d68db606SDmitry Baryshkov static const struct msm_mdss_data sm6115_data = { 556d68db606SDmitry Baryshkov .ubwc_version = UBWC_1_0, 557d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_2_0, 558d68db606SDmitry Baryshkov .ubwc_swizzle = 7, 559d68db606SDmitry Baryshkov .ubwc_static = 0x11f, 560d68db606SDmitry Baryshkov }; 561d68db606SDmitry Baryshkov 562*87aa3c9bSMarijn Suijten static const struct msm_mdss_data sm6125_data = { 563*87aa3c9bSMarijn Suijten .ubwc_version = UBWC_1_0, 564*87aa3c9bSMarijn Suijten .ubwc_dec_version = UBWC_3_0, 565*87aa3c9bSMarijn Suijten .ubwc_swizzle = 1, 566*87aa3c9bSMarijn Suijten .highest_bank_bit = 1, 567*87aa3c9bSMarijn Suijten }; 568*87aa3c9bSMarijn Suijten 569d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8250_data = { 570d68db606SDmitry Baryshkov .ubwc_version = UBWC_4_0, 571d68db606SDmitry Baryshkov .ubwc_dec_version = UBWC_4_0, 572d68db606SDmitry Baryshkov .ubwc_swizzle = 6, 573d68db606SDmitry Baryshkov .ubwc_static = 1, 574d68db606SDmitry Baryshkov /* TODO: highest_bank_bit = 2 for LP_DDR4 */ 575d68db606SDmitry Baryshkov .highest_bank_bit = 3, 576d68db606SDmitry Baryshkov .macrotile_mode = 1, 577d68db606SDmitry Baryshkov }; 578d68db606SDmitry Baryshkov 579ecb23f2eSDmitry Baryshkov static const struct of_device_id mdss_dt_match[] = { 5805d44531bSDmitry Baryshkov { .compatible = "qcom,mdss" }, 5815d44531bSDmitry Baryshkov { .compatible = "qcom,msm8998-mdss" }, 5825d44531bSDmitry Baryshkov { .compatible = "qcom,qcm2290-mdss" }, 5839cffae4aSDmitry Baryshkov { .compatible = "qcom,sdm845-mdss", .data = &sdm845_data }, 584d68db606SDmitry Baryshkov { .compatible = "qcom,sc7180-mdss", .data = &sc7180_data }, 585d68db606SDmitry Baryshkov { .compatible = "qcom,sc7280-mdss", .data = &sc7280_data }, 586aeff6bb5SDmitry Baryshkov { .compatible = "qcom,sc8180x-mdss", .data = &sc8180x_data }, 587d68db606SDmitry Baryshkov { .compatible = "qcom,sc8280xp-mdss", .data = &sc8280xp_data }, 588d68db606SDmitry Baryshkov { .compatible = "qcom,sm6115-mdss", .data = &sm6115_data }, 589*87aa3c9bSMarijn Suijten { .compatible = "qcom,sm6125-mdss", .data = &sm6125_data }, 590c2c1217eSKonrad Dybcio { .compatible = "qcom,sm6350-mdss", .data = &sm6350_data }, 5915ff3d3a0SKonrad Dybcio { .compatible = "qcom,sm6375-mdss", .data = &sm6350_data }, 592d68db606SDmitry Baryshkov { .compatible = "qcom,sm8150-mdss", .data = &sm8150_data }, 593d68db606SDmitry Baryshkov { .compatible = "qcom,sm8250-mdss", .data = &sm8250_data }, 594d68db606SDmitry Baryshkov { .compatible = "qcom,sm8350-mdss", .data = &sm8250_data }, 595d68db606SDmitry Baryshkov { .compatible = "qcom,sm8450-mdss", .data = &sm8250_data }, 596d68db606SDmitry Baryshkov { .compatible = "qcom,sm8550-mdss", .data = &sm8250_data }, 597ecb23f2eSDmitry Baryshkov {} 598ecb23f2eSDmitry Baryshkov }; 599ecb23f2eSDmitry Baryshkov MODULE_DEVICE_TABLE(of, mdss_dt_match); 600ecb23f2eSDmitry Baryshkov 601ecb23f2eSDmitry Baryshkov static struct platform_driver mdss_platform_driver = { 602ecb23f2eSDmitry Baryshkov .probe = mdss_probe, 603ecb23f2eSDmitry Baryshkov .remove = mdss_remove, 604ecb23f2eSDmitry Baryshkov .driver = { 605ecb23f2eSDmitry Baryshkov .name = "msm-mdss", 606ecb23f2eSDmitry Baryshkov .of_match_table = mdss_dt_match, 607ecb23f2eSDmitry Baryshkov .pm = &mdss_pm_ops, 608ecb23f2eSDmitry Baryshkov }, 609ecb23f2eSDmitry Baryshkov }; 610ecb23f2eSDmitry Baryshkov 611ecb23f2eSDmitry Baryshkov void __init msm_mdss_register(void) 612ecb23f2eSDmitry Baryshkov { 613ecb23f2eSDmitry Baryshkov platform_driver_register(&mdss_platform_driver); 614ecb23f2eSDmitry Baryshkov } 615ecb23f2eSDmitry Baryshkov 616ecb23f2eSDmitry Baryshkov void __exit msm_mdss_unregister(void) 617ecb23f2eSDmitry Baryshkov { 618ecb23f2eSDmitry Baryshkov platform_driver_unregister(&mdss_platform_driver); 619ecb23f2eSDmitry Baryshkov } 620