xref: /openbmc/linux/drivers/gpu/drm/msm/msm_mdss.c (revision 87aa3c9b44709f2c0c26d3a4fc4d08b3c1e46521)
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