162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/clk.h>
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/interconnect.h>
962306a36Sopenharmony_ci#include <linux/irq.h>
1062306a36Sopenharmony_ci#include <linux/irqchip.h>
1162306a36Sopenharmony_ci#include <linux/irqdesc.h>
1262306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h>
1362306a36Sopenharmony_ci#include <linux/of_platform.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/reset.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "msm_mdss.h"
1962306a36Sopenharmony_ci#include "msm_kms.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define HW_REV				0x0
2262306a36Sopenharmony_ci#define HW_INTR_STATUS			0x0010
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define UBWC_DEC_HW_VERSION		0x58
2562306a36Sopenharmony_ci#define UBWC_STATIC			0x144
2662306a36Sopenharmony_ci#define UBWC_CTRL_2			0x150
2762306a36Sopenharmony_ci#define UBWC_PREDICTION_MODE		0x154
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MIN_IB_BW	400000000UL /* Min ib vote 400MB */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct msm_mdss {
3262306a36Sopenharmony_ci	struct device *dev;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	void __iomem *mmio;
3562306a36Sopenharmony_ci	struct clk_bulk_data *clocks;
3662306a36Sopenharmony_ci	size_t num_clocks;
3762306a36Sopenharmony_ci	bool is_mdp5;
3862306a36Sopenharmony_ci	struct {
3962306a36Sopenharmony_ci		unsigned long enabled_mask;
4062306a36Sopenharmony_ci		struct irq_domain *domain;
4162306a36Sopenharmony_ci	} irq_controller;
4262306a36Sopenharmony_ci	const struct msm_mdss_data *mdss_data;
4362306a36Sopenharmony_ci	struct icc_path *path[2];
4462306a36Sopenharmony_ci	u32 num_paths;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int msm_mdss_parse_data_bus_icc_path(struct device *dev,
4862306a36Sopenharmony_ci					    struct msm_mdss *msm_mdss)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct icc_path *path0;
5162306a36Sopenharmony_ci	struct icc_path *path1;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	path0 = of_icc_get(dev, "mdp0-mem");
5462306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(path0))
5562306a36Sopenharmony_ci		return PTR_ERR_OR_ZERO(path0);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	msm_mdss->path[0] = path0;
5862306a36Sopenharmony_ci	msm_mdss->num_paths = 1;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	path1 = of_icc_get(dev, "mdp1-mem");
6162306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(path1)) {
6262306a36Sopenharmony_ci		msm_mdss->path[1] = path1;
6362306a36Sopenharmony_ci		msm_mdss->num_paths++;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void msm_mdss_put_icc_path(void *data)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct msm_mdss *msm_mdss = data;
7262306a36Sopenharmony_ci	int i;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	for (i = 0; i < msm_mdss->num_paths; i++)
7562306a36Sopenharmony_ci		icc_put(msm_mdss->path[i]);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	int i;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	for (i = 0; i < msm_mdss->num_paths; i++)
8362306a36Sopenharmony_ci		icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw));
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void msm_mdss_irq(struct irq_desc *desc)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc);
8962306a36Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
9062306a36Sopenharmony_ci	u32 interrupts;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	chained_irq_enter(chip, desc);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	while (interrupts) {
9762306a36Sopenharmony_ci		irq_hw_number_t hwirq = fls(interrupts) - 1;
9862306a36Sopenharmony_ci		int rc;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		rc = generic_handle_domain_irq(msm_mdss->irq_controller.domain,
10162306a36Sopenharmony_ci					       hwirq);
10262306a36Sopenharmony_ci		if (rc < 0) {
10362306a36Sopenharmony_ci			dev_err(msm_mdss->dev, "handle irq fail: irq=%lu rc=%d\n",
10462306a36Sopenharmony_ci				  hwirq, rc);
10562306a36Sopenharmony_ci			break;
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		interrupts &= ~(1 << hwirq);
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	chained_irq_exit(chip, desc);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void msm_mdss_irq_mask(struct irq_data *irqd)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* memory barrier */
11962306a36Sopenharmony_ci	smp_mb__before_atomic();
12062306a36Sopenharmony_ci	clear_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask);
12162306a36Sopenharmony_ci	/* memory barrier */
12262306a36Sopenharmony_ci	smp_mb__after_atomic();
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void msm_mdss_irq_unmask(struct irq_data *irqd)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct msm_mdss *msm_mdss = irq_data_get_irq_chip_data(irqd);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* memory barrier */
13062306a36Sopenharmony_ci	smp_mb__before_atomic();
13162306a36Sopenharmony_ci	set_bit(irqd->hwirq, &msm_mdss->irq_controller.enabled_mask);
13262306a36Sopenharmony_ci	/* memory barrier */
13362306a36Sopenharmony_ci	smp_mb__after_atomic();
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct irq_chip msm_mdss_irq_chip = {
13762306a36Sopenharmony_ci	.name = "msm_mdss",
13862306a36Sopenharmony_ci	.irq_mask = msm_mdss_irq_mask,
13962306a36Sopenharmony_ci	.irq_unmask = msm_mdss_irq_unmask,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct lock_class_key msm_mdss_lock_key, msm_mdss_request_key;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int msm_mdss_irqdomain_map(struct irq_domain *domain,
14562306a36Sopenharmony_ci		unsigned int irq, irq_hw_number_t hwirq)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct msm_mdss *msm_mdss = domain->host_data;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	irq_set_lockdep_class(irq, &msm_mdss_lock_key, &msm_mdss_request_key);
15062306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, &msm_mdss_irq_chip, handle_level_irq);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return irq_set_chip_data(irq, msm_mdss);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct irq_domain_ops msm_mdss_irqdomain_ops = {
15662306a36Sopenharmony_ci	.map = msm_mdss_irqdomain_map,
15762306a36Sopenharmony_ci	.xlate = irq_domain_xlate_onecell,
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct device *dev;
16362306a36Sopenharmony_ci	struct irq_domain *domain;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	dev = msm_mdss->dev;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	domain = irq_domain_add_linear(dev->of_node, 32,
16862306a36Sopenharmony_ci			&msm_mdss_irqdomain_ops, msm_mdss);
16962306a36Sopenharmony_ci	if (!domain) {
17062306a36Sopenharmony_ci		dev_err(dev, "failed to add irq_domain\n");
17162306a36Sopenharmony_ci		return -EINVAL;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	msm_mdss->irq_controller.enabled_mask = 0;
17562306a36Sopenharmony_ci	msm_mdss->irq_controller.domain = domain;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return 0;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	const struct msm_mdss_data *data = msm_mdss->mdss_data;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	writel_relaxed(data->ubwc_static, msm_mdss->mmio + UBWC_STATIC);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	const struct msm_mdss_data *data = msm_mdss->mdss_data;
19062306a36Sopenharmony_ci	u32 value = (data->ubwc_swizzle & 0x1) |
19162306a36Sopenharmony_ci		    (data->highest_bank_bit & 0x3) << 4 |
19262306a36Sopenharmony_ci		    (data->macrotile_mode & 0x1) << 12;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (data->ubwc_enc_version == UBWC_3_0)
19562306a36Sopenharmony_ci		value |= BIT(10);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (data->ubwc_enc_version == UBWC_1_0)
19862306a36Sopenharmony_ci		value |= BIT(8);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	const struct msm_mdss_data *data = msm_mdss->mdss_data;
20662306a36Sopenharmony_ci	u32 value = (data->ubwc_swizzle & 0x7) |
20762306a36Sopenharmony_ci		    (data->ubwc_static & 0x1) << 3 |
20862306a36Sopenharmony_ci		    (data->highest_bank_bit & 0x7) << 4 |
20962306a36Sopenharmony_ci		    (data->macrotile_mode & 0x1) << 12;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (data->ubwc_enc_version == UBWC_3_0) {
21462306a36Sopenharmony_ci		writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2);
21562306a36Sopenharmony_ci		writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE);
21662306a36Sopenharmony_ci	} else {
21762306a36Sopenharmony_ci		if (data->ubwc_dec_version == UBWC_4_3)
21862306a36Sopenharmony_ci			writel_relaxed(3, msm_mdss->mmio + UBWC_CTRL_2);
21962306a36Sopenharmony_ci		else
22062306a36Sopenharmony_ci			writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2);
22162306a36Sopenharmony_ci		writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciconst struct msm_mdss_data *msm_mdss_get_mdss_data(struct device *dev)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct msm_mdss *mdss;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (!dev)
23062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	mdss = dev_get_drvdata(dev);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return mdss->mdss_data;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int msm_mdss_enable(struct msm_mdss *msm_mdss)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	int ret;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/*
24262306a36Sopenharmony_ci	 * Several components have AXI clocks that can only be turned on if
24362306a36Sopenharmony_ci	 * the interconnect is enabled (non-zero bandwidth). Let's make sure
24462306a36Sopenharmony_ci	 * that the interconnects are at least at a minimum amount.
24562306a36Sopenharmony_ci	 */
24662306a36Sopenharmony_ci	msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks);
24962306a36Sopenharmony_ci	if (ret) {
25062306a36Sopenharmony_ci		dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret);
25162306a36Sopenharmony_ci		return ret;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/*
25562306a36Sopenharmony_ci	 * Register access requires MDSS_MDP_CLK, which is not enabled by the
25662306a36Sopenharmony_ci	 * mdss on mdp5 hardware. Skip it for now.
25762306a36Sopenharmony_ci	 */
25862306a36Sopenharmony_ci	if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data)
25962306a36Sopenharmony_ci		return 0;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/*
26262306a36Sopenharmony_ci	 * ubwc config is part of the "mdss" region which is not accessible
26362306a36Sopenharmony_ci	 * from the rest of the driver. hardcode known configurations here
26462306a36Sopenharmony_ci	 *
26562306a36Sopenharmony_ci	 * Decoder version can be read from the UBWC_DEC_HW_VERSION reg,
26662306a36Sopenharmony_ci	 * UBWC_n and the rest of params comes from hw data.
26762306a36Sopenharmony_ci	 */
26862306a36Sopenharmony_ci	switch (msm_mdss->mdss_data->ubwc_dec_version) {
26962306a36Sopenharmony_ci	case 0: /* no UBWC */
27062306a36Sopenharmony_ci	case UBWC_1_0:
27162306a36Sopenharmony_ci		/* do nothing */
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case UBWC_2_0:
27462306a36Sopenharmony_ci		msm_mdss_setup_ubwc_dec_20(msm_mdss);
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	case UBWC_3_0:
27762306a36Sopenharmony_ci		msm_mdss_setup_ubwc_dec_30(msm_mdss);
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	case UBWC_4_0:
28062306a36Sopenharmony_ci	case UBWC_4_3:
28162306a36Sopenharmony_ci		msm_mdss_setup_ubwc_dec_40(msm_mdss);
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	default:
28462306a36Sopenharmony_ci		dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n",
28562306a36Sopenharmony_ci			msm_mdss->mdss_data->ubwc_dec_version);
28662306a36Sopenharmony_ci		dev_err(msm_mdss->dev, "HW_REV: 0x%x\n",
28762306a36Sopenharmony_ci			readl_relaxed(msm_mdss->mmio + HW_REV));
28862306a36Sopenharmony_ci		dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n",
28962306a36Sopenharmony_ci			readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION));
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return ret;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int msm_mdss_disable(struct msm_mdss *msm_mdss)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks);
29962306a36Sopenharmony_ci	msm_mdss_icc_request_bw(msm_mdss, 0);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void msm_mdss_destroy(struct msm_mdss *msm_mdss)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(msm_mdss->dev);
30762306a36Sopenharmony_ci	int irq;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	pm_runtime_suspend(msm_mdss->dev);
31062306a36Sopenharmony_ci	pm_runtime_disable(msm_mdss->dev);
31162306a36Sopenharmony_ci	irq_domain_remove(msm_mdss->irq_controller.domain);
31262306a36Sopenharmony_ci	msm_mdss->irq_controller.domain = NULL;
31362306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
31462306a36Sopenharmony_ci	irq_set_chained_handler_and_data(irq, NULL, NULL);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int msm_mdss_reset(struct device *dev)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct reset_control *reset;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	reset = reset_control_get_optional_exclusive(dev, NULL);
32262306a36Sopenharmony_ci	if (!reset) {
32362306a36Sopenharmony_ci		/* Optional reset not specified */
32462306a36Sopenharmony_ci		return 0;
32562306a36Sopenharmony_ci	} else if (IS_ERR(reset)) {
32662306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(reset),
32762306a36Sopenharmony_ci				     "failed to acquire mdss reset\n");
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	reset_control_assert(reset);
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * Tests indicate that reset has to be held for some period of time,
33362306a36Sopenharmony_ci	 * make it one frame in a typical system
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	msleep(20);
33662306a36Sopenharmony_ci	reset_control_deassert(reset);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	reset_control_put(reset);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci/*
34462306a36Sopenharmony_ci * MDP5 MDSS uses at most three specified clocks.
34562306a36Sopenharmony_ci */
34662306a36Sopenharmony_ci#define MDP5_MDSS_NUM_CLOCKS 3
34762306a36Sopenharmony_cistatic int mdp5_mdss_parse_clock(struct platform_device *pdev, struct clk_bulk_data **clocks)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct clk_bulk_data *bulk;
35062306a36Sopenharmony_ci	int num_clocks = 0;
35162306a36Sopenharmony_ci	int ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (!pdev)
35462306a36Sopenharmony_ci		return -EINVAL;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	bulk = devm_kcalloc(&pdev->dev, MDP5_MDSS_NUM_CLOCKS, sizeof(struct clk_bulk_data), GFP_KERNEL);
35762306a36Sopenharmony_ci	if (!bulk)
35862306a36Sopenharmony_ci		return -ENOMEM;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	bulk[num_clocks++].id = "iface";
36162306a36Sopenharmony_ci	bulk[num_clocks++].id = "bus";
36262306a36Sopenharmony_ci	bulk[num_clocks++].id = "vsync";
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ret = devm_clk_bulk_get_optional(&pdev->dev, num_clocks, bulk);
36562306a36Sopenharmony_ci	if (ret)
36662306a36Sopenharmony_ci		return ret;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	*clocks = bulk;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return num_clocks;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct msm_mdss *msm_mdss;
37662306a36Sopenharmony_ci	int ret;
37762306a36Sopenharmony_ci	int irq;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	ret = msm_mdss_reset(&pdev->dev);
38062306a36Sopenharmony_ci	if (ret)
38162306a36Sopenharmony_ci		return ERR_PTR(ret);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	msm_mdss = devm_kzalloc(&pdev->dev, sizeof(*msm_mdss), GFP_KERNEL);
38462306a36Sopenharmony_ci	if (!msm_mdss)
38562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss");
38862306a36Sopenharmony_ci	if (IS_ERR(msm_mdss->mmio))
38962306a36Sopenharmony_ci		return ERR_CAST(msm_mdss->mmio);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss);
39462306a36Sopenharmony_ci	if (ret)
39562306a36Sopenharmony_ci		return ERR_PTR(ret);
39662306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss);
39762306a36Sopenharmony_ci	if (ret)
39862306a36Sopenharmony_ci		return ERR_PTR(ret);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (is_mdp5)
40162306a36Sopenharmony_ci		ret = mdp5_mdss_parse_clock(pdev, &msm_mdss->clocks);
40262306a36Sopenharmony_ci	else
40362306a36Sopenharmony_ci		ret = devm_clk_bulk_get_all(&pdev->dev, &msm_mdss->clocks);
40462306a36Sopenharmony_ci	if (ret < 0) {
40562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to parse clocks, ret=%d\n", ret);
40662306a36Sopenharmony_ci		return ERR_PTR(ret);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci	msm_mdss->num_clocks = ret;
40962306a36Sopenharmony_ci	msm_mdss->is_mdp5 = is_mdp5;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	msm_mdss->dev = &pdev->dev;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
41462306a36Sopenharmony_ci	if (irq < 0)
41562306a36Sopenharmony_ci		return ERR_PTR(irq);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = _msm_mdss_irq_domain_add(msm_mdss);
41862306a36Sopenharmony_ci	if (ret)
41962306a36Sopenharmony_ci		return ERR_PTR(ret);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	irq_set_chained_handler_and_data(irq, msm_mdss_irq,
42262306a36Sopenharmony_ci					 msm_mdss);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return msm_mdss;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int __maybe_unused mdss_runtime_suspend(struct device *dev)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct msm_mdss *mdss = dev_get_drvdata(dev);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	DBG("");
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return msm_mdss_disable(mdss);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic int __maybe_unused mdss_runtime_resume(struct device *dev)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct msm_mdss *mdss = dev_get_drvdata(dev);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	DBG("");
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return msm_mdss_enable(mdss);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int __maybe_unused mdss_pm_suspend(struct device *dev)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (pm_runtime_suspended(dev))
45162306a36Sopenharmony_ci		return 0;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return mdss_runtime_suspend(dev);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int __maybe_unused mdss_pm_resume(struct device *dev)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	if (pm_runtime_suspended(dev))
45962306a36Sopenharmony_ci		return 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return mdss_runtime_resume(dev);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic const struct dev_pm_ops mdss_pm_ops = {
46562306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(mdss_pm_suspend, mdss_pm_resume)
46662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(mdss_runtime_suspend, mdss_runtime_resume, NULL)
46762306a36Sopenharmony_ci};
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int mdss_probe(struct platform_device *pdev)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct msm_mdss *mdss;
47262306a36Sopenharmony_ci	bool is_mdp5 = of_device_is_compatible(pdev->dev.of_node, "qcom,mdss");
47362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
47462306a36Sopenharmony_ci	int ret;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	mdss = msm_mdss_init(pdev, is_mdp5);
47762306a36Sopenharmony_ci	if (IS_ERR(mdss))
47862306a36Sopenharmony_ci		return PTR_ERR(mdss);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	mdss->mdss_data = of_device_get_match_data(&pdev->dev);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	platform_set_drvdata(pdev, mdss);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * MDP5/DPU based devices don't have a flat hierarchy. There is a top
48662306a36Sopenharmony_ci	 * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc.
48762306a36Sopenharmony_ci	 * Populate the children devices, find the MDP5/DPU node, and then add
48862306a36Sopenharmony_ci	 * the interfaces to our components list.
48962306a36Sopenharmony_ci	 */
49062306a36Sopenharmony_ci	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
49162306a36Sopenharmony_ci	if (ret) {
49262306a36Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to populate children devices\n");
49362306a36Sopenharmony_ci		msm_mdss_destroy(mdss);
49462306a36Sopenharmony_ci		return ret;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return 0;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int mdss_remove(struct platform_device *pdev)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct msm_mdss *mdss = platform_get_drvdata(pdev);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	of_platform_depopulate(&pdev->dev);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	msm_mdss_destroy(mdss);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic const struct msm_mdss_data msm8998_data = {
51262306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_1_0,
51362306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_1_0,
51462306a36Sopenharmony_ci	.highest_bank_bit = 2,
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic const struct msm_mdss_data qcm2290_data = {
51862306a36Sopenharmony_ci	/* no UBWC */
51962306a36Sopenharmony_ci	.highest_bank_bit = 0x2,
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic const struct msm_mdss_data sc7180_data = {
52362306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_2_0,
52462306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_2_0,
52562306a36Sopenharmony_ci	.ubwc_static = 0x1e,
52662306a36Sopenharmony_ci	.highest_bank_bit = 0x3,
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic const struct msm_mdss_data sc7280_data = {
53062306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_3_0,
53162306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_4_0,
53262306a36Sopenharmony_ci	.ubwc_swizzle = 6,
53362306a36Sopenharmony_ci	.ubwc_static = 1,
53462306a36Sopenharmony_ci	.highest_bank_bit = 1,
53562306a36Sopenharmony_ci	.macrotile_mode = 1,
53662306a36Sopenharmony_ci};
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic const struct msm_mdss_data sc8180x_data = {
53962306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_3_0,
54062306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_3_0,
54162306a36Sopenharmony_ci	.highest_bank_bit = 3,
54262306a36Sopenharmony_ci	.macrotile_mode = 1,
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic const struct msm_mdss_data sc8280xp_data = {
54662306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_4_0,
54762306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_4_0,
54862306a36Sopenharmony_ci	.ubwc_swizzle = 6,
54962306a36Sopenharmony_ci	.ubwc_static = 1,
55062306a36Sopenharmony_ci	.highest_bank_bit = 2,
55162306a36Sopenharmony_ci	.macrotile_mode = 1,
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic const struct msm_mdss_data sdm845_data = {
55562306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_2_0,
55662306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_2_0,
55762306a36Sopenharmony_ci	.highest_bank_bit = 2,
55862306a36Sopenharmony_ci};
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic const struct msm_mdss_data sm6350_data = {
56162306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_2_0,
56262306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_2_0,
56362306a36Sopenharmony_ci	.ubwc_swizzle = 6,
56462306a36Sopenharmony_ci	.ubwc_static = 0x1e,
56562306a36Sopenharmony_ci	.highest_bank_bit = 1,
56662306a36Sopenharmony_ci};
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic const struct msm_mdss_data sm8150_data = {
56962306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_3_0,
57062306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_3_0,
57162306a36Sopenharmony_ci	.highest_bank_bit = 2,
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic const struct msm_mdss_data sm6115_data = {
57562306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_1_0,
57662306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_2_0,
57762306a36Sopenharmony_ci	.ubwc_swizzle = 7,
57862306a36Sopenharmony_ci	.ubwc_static = 0x11f,
57962306a36Sopenharmony_ci	.highest_bank_bit = 0x1,
58062306a36Sopenharmony_ci};
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic const struct msm_mdss_data sm6125_data = {
58362306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_1_0,
58462306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_3_0,
58562306a36Sopenharmony_ci	.ubwc_swizzle = 1,
58662306a36Sopenharmony_ci	.highest_bank_bit = 1,
58762306a36Sopenharmony_ci};
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic const struct msm_mdss_data sm8250_data = {
59062306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_4_0,
59162306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_4_0,
59262306a36Sopenharmony_ci	.ubwc_swizzle = 6,
59362306a36Sopenharmony_ci	.ubwc_static = 1,
59462306a36Sopenharmony_ci	/* TODO: highest_bank_bit = 2 for LP_DDR4 */
59562306a36Sopenharmony_ci	.highest_bank_bit = 3,
59662306a36Sopenharmony_ci	.macrotile_mode = 1,
59762306a36Sopenharmony_ci};
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic const struct msm_mdss_data sm8550_data = {
60062306a36Sopenharmony_ci	.ubwc_enc_version = UBWC_4_0,
60162306a36Sopenharmony_ci	.ubwc_dec_version = UBWC_4_3,
60262306a36Sopenharmony_ci	.ubwc_swizzle = 6,
60362306a36Sopenharmony_ci	.ubwc_static = 1,
60462306a36Sopenharmony_ci	/* TODO: highest_bank_bit = 2 for LP_DDR4 */
60562306a36Sopenharmony_ci	.highest_bank_bit = 3,
60662306a36Sopenharmony_ci	.macrotile_mode = 1,
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_cistatic const struct of_device_id mdss_dt_match[] = {
60962306a36Sopenharmony_ci	{ .compatible = "qcom,mdss" },
61062306a36Sopenharmony_ci	{ .compatible = "qcom,msm8998-mdss", .data = &msm8998_data },
61162306a36Sopenharmony_ci	{ .compatible = "qcom,qcm2290-mdss", .data = &qcm2290_data },
61262306a36Sopenharmony_ci	{ .compatible = "qcom,sdm845-mdss", .data = &sdm845_data },
61362306a36Sopenharmony_ci	{ .compatible = "qcom,sc7180-mdss", .data = &sc7180_data },
61462306a36Sopenharmony_ci	{ .compatible = "qcom,sc7280-mdss", .data = &sc7280_data },
61562306a36Sopenharmony_ci	{ .compatible = "qcom,sc8180x-mdss", .data = &sc8180x_data },
61662306a36Sopenharmony_ci	{ .compatible = "qcom,sc8280xp-mdss", .data = &sc8280xp_data },
61762306a36Sopenharmony_ci	{ .compatible = "qcom,sm6115-mdss", .data = &sm6115_data },
61862306a36Sopenharmony_ci	{ .compatible = "qcom,sm6125-mdss", .data = &sm6125_data },
61962306a36Sopenharmony_ci	{ .compatible = "qcom,sm6350-mdss", .data = &sm6350_data },
62062306a36Sopenharmony_ci	{ .compatible = "qcom,sm6375-mdss", .data = &sm6350_data },
62162306a36Sopenharmony_ci	{ .compatible = "qcom,sm8150-mdss", .data = &sm8150_data },
62262306a36Sopenharmony_ci	{ .compatible = "qcom,sm8250-mdss", .data = &sm8250_data },
62362306a36Sopenharmony_ci	{ .compatible = "qcom,sm8350-mdss", .data = &sm8250_data },
62462306a36Sopenharmony_ci	{ .compatible = "qcom,sm8450-mdss", .data = &sm8250_data },
62562306a36Sopenharmony_ci	{ .compatible = "qcom,sm8550-mdss", .data = &sm8550_data },
62662306a36Sopenharmony_ci	{}
62762306a36Sopenharmony_ci};
62862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mdss_dt_match);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic struct platform_driver mdss_platform_driver = {
63162306a36Sopenharmony_ci	.probe      = mdss_probe,
63262306a36Sopenharmony_ci	.remove     = mdss_remove,
63362306a36Sopenharmony_ci	.driver     = {
63462306a36Sopenharmony_ci		.name   = "msm-mdss",
63562306a36Sopenharmony_ci		.of_match_table = mdss_dt_match,
63662306a36Sopenharmony_ci		.pm     = &mdss_pm_ops,
63762306a36Sopenharmony_ci	},
63862306a36Sopenharmony_ci};
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_civoid __init msm_mdss_register(void)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	platform_driver_register(&mdss_platform_driver);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_civoid __exit msm_mdss_unregister(void)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	platform_driver_unregister(&mdss_platform_driver);
64862306a36Sopenharmony_ci}
649