xref: /openbmc/linux/drivers/gpu/drm/msm/msm_mdss.c (revision 722d4f06e560ae8eee84fbd63035356592a37dd1)
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>
13*722d4f06SRob Herring #include <linux/of_platform.h>
14*722d4f06SRob Herring #include <linux/platform_device.h>
15e1072257SDmitry Baryshkov #include <linux/pm_runtime.h>
163e9c146fSBjorn Andersson #include <linux/reset.h>
1787729e2aSDmitry Baryshkov 
18ecb23f2eSDmitry Baryshkov #include "msm_drv.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 
31d68db606SDmitry Baryshkov struct msm_mdss_data {
32d68db606SDmitry Baryshkov 	u32 ubwc_version;
33d68db606SDmitry Baryshkov 	/* can be read from register 0x58 */
34d68db606SDmitry Baryshkov 	u32 ubwc_dec_version;
35d68db606SDmitry Baryshkov 	u32 ubwc_swizzle;
36d68db606SDmitry Baryshkov 	u32 ubwc_static;
37d68db606SDmitry Baryshkov 	u32 highest_bank_bit;
38d68db606SDmitry Baryshkov 	u32 macrotile_mode;
39d68db606SDmitry Baryshkov };
40d68db606SDmitry Baryshkov 
41e1072257SDmitry Baryshkov struct msm_mdss {
42e1072257SDmitry Baryshkov 	struct device *dev;
43e1072257SDmitry Baryshkov 
4487729e2aSDmitry Baryshkov 	void __iomem *mmio;
4587729e2aSDmitry Baryshkov 	struct clk_bulk_data *clocks;
4687729e2aSDmitry Baryshkov 	size_t num_clocks;
4787729e2aSDmitry Baryshkov 	bool is_mdp5;
4887729e2aSDmitry Baryshkov 	struct {
4987729e2aSDmitry Baryshkov 		unsigned long enabled_mask;
5087729e2aSDmitry Baryshkov 		struct irq_domain *domain;
5187729e2aSDmitry Baryshkov 	} irq_controller;
52d68db606SDmitry Baryshkov 	const struct msm_mdss_data *mdss_data;
53b9364eedSDouglas Anderson 	struct icc_path *path[2];
54b9364eedSDouglas Anderson 	u32 num_paths;
5587729e2aSDmitry Baryshkov };
5687729e2aSDmitry Baryshkov 
57b9364eedSDouglas Anderson static int msm_mdss_parse_data_bus_icc_path(struct device *dev,
58b9364eedSDouglas Anderson 					    struct msm_mdss *msm_mdss)
59b9364eedSDouglas Anderson {
6045dac135SMiaoqian Lin 	struct icc_path *path0;
6145dac135SMiaoqian Lin 	struct icc_path *path1;
62b9364eedSDouglas Anderson 
6345dac135SMiaoqian Lin 	path0 = of_icc_get(dev, "mdp0-mem");
64b9364eedSDouglas Anderson 	if (IS_ERR_OR_NULL(path0))
65b9364eedSDouglas Anderson 		return PTR_ERR_OR_ZERO(path0);
66b9364eedSDouglas Anderson 
67b9364eedSDouglas Anderson 	msm_mdss->path[0] = path0;
68b9364eedSDouglas Anderson 	msm_mdss->num_paths = 1;
69b9364eedSDouglas Anderson 
7045dac135SMiaoqian Lin 	path1 = of_icc_get(dev, "mdp1-mem");
71b9364eedSDouglas Anderson 	if (!IS_ERR_OR_NULL(path1)) {
72b9364eedSDouglas Anderson 		msm_mdss->path[1] = path1;
73b9364eedSDouglas Anderson 		msm_mdss->num_paths++;
74b9364eedSDouglas Anderson 	}
75b9364eedSDouglas Anderson 
76b9364eedSDouglas Anderson 	return 0;
77b9364eedSDouglas Anderson }
78b9364eedSDouglas Anderson 
79b9364eedSDouglas Anderson static void msm_mdss_put_icc_path(void *data)
80b9364eedSDouglas Anderson {
81b9364eedSDouglas Anderson 	struct msm_mdss *msm_mdss = data;
82b9364eedSDouglas Anderson 	int i;
83b9364eedSDouglas Anderson 
84b9364eedSDouglas Anderson 	for (i = 0; i < msm_mdss->num_paths; i++)
85b9364eedSDouglas Anderson 		icc_put(msm_mdss->path[i]);
86b9364eedSDouglas Anderson }
87b9364eedSDouglas Anderson 
88b9364eedSDouglas Anderson static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw)
89b9364eedSDouglas Anderson {
90b9364eedSDouglas Anderson 	int i;
91b9364eedSDouglas Anderson 
92b9364eedSDouglas Anderson 	for (i = 0; i < msm_mdss->num_paths; i++)
93b9364eedSDouglas Anderson 		icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw));
94b9364eedSDouglas Anderson }
95b9364eedSDouglas Anderson 
9687729e2aSDmitry Baryshkov static void msm_mdss_irq(struct irq_desc *desc)
9787729e2aSDmitry Baryshkov {
98e1072257SDmitry Baryshkov 	struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc);
9987729e2aSDmitry Baryshkov 	struct irq_chip *chip = irq_desc_get_chip(desc);
10087729e2aSDmitry Baryshkov 	u32 interrupts;
10187729e2aSDmitry Baryshkov 
10287729e2aSDmitry Baryshkov 	chained_irq_enter(chip, desc);
10387729e2aSDmitry Baryshkov 
104e1072257SDmitry Baryshkov 	interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS);
10587729e2aSDmitry Baryshkov 
10687729e2aSDmitry Baryshkov 	while (interrupts) {
10787729e2aSDmitry Baryshkov 		irq_hw_number_t hwirq = fls(interrupts) - 1;
10887729e2aSDmitry Baryshkov 		int rc;
10987729e2aSDmitry Baryshkov 
110e1072257SDmitry Baryshkov 		rc = generic_handle_domain_irq(msm_mdss->irq_controller.domain,
11187729e2aSDmitry Baryshkov 					       hwirq);
11287729e2aSDmitry Baryshkov 		if (rc < 0) {
113e1072257SDmitry Baryshkov 			dev_err(msm_mdss->dev, "handle irq fail: irq=%lu rc=%d\n",
11487729e2aSDmitry Baryshkov 				  hwirq, rc);
11587729e2aSDmitry Baryshkov 			break;
11687729e2aSDmitry Baryshkov 		}
11787729e2aSDmitry Baryshkov 
11887729e2aSDmitry Baryshkov 		interrupts &= ~(1 << hwirq);
11987729e2aSDmitry Baryshkov 	}
12087729e2aSDmitry Baryshkov 
12187729e2aSDmitry Baryshkov 	chained_irq_exit(chip, desc);
12287729e2aSDmitry Baryshkov }
12387729e2aSDmitry Baryshkov 
12487729e2aSDmitry Baryshkov static void msm_mdss_irq_mask(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 	clear_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 void msm_mdss_irq_unmask(struct irq_data *irqd)
13687729e2aSDmitry Baryshkov {
137e1072257SDmitry Baryshkov 	struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd);
13887729e2aSDmitry Baryshkov 
13987729e2aSDmitry Baryshkov 	/* memory barrier */
14087729e2aSDmitry Baryshkov 	smp_mb__before_atomic();
141e1072257SDmitry Baryshkov 	set_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask);
14287729e2aSDmitry Baryshkov 	/* memory barrier */
14387729e2aSDmitry Baryshkov 	smp_mb__after_atomic();
14487729e2aSDmitry Baryshkov }
14587729e2aSDmitry Baryshkov 
14687729e2aSDmitry Baryshkov static struct irq_chip msm_mdss_irq_chip = {
147e1072257SDmitry Baryshkov 	.name = "msm_mdss",
14887729e2aSDmitry Baryshkov 	.irq_mask = msm_mdss_irq_mask,
14987729e2aSDmitry Baryshkov 	.irq_unmask = msm_mdss_irq_unmask,
15087729e2aSDmitry Baryshkov };
15187729e2aSDmitry Baryshkov 
15287729e2aSDmitry Baryshkov static struct lock_class_key msm_mdss_lock_key, msm_mdss_request_key;
15387729e2aSDmitry Baryshkov 
15487729e2aSDmitry Baryshkov static int msm_mdss_irqdomain_map(struct irq_domain *domain,
15587729e2aSDmitry Baryshkov 		unsigned int irq, irq_hw_number_t hwirq)
15687729e2aSDmitry Baryshkov {
157e1072257SDmitry Baryshkov 	struct msm_mdss *msm_mdss = domain->host_data;
15887729e2aSDmitry Baryshkov 
15987729e2aSDmitry Baryshkov 	irq_set_lockdep_class(irq, &msm_mdss_lock_key, &msm_mdss_request_key);
16087729e2aSDmitry Baryshkov 	irq_set_chip_and_handler(irq, &msm_mdss_irq_chip, handle_level_irq);
16187729e2aSDmitry Baryshkov 
162e1072257SDmitry Baryshkov 	return irq_set_chip_data(irq, msm_mdss);
16387729e2aSDmitry Baryshkov }
16487729e2aSDmitry Baryshkov 
16587729e2aSDmitry Baryshkov static const struct irq_domain_ops msm_mdss_irqdomain_ops = {
16687729e2aSDmitry Baryshkov 	.map = msm_mdss_irqdomain_map,
16787729e2aSDmitry Baryshkov 	.xlate = irq_domain_xlate_onecell,
16887729e2aSDmitry Baryshkov };
16987729e2aSDmitry Baryshkov 
170e1072257SDmitry Baryshkov static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
17187729e2aSDmitry Baryshkov {
17287729e2aSDmitry Baryshkov 	struct device *dev;
17387729e2aSDmitry Baryshkov 	struct irq_domain *domain;
17487729e2aSDmitry Baryshkov 
175e1072257SDmitry Baryshkov 	dev = msm_mdss->dev;
17687729e2aSDmitry Baryshkov 
17787729e2aSDmitry Baryshkov 	domain = irq_domain_add_linear(dev->of_node, 32,
178e1072257SDmitry Baryshkov 			&msm_mdss_irqdomain_ops, msm_mdss);
17987729e2aSDmitry Baryshkov 	if (!domain) {
180e1072257SDmitry Baryshkov 		dev_err(dev, "failed to add irq_domain\n");
18187729e2aSDmitry Baryshkov 		return -EINVAL;
18287729e2aSDmitry Baryshkov 	}
18387729e2aSDmitry Baryshkov 
184e1072257SDmitry Baryshkov 	msm_mdss->irq_controller.enabled_mask = 0;
185e1072257SDmitry Baryshkov 	msm_mdss->irq_controller.domain = domain;
18687729e2aSDmitry Baryshkov 
18787729e2aSDmitry Baryshkov 	return 0;
18887729e2aSDmitry Baryshkov }
18987729e2aSDmitry Baryshkov 
19092bab914SDmitry Baryshkov #define UBWC_1_0 0x10000000
19192bab914SDmitry Baryshkov #define UBWC_2_0 0x20000000
19292bab914SDmitry Baryshkov #define UBWC_3_0 0x30000000
19392bab914SDmitry Baryshkov #define UBWC_4_0 0x40000000
19492bab914SDmitry Baryshkov 
195d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss)
19692bab914SDmitry Baryshkov {
197d68db606SDmitry Baryshkov 	const struct msm_mdss_data *data = msm_mdss->mdss_data;
198d68db606SDmitry Baryshkov 
199d68db606SDmitry Baryshkov 	writel_relaxed(data->ubwc_static, msm_mdss->mmio + UBWC_STATIC);
20092bab914SDmitry Baryshkov }
20192bab914SDmitry Baryshkov 
202d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_30(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 & 0x1) |
206d68db606SDmitry Baryshkov 		    (data->highest_bank_bit & 0x3) << 4 |
207d68db606SDmitry Baryshkov 		    (data->macrotile_mode & 0x1) << 12;
20892bab914SDmitry Baryshkov 
209d68db606SDmitry Baryshkov 	if (data->ubwc_version == UBWC_3_0)
21092bab914SDmitry Baryshkov 		value |= BIT(10);
21192bab914SDmitry Baryshkov 
212d68db606SDmitry Baryshkov 	if (data->ubwc_version == UBWC_1_0)
21392bab914SDmitry Baryshkov 		value |= BIT(8);
21492bab914SDmitry Baryshkov 
21592bab914SDmitry Baryshkov 	writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
21692bab914SDmitry Baryshkov }
21792bab914SDmitry Baryshkov 
218d68db606SDmitry Baryshkov static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss)
21992bab914SDmitry Baryshkov {
220d68db606SDmitry Baryshkov 	const struct msm_mdss_data *data = msm_mdss->mdss_data;
221d68db606SDmitry Baryshkov 	u32 value = (data->ubwc_swizzle & 0x7) |
222d68db606SDmitry Baryshkov 		    (data->ubwc_static & 0x1) << 3 |
223d68db606SDmitry Baryshkov 		    (data->highest_bank_bit & 0x7) << 4 |
224d68db606SDmitry Baryshkov 		    (data->macrotile_mode & 0x1) << 12;
22592bab914SDmitry Baryshkov 
22692bab914SDmitry Baryshkov 	writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
22792bab914SDmitry Baryshkov 
228d68db606SDmitry Baryshkov 	if (data->ubwc_version == UBWC_3_0) {
22992bab914SDmitry Baryshkov 		writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2);
23092bab914SDmitry Baryshkov 		writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE);
23192bab914SDmitry Baryshkov 	} else {
23292bab914SDmitry Baryshkov 		writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2);
23392bab914SDmitry Baryshkov 		writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE);
23492bab914SDmitry Baryshkov 	}
23592bab914SDmitry Baryshkov }
23692bab914SDmitry Baryshkov 
237ecb23f2eSDmitry Baryshkov static int msm_mdss_enable(struct msm_mdss *msm_mdss)
23887729e2aSDmitry Baryshkov {
23987729e2aSDmitry Baryshkov 	int ret;
24087729e2aSDmitry Baryshkov 
241b9364eedSDouglas Anderson 	/*
242b9364eedSDouglas Anderson 	 * Several components have AXI clocks that can only be turned on if
243b9364eedSDouglas Anderson 	 * the interconnect is enabled (non-zero bandwidth). Let's make sure
244b9364eedSDouglas Anderson 	 * that the interconnects are at least at a minimum amount.
245b9364eedSDouglas Anderson 	 */
246b9364eedSDouglas Anderson 	msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW);
247b9364eedSDouglas Anderson 
248e1072257SDmitry Baryshkov 	ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks);
24987729e2aSDmitry Baryshkov 	if (ret) {
250e1072257SDmitry Baryshkov 		dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret);
25187729e2aSDmitry Baryshkov 		return ret;
25287729e2aSDmitry Baryshkov 	}
25387729e2aSDmitry Baryshkov 
25487729e2aSDmitry Baryshkov 	/*
255d68db606SDmitry Baryshkov 	 * Register access requires MDSS_MDP_CLK, which is not enabled by the
256d68db606SDmitry Baryshkov 	 * mdss on mdp5 hardware. Skip it for now.
25787729e2aSDmitry Baryshkov 	 */
258d68db606SDmitry Baryshkov 	if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data)
25987729e2aSDmitry Baryshkov 		return 0;
26087729e2aSDmitry Baryshkov 
26187729e2aSDmitry Baryshkov 	/*
26287729e2aSDmitry Baryshkov 	 * ubwc config is part of the "mdss" region which is not accessible
26387729e2aSDmitry Baryshkov 	 * from the rest of the driver. hardcode known configurations here
26492bab914SDmitry Baryshkov 	 *
26592bab914SDmitry Baryshkov 	 * Decoder version can be read from the UBWC_DEC_HW_VERSION reg,
266d68db606SDmitry Baryshkov 	 * UBWC_n and the rest of params comes from hw data.
26787729e2aSDmitry Baryshkov 	 */
268d68db606SDmitry Baryshkov 	switch (msm_mdss->mdss_data->ubwc_dec_version) {
269d68db606SDmitry Baryshkov 	case UBWC_2_0:
270d68db606SDmitry Baryshkov 		msm_mdss_setup_ubwc_dec_20(msm_mdss);
27187729e2aSDmitry Baryshkov 		break;
272d68db606SDmitry Baryshkov 	case UBWC_3_0:
273d68db606SDmitry Baryshkov 		msm_mdss_setup_ubwc_dec_30(msm_mdss);
27487729e2aSDmitry Baryshkov 		break;
275d68db606SDmitry Baryshkov 	case UBWC_4_0:
276d68db606SDmitry Baryshkov 		msm_mdss_setup_ubwc_dec_40(msm_mdss);
27787729e2aSDmitry Baryshkov 		break;
278d68db606SDmitry Baryshkov 	default:
2796ec59381SColin Ian King 		dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n",
280d68db606SDmitry Baryshkov 			msm_mdss->mdss_data->ubwc_dec_version);
281d68db606SDmitry Baryshkov 		dev_err(msm_mdss->dev, "HW_REV: 0x%x\n",
282d68db606SDmitry Baryshkov 			readl_relaxed(msm_mdss->mmio + HW_REV));
283d68db606SDmitry Baryshkov 		dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n",
284d68db606SDmitry Baryshkov 			readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION));
28580056d9aSDmitry Baryshkov 		break;
28687729e2aSDmitry Baryshkov 	}
28787729e2aSDmitry Baryshkov 
28887729e2aSDmitry Baryshkov 	return ret;
28987729e2aSDmitry Baryshkov }
29087729e2aSDmitry Baryshkov 
291ecb23f2eSDmitry Baryshkov static int msm_mdss_disable(struct msm_mdss *msm_mdss)
29287729e2aSDmitry Baryshkov {
293e1072257SDmitry Baryshkov 	clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks);
294b9364eedSDouglas Anderson 	msm_mdss_icc_request_bw(msm_mdss, 0);
29587729e2aSDmitry Baryshkov 
29687729e2aSDmitry Baryshkov 	return 0;
29787729e2aSDmitry Baryshkov }
29887729e2aSDmitry Baryshkov 
299ecb23f2eSDmitry Baryshkov static void msm_mdss_destroy(struct msm_mdss *msm_mdss)
30087729e2aSDmitry Baryshkov {
301e1072257SDmitry Baryshkov 	struct platform_device *pdev = to_platform_device(msm_mdss->dev);
30287729e2aSDmitry Baryshkov 	int irq;
30387729e2aSDmitry Baryshkov 
304e1072257SDmitry Baryshkov 	pm_runtime_suspend(msm_mdss->dev);
305e1072257SDmitry Baryshkov 	pm_runtime_disable(msm_mdss->dev);
306e1072257SDmitry Baryshkov 	irq_domain_remove(msm_mdss->irq_controller.domain);
307e1072257SDmitry Baryshkov 	msm_mdss->irq_controller.domain = NULL;
30887729e2aSDmitry Baryshkov 	irq = platform_get_irq(pdev, 0);
30987729e2aSDmitry Baryshkov 	irq_set_chained_handler_and_data(irq, NULL, NULL);
31087729e2aSDmitry Baryshkov }
31187729e2aSDmitry Baryshkov 
3123e9c146fSBjorn Andersson static int msm_mdss_reset(struct device *dev)
3133e9c146fSBjorn Andersson {
3143e9c146fSBjorn Andersson 	struct reset_control *reset;
3153e9c146fSBjorn Andersson 
3163e9c146fSBjorn Andersson 	reset = reset_control_get_optional_exclusive(dev, NULL);
3173e9c146fSBjorn Andersson 	if (!reset) {
3183e9c146fSBjorn Andersson 		/* Optional reset not specified */
3193e9c146fSBjorn Andersson 		return 0;
3203e9c146fSBjorn Andersson 	} else if (IS_ERR(reset)) {
3213e9c146fSBjorn Andersson 		return dev_err_probe(dev, PTR_ERR(reset),
3223e9c146fSBjorn Andersson 				     "failed to acquire mdss reset\n");
3233e9c146fSBjorn Andersson 	}
3243e9c146fSBjorn Andersson 
3253e9c146fSBjorn Andersson 	reset_control_assert(reset);
3263e9c146fSBjorn Andersson 	/*
3273e9c146fSBjorn Andersson 	 * Tests indicate that reset has to be held for some period of time,
3283e9c146fSBjorn Andersson 	 * make it one frame in a typical system
3293e9c146fSBjorn Andersson 	 */
3303e9c146fSBjorn Andersson 	msleep(20);
3313e9c146fSBjorn Andersson 	reset_control_deassert(reset);
3323e9c146fSBjorn Andersson 
3333e9c146fSBjorn Andersson 	reset_control_put(reset);
3343e9c146fSBjorn Andersson 
3353e9c146fSBjorn Andersson 	return 0;
3363e9c146fSBjorn Andersson }
3373e9c146fSBjorn Andersson 
33887729e2aSDmitry Baryshkov /*
33987729e2aSDmitry Baryshkov  * MDP5 MDSS uses at most three specified clocks.
34087729e2aSDmitry Baryshkov  */
34187729e2aSDmitry Baryshkov #define MDP5_MDSS_NUM_CLOCKS 3
34287729e2aSDmitry Baryshkov static int mdp5_mdss_parse_clock(struct platform_device *pdev, struct clk_bulk_data **clocks)
34387729e2aSDmitry Baryshkov {
34487729e2aSDmitry Baryshkov 	struct clk_bulk_data *bulk;
34587729e2aSDmitry Baryshkov 	int num_clocks = 0;
34687729e2aSDmitry Baryshkov 	int ret;
34787729e2aSDmitry Baryshkov 
34887729e2aSDmitry Baryshkov 	if (!pdev)
34987729e2aSDmitry Baryshkov 		return -EINVAL;
35087729e2aSDmitry Baryshkov 
35187729e2aSDmitry Baryshkov 	bulk = devm_kcalloc(&pdev->dev, MDP5_MDSS_NUM_CLOCKS, sizeof(struct clk_bulk_data), GFP_KERNEL);
35287729e2aSDmitry Baryshkov 	if (!bulk)
35387729e2aSDmitry Baryshkov 		return -ENOMEM;
35487729e2aSDmitry Baryshkov 
35587729e2aSDmitry Baryshkov 	bulk[num_clocks++].id = "iface";
35687729e2aSDmitry Baryshkov 	bulk[num_clocks++].id = "bus";
35787729e2aSDmitry Baryshkov 	bulk[num_clocks++].id = "vsync";
35887729e2aSDmitry Baryshkov 
35987729e2aSDmitry Baryshkov 	ret = devm_clk_bulk_get_optional(&pdev->dev, num_clocks, bulk);
36087729e2aSDmitry Baryshkov 	if (ret)
36187729e2aSDmitry Baryshkov 		return ret;
36287729e2aSDmitry Baryshkov 
36387729e2aSDmitry Baryshkov 	*clocks = bulk;
36487729e2aSDmitry Baryshkov 
36587729e2aSDmitry Baryshkov 	return num_clocks;
36687729e2aSDmitry Baryshkov }
36787729e2aSDmitry Baryshkov 
368ecb23f2eSDmitry Baryshkov static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5)
36987729e2aSDmitry Baryshkov {
370e1072257SDmitry Baryshkov 	struct msm_mdss *msm_mdss;
37187729e2aSDmitry Baryshkov 	int ret;
37287729e2aSDmitry Baryshkov 	int irq;
37387729e2aSDmitry Baryshkov 
3743e9c146fSBjorn Andersson 	ret = msm_mdss_reset(&pdev->dev);
3753e9c146fSBjorn Andersson 	if (ret)
3763e9c146fSBjorn Andersson 		return ERR_PTR(ret);
3773e9c146fSBjorn Andersson 
378e1072257SDmitry Baryshkov 	msm_mdss = devm_kzalloc(&pdev->dev, sizeof(*msm_mdss), GFP_KERNEL);
379e1072257SDmitry Baryshkov 	if (!msm_mdss)
380e1072257SDmitry Baryshkov 		return ERR_PTR(-ENOMEM);
38187729e2aSDmitry Baryshkov 
382e1072257SDmitry Baryshkov 	msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss");
383e1072257SDmitry Baryshkov 	if (IS_ERR(msm_mdss->mmio))
384e1072257SDmitry Baryshkov 		return ERR_CAST(msm_mdss->mmio);
38587729e2aSDmitry Baryshkov 
386e1072257SDmitry Baryshkov 	dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio);
38787729e2aSDmitry Baryshkov 
388b9364eedSDouglas Anderson 	ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss);
389b9364eedSDouglas Anderson 	if (ret)
390b9364eedSDouglas Anderson 		return ERR_PTR(ret);
391b9364eedSDouglas Anderson 	ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss);
392b9364eedSDouglas Anderson 	if (ret)
393b9364eedSDouglas Anderson 		return ERR_PTR(ret);
394b9364eedSDouglas Anderson 
39587729e2aSDmitry Baryshkov 	if (is_mdp5)
396e1072257SDmitry Baryshkov 		ret = mdp5_mdss_parse_clock(pdev, &msm_mdss->clocks);
39787729e2aSDmitry Baryshkov 	else
398e1072257SDmitry Baryshkov 		ret = devm_clk_bulk_get_all(&pdev->dev, &msm_mdss->clocks);
39987729e2aSDmitry Baryshkov 	if (ret < 0) {
400e1072257SDmitry Baryshkov 		dev_err(&pdev->dev, "failed to parse clocks, ret=%d\n", ret);
401e1072257SDmitry Baryshkov 		return ERR_PTR(ret);
40287729e2aSDmitry Baryshkov 	}
403e1072257SDmitry Baryshkov 	msm_mdss->num_clocks = ret;
404e1072257SDmitry Baryshkov 	msm_mdss->is_mdp5 = is_mdp5;
40587729e2aSDmitry Baryshkov 
406e1072257SDmitry Baryshkov 	msm_mdss->dev = &pdev->dev;
40787729e2aSDmitry Baryshkov 
40887729e2aSDmitry Baryshkov 	irq = platform_get_irq(pdev, 0);
40987729e2aSDmitry Baryshkov 	if (irq < 0)
410e1072257SDmitry Baryshkov 		return ERR_PTR(irq);
41187729e2aSDmitry Baryshkov 
412e1072257SDmitry Baryshkov 	ret = _msm_mdss_irq_domain_add(msm_mdss);
41387729e2aSDmitry Baryshkov 	if (ret)
414e1072257SDmitry Baryshkov 		return ERR_PTR(ret);
41587729e2aSDmitry Baryshkov 
41687729e2aSDmitry Baryshkov 	irq_set_chained_handler_and_data(irq, msm_mdss_irq,
417e1072257SDmitry Baryshkov 					 msm_mdss);
41887729e2aSDmitry Baryshkov 
41987729e2aSDmitry Baryshkov 	pm_runtime_enable(&pdev->dev);
42087729e2aSDmitry Baryshkov 
421e1072257SDmitry Baryshkov 	return msm_mdss;
42287729e2aSDmitry Baryshkov }
423ecb23f2eSDmitry Baryshkov 
424ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_suspend(struct device *dev)
425ecb23f2eSDmitry Baryshkov {
4266874f48bSDmitry Baryshkov 	struct msm_mdss *mdss = dev_get_drvdata(dev);
427ecb23f2eSDmitry Baryshkov 
428ecb23f2eSDmitry Baryshkov 	DBG("");
429ecb23f2eSDmitry Baryshkov 
4306874f48bSDmitry Baryshkov 	return msm_mdss_disable(mdss);
431ecb23f2eSDmitry Baryshkov }
432ecb23f2eSDmitry Baryshkov 
433ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_runtime_resume(struct device *dev)
434ecb23f2eSDmitry Baryshkov {
4356874f48bSDmitry Baryshkov 	struct msm_mdss *mdss = dev_get_drvdata(dev);
436ecb23f2eSDmitry Baryshkov 
437ecb23f2eSDmitry Baryshkov 	DBG("");
438ecb23f2eSDmitry Baryshkov 
4396874f48bSDmitry Baryshkov 	return msm_mdss_enable(mdss);
440ecb23f2eSDmitry Baryshkov }
441ecb23f2eSDmitry Baryshkov 
442ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_suspend(struct device *dev)
443ecb23f2eSDmitry Baryshkov {
444ecb23f2eSDmitry Baryshkov 
445ecb23f2eSDmitry Baryshkov 	if (pm_runtime_suspended(dev))
446ecb23f2eSDmitry Baryshkov 		return 0;
447ecb23f2eSDmitry Baryshkov 
448ecb23f2eSDmitry Baryshkov 	return mdss_runtime_suspend(dev);
449ecb23f2eSDmitry Baryshkov }
450ecb23f2eSDmitry Baryshkov 
451ecb23f2eSDmitry Baryshkov static int __maybe_unused mdss_pm_resume(struct device *dev)
452ecb23f2eSDmitry Baryshkov {
453ecb23f2eSDmitry Baryshkov 	if (pm_runtime_suspended(dev))
454ecb23f2eSDmitry Baryshkov 		return 0;
455ecb23f2eSDmitry Baryshkov 
456ecb23f2eSDmitry Baryshkov 	return mdss_runtime_resume(dev);
457ecb23f2eSDmitry Baryshkov }
458ecb23f2eSDmitry Baryshkov 
459ecb23f2eSDmitry Baryshkov static const struct dev_pm_ops mdss_pm_ops = {
460ecb23f2eSDmitry Baryshkov 	SET_SYSTEM_SLEEP_PM_OPS(mdss_pm_suspend, mdss_pm_resume)
461ecb23f2eSDmitry Baryshkov 	SET_RUNTIME_PM_OPS(mdss_runtime_suspend, mdss_runtime_resume, NULL)
462ecb23f2eSDmitry Baryshkov };
463ecb23f2eSDmitry Baryshkov 
464ecb23f2eSDmitry Baryshkov static int mdss_probe(struct platform_device *pdev)
465ecb23f2eSDmitry Baryshkov {
466ecb23f2eSDmitry Baryshkov 	struct msm_mdss *mdss;
4675d44531bSDmitry Baryshkov 	bool is_mdp5 = of_device_is_compatible(pdev->dev.of_node, "qcom,mdss");
468ecb23f2eSDmitry Baryshkov 	struct device *dev = &pdev->dev;
469ecb23f2eSDmitry Baryshkov 	int ret;
470ecb23f2eSDmitry Baryshkov 
4715d44531bSDmitry Baryshkov 	mdss = msm_mdss_init(pdev, is_mdp5);
472ecb23f2eSDmitry Baryshkov 	if (IS_ERR(mdss))
473ecb23f2eSDmitry Baryshkov 		return PTR_ERR(mdss);
474ecb23f2eSDmitry Baryshkov 
475d68db606SDmitry Baryshkov 	mdss->mdss_data = of_device_get_match_data(&pdev->dev);
476d68db606SDmitry Baryshkov 
4776874f48bSDmitry Baryshkov 	platform_set_drvdata(pdev, mdss);
478ecb23f2eSDmitry Baryshkov 
479ecb23f2eSDmitry Baryshkov 	/*
480ecb23f2eSDmitry Baryshkov 	 * MDP5/DPU based devices don't have a flat hierarchy. There is a top
481ecb23f2eSDmitry Baryshkov 	 * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc.
482ecb23f2eSDmitry Baryshkov 	 * Populate the children devices, find the MDP5/DPU node, and then add
483ecb23f2eSDmitry Baryshkov 	 * the interfaces to our components list.
484ecb23f2eSDmitry Baryshkov 	 */
485ecb23f2eSDmitry Baryshkov 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
486ecb23f2eSDmitry Baryshkov 	if (ret) {
487ecb23f2eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "failed to populate children devices\n");
4886874f48bSDmitry Baryshkov 		msm_mdss_destroy(mdss);
4896874f48bSDmitry Baryshkov 		return ret;
490ecb23f2eSDmitry Baryshkov 	}
491ecb23f2eSDmitry Baryshkov 
492ecb23f2eSDmitry Baryshkov 	return 0;
493ecb23f2eSDmitry Baryshkov }
494ecb23f2eSDmitry Baryshkov 
495ecb23f2eSDmitry Baryshkov static int mdss_remove(struct platform_device *pdev)
496ecb23f2eSDmitry Baryshkov {
4976874f48bSDmitry Baryshkov 	struct msm_mdss *mdss = platform_get_drvdata(pdev);
498ecb23f2eSDmitry Baryshkov 
499ecb23f2eSDmitry Baryshkov 	of_platform_depopulate(&pdev->dev);
500ecb23f2eSDmitry Baryshkov 
501ecb23f2eSDmitry Baryshkov 	msm_mdss_destroy(mdss);
502ecb23f2eSDmitry Baryshkov 
503ecb23f2eSDmitry Baryshkov 	return 0;
504ecb23f2eSDmitry Baryshkov }
505ecb23f2eSDmitry Baryshkov 
506d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7180_data = {
507d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_2_0,
508d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_2_0,
509d68db606SDmitry Baryshkov 	.ubwc_static = 0x1e,
510d68db606SDmitry Baryshkov };
511d68db606SDmitry Baryshkov 
512d68db606SDmitry Baryshkov static const struct msm_mdss_data sc7280_data = {
513d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_3_0,
514d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_4_0,
515d68db606SDmitry Baryshkov 	.ubwc_swizzle = 6,
516d68db606SDmitry Baryshkov 	.ubwc_static = 1,
517d68db606SDmitry Baryshkov 	.highest_bank_bit = 1,
518d68db606SDmitry Baryshkov 	.macrotile_mode = 1,
519d68db606SDmitry Baryshkov };
520d68db606SDmitry Baryshkov 
521aeff6bb5SDmitry Baryshkov static const struct msm_mdss_data sc8180x_data = {
522aeff6bb5SDmitry Baryshkov 	.ubwc_version = UBWC_3_0,
523aeff6bb5SDmitry Baryshkov 	.ubwc_dec_version = UBWC_3_0,
524aeff6bb5SDmitry Baryshkov 	.highest_bank_bit = 3,
525aeff6bb5SDmitry Baryshkov 	.macrotile_mode = 1,
526aeff6bb5SDmitry Baryshkov };
527aeff6bb5SDmitry Baryshkov 
528d68db606SDmitry Baryshkov static const struct msm_mdss_data sc8280xp_data = {
529d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_4_0,
530d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_4_0,
531d68db606SDmitry Baryshkov 	.ubwc_swizzle = 6,
532d68db606SDmitry Baryshkov 	.ubwc_static = 1,
533d68db606SDmitry Baryshkov 	.highest_bank_bit = 2,
534d68db606SDmitry Baryshkov 	.macrotile_mode = 1,
535d68db606SDmitry Baryshkov };
536d68db606SDmitry Baryshkov 
5379cffae4aSDmitry Baryshkov static const struct msm_mdss_data sdm845_data = {
5389cffae4aSDmitry Baryshkov 	.ubwc_version = UBWC_2_0,
5399cffae4aSDmitry Baryshkov 	.ubwc_dec_version = UBWC_2_0,
5409cffae4aSDmitry Baryshkov 	.highest_bank_bit = 2,
5419cffae4aSDmitry Baryshkov };
5429cffae4aSDmitry Baryshkov 
543c2c1217eSKonrad Dybcio static const struct msm_mdss_data sm6350_data = {
544c2c1217eSKonrad Dybcio 	.ubwc_version = UBWC_2_0,
545c2c1217eSKonrad Dybcio 	.ubwc_dec_version = UBWC_2_0,
546c2c1217eSKonrad Dybcio 	.ubwc_swizzle = 6,
547c2c1217eSKonrad Dybcio 	.ubwc_static = 0x1e,
548c2c1217eSKonrad Dybcio 	.highest_bank_bit = 1,
549c2c1217eSKonrad Dybcio };
550c2c1217eSKonrad Dybcio 
551d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8150_data = {
552d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_3_0,
553d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_3_0,
554d68db606SDmitry Baryshkov 	.highest_bank_bit = 2,
555d68db606SDmitry Baryshkov };
556d68db606SDmitry Baryshkov 
557d68db606SDmitry Baryshkov static const struct msm_mdss_data sm6115_data = {
558d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_1_0,
559d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_2_0,
560d68db606SDmitry Baryshkov 	.ubwc_swizzle = 7,
561d68db606SDmitry Baryshkov 	.ubwc_static = 0x11f,
562d68db606SDmitry Baryshkov };
563d68db606SDmitry Baryshkov 
564d68db606SDmitry Baryshkov static const struct msm_mdss_data sm8250_data = {
565d68db606SDmitry Baryshkov 	.ubwc_version = UBWC_4_0,
566d68db606SDmitry Baryshkov 	.ubwc_dec_version = UBWC_4_0,
567d68db606SDmitry Baryshkov 	.ubwc_swizzle = 6,
568d68db606SDmitry Baryshkov 	.ubwc_static = 1,
569d68db606SDmitry Baryshkov 	/* TODO: highest_bank_bit = 2 for LP_DDR4 */
570d68db606SDmitry Baryshkov 	.highest_bank_bit = 3,
571d68db606SDmitry Baryshkov 	.macrotile_mode = 1,
572d68db606SDmitry Baryshkov };
573d68db606SDmitry Baryshkov 
574ecb23f2eSDmitry Baryshkov static const struct of_device_id mdss_dt_match[] = {
5755d44531bSDmitry Baryshkov 	{ .compatible = "qcom,mdss" },
5765d44531bSDmitry Baryshkov 	{ .compatible = "qcom,msm8998-mdss" },
5775d44531bSDmitry Baryshkov 	{ .compatible = "qcom,qcm2290-mdss" },
5789cffae4aSDmitry Baryshkov 	{ .compatible = "qcom,sdm845-mdss", .data = &sdm845_data },
579d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sc7180-mdss", .data = &sc7180_data },
580d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sc7280-mdss", .data = &sc7280_data },
581aeff6bb5SDmitry Baryshkov 	{ .compatible = "qcom,sc8180x-mdss", .data = &sc8180x_data },
582d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sc8280xp-mdss", .data = &sc8280xp_data },
583d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm6115-mdss", .data = &sm6115_data },
584c2c1217eSKonrad Dybcio 	{ .compatible = "qcom,sm6350-mdss", .data = &sm6350_data },
5855ff3d3a0SKonrad Dybcio 	{ .compatible = "qcom,sm6375-mdss", .data = &sm6350_data },
586d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm8150-mdss", .data = &sm8150_data },
587d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm8250-mdss", .data = &sm8250_data },
588d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm8350-mdss", .data = &sm8250_data },
589d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm8450-mdss", .data = &sm8250_data },
590d68db606SDmitry Baryshkov 	{ .compatible = "qcom,sm8550-mdss", .data = &sm8250_data },
591ecb23f2eSDmitry Baryshkov 	{}
592ecb23f2eSDmitry Baryshkov };
593ecb23f2eSDmitry Baryshkov MODULE_DEVICE_TABLE(of, mdss_dt_match);
594ecb23f2eSDmitry Baryshkov 
595ecb23f2eSDmitry Baryshkov static struct platform_driver mdss_platform_driver = {
596ecb23f2eSDmitry Baryshkov 	.probe      = mdss_probe,
597ecb23f2eSDmitry Baryshkov 	.remove     = mdss_remove,
598ecb23f2eSDmitry Baryshkov 	.driver     = {
599ecb23f2eSDmitry Baryshkov 		.name   = "msm-mdss",
600ecb23f2eSDmitry Baryshkov 		.of_match_table = mdss_dt_match,
601ecb23f2eSDmitry Baryshkov 		.pm     = &mdss_pm_ops,
602ecb23f2eSDmitry Baryshkov 	},
603ecb23f2eSDmitry Baryshkov };
604ecb23f2eSDmitry Baryshkov 
605ecb23f2eSDmitry Baryshkov void __init msm_mdss_register(void)
606ecb23f2eSDmitry Baryshkov {
607ecb23f2eSDmitry Baryshkov 	platform_driver_register(&mdss_platform_driver);
608ecb23f2eSDmitry Baryshkov }
609ecb23f2eSDmitry Baryshkov 
610ecb23f2eSDmitry Baryshkov void __exit msm_mdss_unregister(void)
611ecb23f2eSDmitry Baryshkov {
612ecb23f2eSDmitry Baryshkov 	platform_driver_unregister(&mdss_platform_driver);
613ecb23f2eSDmitry Baryshkov }
614