16e0832faSShawn Lin // SPDX-License-Identifier: GPL-2.0
26e0832faSShawn Lin /*
36e0832faSShawn Lin  * Qualcomm PCIe root complex driver
46e0832faSShawn Lin  *
56e0832faSShawn Lin  * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
66e0832faSShawn Lin  * Copyright 2015 Linaro Limited.
76e0832faSShawn Lin  *
86e0832faSShawn Lin  * Author: Stanimir Varbanov <svarbanov@mm-sol.com>
96e0832faSShawn Lin  */
106e0832faSShawn Lin 
116e0832faSShawn Lin #include <linux/clk.h>
124c939882SManivannan Sadhasivam #include <linux/crc8.h>
136e0832faSShawn Lin #include <linux/delay.h>
146e0832faSShawn Lin #include <linux/gpio/consumer.h>
15c4860af8SJohan Hovold #include <linux/interconnect.h>
166e0832faSShawn Lin #include <linux/interrupt.h>
176e0832faSShawn Lin #include <linux/io.h>
186e0832faSShawn Lin #include <linux/iopoll.h>
196e0832faSShawn Lin #include <linux/kernel.h>
206e0832faSShawn Lin #include <linux/init.h>
216e0832faSShawn Lin #include <linux/of_device.h>
226e0832faSShawn Lin #include <linux/of_gpio.h>
236e0832faSShawn Lin #include <linux/pci.h>
246e0832faSShawn Lin #include <linux/pm_runtime.h>
256e0832faSShawn Lin #include <linux/platform_device.h>
26f90747d1SDmitry Baryshkov #include <linux/phy/pcie.h>
276e0832faSShawn Lin #include <linux/phy/phy.h>
286e0832faSShawn Lin #include <linux/regulator/consumer.h>
296e0832faSShawn Lin #include <linux/reset.h>
306e0832faSShawn Lin #include <linux/slab.h>
316e0832faSShawn Lin #include <linux/types.h>
326e0832faSShawn Lin 
3351ed2c2bSSham Muthayyan #include "../../pci.h"
346e0832faSShawn Lin #include "pcie-designware.h"
356e0832faSShawn Lin 
36769e49d8SManivannan Sadhasivam /* PARF registers */
3739171b33SManivannan Sadhasivam #define PARF_SYS_CTRL				0x00
38769e49d8SManivannan Sadhasivam #define PARF_PM_CTRL				0x20
39769e49d8SManivannan Sadhasivam #define PARF_PCS_DEEMPH				0x34
40769e49d8SManivannan Sadhasivam #define PARF_PCS_SWING				0x38
41769e49d8SManivannan Sadhasivam #define PARF_PHY_CTRL				0x40
4294ebd232SManivannan Sadhasivam #define PARF_PHY_REFCLK				0x4c
43769e49d8SManivannan Sadhasivam #define PARF_CONFIG_BITS			0x50
44769e49d8SManivannan Sadhasivam #define PARF_DBI_BASE_ADDR			0x168
4594ebd232SManivannan Sadhasivam #define PARF_SLV_ADDR_SPACE_SIZE_2_3_3		0x16c /* Register offset specific to IP ver 2.3.3 */
46769e49d8SManivannan Sadhasivam #define PARF_MHI_CLOCK_RESET_CTRL		0x174
47769e49d8SManivannan Sadhasivam #define PARF_AXI_MSTR_WR_ADDR_HALT		0x178
4894ebd232SManivannan Sadhasivam #define PARF_AXI_MSTR_WR_ADDR_HALT_V2		0x1a8
4994ebd232SManivannan Sadhasivam #define PARF_Q2A_FLUSH				0x1ac
5094ebd232SManivannan Sadhasivam #define PARF_LTSSM				0x1b0
51769e49d8SManivannan Sadhasivam #define PARF_SID_OFFSET				0x234
5294ebd232SManivannan Sadhasivam #define PARF_BDF_TRANSLATE_CFG			0x24c
53769e49d8SManivannan Sadhasivam #define PARF_SLV_ADDR_SPACE_SIZE		0x358
54769e49d8SManivannan Sadhasivam #define PARF_DEVICE_TYPE			0x1000
55769e49d8SManivannan Sadhasivam #define PARF_BDF_TO_SID_TABLE_N			0x2000
56769e49d8SManivannan Sadhasivam 
57769e49d8SManivannan Sadhasivam /* ELBI registers */
58769e49d8SManivannan Sadhasivam #define ELBI_SYS_CTRL				0x04
59769e49d8SManivannan Sadhasivam 
60769e49d8SManivannan Sadhasivam /* DBI registers */
61769e49d8SManivannan Sadhasivam #define AXI_MSTR_RESP_COMP_CTRL0		0x818
62769e49d8SManivannan Sadhasivam #define AXI_MSTR_RESP_COMP_CTRL1		0x81c
6394ebd232SManivannan Sadhasivam #define MISC_CONTROL_1_REG			0x8bc
64769e49d8SManivannan Sadhasivam 
65769e49d8SManivannan Sadhasivam /* PARF_SYS_CTRL register fields */
6617804668SManivannan Sadhasivam #define MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN	BIT(29)
676e0832faSShawn Lin #define MST_WAKEUP_EN				BIT(13)
686e0832faSShawn Lin #define SLV_WAKEUP_EN				BIT(12)
696e0832faSShawn Lin #define MSTR_ACLK_CGC_DIS			BIT(10)
706e0832faSShawn Lin #define SLV_ACLK_CGC_DIS			BIT(9)
716e0832faSShawn Lin #define CORE_CLK_CGC_DIS			BIT(6)
726e0832faSShawn Lin #define AUX_PWR_DET				BIT(4)
736e0832faSShawn Lin #define L23_CLK_RMV_DIS				BIT(2)
746e0832faSShawn Lin #define L1_CLK_RMV_DIS				BIT(1)
756e0832faSShawn Lin 
76769e49d8SManivannan Sadhasivam /* PARF_PM_CTRL register fields */
775147ba8aSKrishna chaitanya chundru #define REQ_NOT_ENTR_L1				BIT(5)
785147ba8aSKrishna chaitanya chundru 
79769e49d8SManivannan Sadhasivam /* PARF_PCS_DEEMPH register fields */
8057eddec8SManivannan Sadhasivam #define PCS_DEEMPH_TX_DEEMPH_GEN1(x)		FIELD_PREP(GENMASK(21, 16), x)
8157eddec8SManivannan Sadhasivam #define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x)	FIELD_PREP(GENMASK(13, 8), x)
8257eddec8SManivannan Sadhasivam #define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x)	FIELD_PREP(GENMASK(5, 0), x)
83769e49d8SManivannan Sadhasivam 
84769e49d8SManivannan Sadhasivam /* PARF_PCS_SWING register fields */
8557eddec8SManivannan Sadhasivam #define PCS_SWING_TX_SWING_FULL(x)		FIELD_PREP(GENMASK(14, 8), x)
8657eddec8SManivannan Sadhasivam #define PCS_SWING_TX_SWING_LOW(x)		FIELD_PREP(GENMASK(6, 0), x)
87769e49d8SManivannan Sadhasivam 
88769e49d8SManivannan Sadhasivam /* PARF_PHY_CTRL register fields */
89de3c4bf6SAnsuel Smith #define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK	GENMASK(20, 16)
9057eddec8SManivannan Sadhasivam #define PHY_CTRL_PHY_TX0_TERM_OFFSET(x)		FIELD_PREP(PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK, x)
9117804668SManivannan Sadhasivam #define PHY_TEST_PWR_DOWN			BIT(0)
92de3c4bf6SAnsuel Smith 
93769e49d8SManivannan Sadhasivam /* PARF_PHY_REFCLK register fields */
94de3c4bf6SAnsuel Smith #define PHY_REFCLK_SSP_EN			BIT(16)
95de3c4bf6SAnsuel Smith #define PHY_REFCLK_USE_PAD			BIT(12)
96de3c4bf6SAnsuel Smith 
97769e49d8SManivannan Sadhasivam /* PARF_CONFIG_BITS register fields */
9857eddec8SManivannan Sadhasivam #define PHY_RX0_EQ(x)				FIELD_PREP(GENMASK(26, 24), x)
99769e49d8SManivannan Sadhasivam 
100769e49d8SManivannan Sadhasivam /* PARF_SLV_ADDR_SPACE_SIZE register value */
101769e49d8SManivannan Sadhasivam #define SLV_ADDR_SPACE_SZ			0x10000000
102769e49d8SManivannan Sadhasivam 
103769e49d8SManivannan Sadhasivam /* PARF_MHI_CLOCK_RESET_CTRL register fields */
1040cf7c2efSSelvam Sathappan Periakaruppan #define AHB_CLK_EN				BIT(0)
1050cf7c2efSSelvam Sathappan Periakaruppan #define MSTR_AXI_CLK_EN				BIT(1)
1060cf7c2efSSelvam Sathappan Periakaruppan #define BYPASS					BIT(4)
1070cf7c2efSSelvam Sathappan Periakaruppan 
10817804668SManivannan Sadhasivam /* PARF_AXI_MSTR_WR_ADDR_HALT register fields */
10917804668SManivannan Sadhasivam #define EN					BIT(31)
11017804668SManivannan Sadhasivam 
11117804668SManivannan Sadhasivam /* PARF_LTSSM register fields */
11217804668SManivannan Sadhasivam #define LTSSM_EN				BIT(8)
11317804668SManivannan Sadhasivam 
114769e49d8SManivannan Sadhasivam /* PARF_DEVICE_TYPE register fields */
115769e49d8SManivannan Sadhasivam #define DEVICE_TYPE_RC				0x4
1166e0832faSShawn Lin 
117769e49d8SManivannan Sadhasivam /* ELBI_SYS_CTRL register fields */
11839171b33SManivannan Sadhasivam #define ELBI_SYS_CTRL_LT_ENABLE			BIT(0)
1196e0832faSShawn Lin 
120769e49d8SManivannan Sadhasivam /* AXI_MSTR_RESP_COMP_CTRL0 register fields */
1216e0832faSShawn Lin #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K	0x4
1226e0832faSShawn Lin #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_4K	0x5
123769e49d8SManivannan Sadhasivam 
124769e49d8SManivannan Sadhasivam /* AXI_MSTR_RESP_COMP_CTRL1 register fields */
1256e0832faSShawn Lin #define CFG_BRIDGE_SB_INIT			BIT(0)
1266e0832faSShawn Lin 
127769e49d8SManivannan Sadhasivam /* MISC_CONTROL_1_REG register fields */
128769e49d8SManivannan Sadhasivam #define DBI_RO_WR_EN				1
129769e49d8SManivannan Sadhasivam 
130769e49d8SManivannan Sadhasivam /* PCI_EXP_SLTCAP register fields */
131769e49d8SManivannan Sadhasivam #define PCIE_CAP_SLOT_POWER_LIMIT_VAL		FIELD_PREP(PCI_EXP_SLTCAP_SPLV, 250)
132769e49d8SManivannan Sadhasivam #define PCIE_CAP_SLOT_POWER_LIMIT_SCALE		FIELD_PREP(PCI_EXP_SLTCAP_SPLS, 1)
1339a765805SBaruch Siach #define PCIE_CAP_SLOT_VAL			(PCI_EXP_SLTCAP_ABP | \
1349a765805SBaruch Siach 						PCI_EXP_SLTCAP_PCP | \
1359a765805SBaruch Siach 						PCI_EXP_SLTCAP_MRLSP | \
1369a765805SBaruch Siach 						PCI_EXP_SLTCAP_AIP | \
1379a765805SBaruch Siach 						PCI_EXP_SLTCAP_PIP | \
1389a765805SBaruch Siach 						PCI_EXP_SLTCAP_HPS | \
1399a765805SBaruch Siach 						PCI_EXP_SLTCAP_HPC | \
1409a765805SBaruch Siach 						PCI_EXP_SLTCAP_EIP | \
1419a765805SBaruch Siach 						PCIE_CAP_SLOT_POWER_LIMIT_VAL | \
1429a765805SBaruch Siach 						PCIE_CAP_SLOT_POWER_LIMIT_SCALE)
1436e0832faSShawn Lin 
1446e0832faSShawn Lin #define PERST_DELAY_US				1000
145ed8cc3b1SBjorn Andersson 
1464c939882SManivannan Sadhasivam #define QCOM_PCIE_CRC8_POLYNOMIAL		(BIT(2) | BIT(1) | BIT(0))
1474c939882SManivannan Sadhasivam 
1485d4ffe5eSManivannan Sadhasivam #define QCOM_PCIE_1_0_0_MAX_CLOCKS		4
1496e0832faSShawn Lin struct qcom_pcie_resources_1_0_0 {
1505d4ffe5eSManivannan Sadhasivam 	struct clk_bulk_data clks[QCOM_PCIE_1_0_0_MAX_CLOCKS];
1516e0832faSShawn Lin 	struct reset_control *core;
1526e0832faSShawn Lin 	struct regulator *vdda;
1536e0832faSShawn Lin };
1546e0832faSShawn Lin 
155383215ddSManivannan Sadhasivam #define QCOM_PCIE_2_1_0_MAX_CLOCKS		5
156383215ddSManivannan Sadhasivam #define QCOM_PCIE_2_1_0_MAX_RESETS		6
157383215ddSManivannan Sadhasivam #define QCOM_PCIE_2_1_0_MAX_SUPPLY		3
158383215ddSManivannan Sadhasivam struct qcom_pcie_resources_2_1_0 {
159383215ddSManivannan Sadhasivam 	struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
160383215ddSManivannan Sadhasivam 	struct reset_control_bulk_data resets[QCOM_PCIE_2_1_0_MAX_RESETS];
161383215ddSManivannan Sadhasivam 	int num_resets;
162383215ddSManivannan Sadhasivam 	struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
163383215ddSManivannan Sadhasivam };
164383215ddSManivannan Sadhasivam 
1655329bcc4SManivannan Sadhasivam #define QCOM_PCIE_2_3_2_MAX_CLOCKS		4
1666e0832faSShawn Lin #define QCOM_PCIE_2_3_2_MAX_SUPPLY		2
1676e0832faSShawn Lin struct qcom_pcie_resources_2_3_2 {
1685329bcc4SManivannan Sadhasivam 	struct clk_bulk_data clks[QCOM_PCIE_2_3_2_MAX_CLOCKS];
1696e0832faSShawn Lin 	struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
1706e0832faSShawn Lin };
1716e0832faSShawn Lin 
172*b699ed9bSManivannan Sadhasivam #define QCOM_PCIE_2_3_3_MAX_CLOCKS		5
173*b699ed9bSManivannan Sadhasivam struct qcom_pcie_resources_2_3_3 {
174*b699ed9bSManivannan Sadhasivam 	struct clk_bulk_data clks[QCOM_PCIE_2_3_3_MAX_CLOCKS];
175*b699ed9bSManivannan Sadhasivam 	struct reset_control *rst[7];
176*b699ed9bSManivannan Sadhasivam };
177*b699ed9bSManivannan Sadhasivam 
17867021ae0SBjorn Andersson #define QCOM_PCIE_2_4_0_MAX_CLOCKS	4
1796e0832faSShawn Lin struct qcom_pcie_resources_2_4_0 {
1805aa18097SBjorn Andersson 	struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
1815aa18097SBjorn Andersson 	int num_clks;
1826e0832faSShawn Lin 	struct reset_control *axi_m_reset;
1836e0832faSShawn Lin 	struct reset_control *axi_s_reset;
1846e0832faSShawn Lin 	struct reset_control *pipe_reset;
1856e0832faSShawn Lin 	struct reset_control *axi_m_vmid_reset;
1866e0832faSShawn Lin 	struct reset_control *axi_s_xpu_reset;
1876e0832faSShawn Lin 	struct reset_control *parf_reset;
1886e0832faSShawn Lin 	struct reset_control *phy_reset;
1896e0832faSShawn Lin 	struct reset_control *axi_m_sticky_reset;
1906e0832faSShawn Lin 	struct reset_control *pipe_sticky_reset;
1916e0832faSShawn Lin 	struct reset_control *pwr_reset;
1926e0832faSShawn Lin 	struct reset_control *ahb_reset;
1936e0832faSShawn Lin 	struct reset_control *phy_ahb_reset;
1946e0832faSShawn Lin };
1956e0832faSShawn Lin 
1967081556fSDmitry Baryshkov /* 6 clocks typically, 7 for sm8250 */
197ed8cc3b1SBjorn Andersson struct qcom_pcie_resources_2_7_0 {
19870574511SJohan Hovold 	struct clk_bulk_data clks[12];
1997081556fSDmitry Baryshkov 	int num_clks;
200ed8cc3b1SBjorn Andersson 	struct regulator_bulk_data supplies[2];
201ed8cc3b1SBjorn Andersson 	struct reset_control *pci_reset;
202ed8cc3b1SBjorn Andersson };
203ed8cc3b1SBjorn Andersson 
2040cf7c2efSSelvam Sathappan Periakaruppan struct qcom_pcie_resources_2_9_0 {
2050cf7c2efSSelvam Sathappan Periakaruppan 	struct clk_bulk_data clks[5];
2060cf7c2efSSelvam Sathappan Periakaruppan 	struct reset_control *rst;
2076e0832faSShawn Lin };
2086e0832faSShawn Lin 
2096e0832faSShawn Lin union qcom_pcie_resources {
2106e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 v1_0_0;
2116e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 v2_1_0;
2126e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 v2_3_2;
2136e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 v2_3_3;
2146e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 v2_4_0;
215ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 v2_7_0;
2160cf7c2efSSelvam Sathappan Periakaruppan 	struct qcom_pcie_resources_2_9_0 v2_9_0;
2176e0832faSShawn Lin };
2186e0832faSShawn Lin 
2196e0832faSShawn Lin struct qcom_pcie;
2206e0832faSShawn Lin 
2216e0832faSShawn Lin struct qcom_pcie_ops {
2226e0832faSShawn Lin 	int (*get_resources)(struct qcom_pcie *pcie);
2236e0832faSShawn Lin 	int (*init)(struct qcom_pcie *pcie);
2246e0832faSShawn Lin 	int (*post_init)(struct qcom_pcie *pcie);
2256e0832faSShawn Lin 	void (*deinit)(struct qcom_pcie *pcie);
2266e0832faSShawn Lin 	void (*ltssm_enable)(struct qcom_pcie *pcie);
2274c939882SManivannan Sadhasivam 	int (*config_sid)(struct qcom_pcie *pcie);
2286e0832faSShawn Lin };
2296e0832faSShawn Lin 
230b89ff410SPrasad Malisetty struct qcom_pcie_cfg {
231b89ff410SPrasad Malisetty 	const struct qcom_pcie_ops *ops;
232b89ff410SPrasad Malisetty };
233b89ff410SPrasad Malisetty 
2346e0832faSShawn Lin struct qcom_pcie {
2356e0832faSShawn Lin 	struct dw_pcie *pci;
2366e0832faSShawn Lin 	void __iomem *parf;			/* DT parf */
2376e0832faSShawn Lin 	void __iomem *elbi;			/* DT elbi */
2386e0832faSShawn Lin 	union qcom_pcie_resources res;
2396e0832faSShawn Lin 	struct phy *phy;
2406e0832faSShawn Lin 	struct gpio_desc *reset;
241c4860af8SJohan Hovold 	struct icc_path *icc_mem;
242f94c35e0SDmitry Baryshkov 	const struct qcom_pcie_cfg *cfg;
2436e0832faSShawn Lin };
2446e0832faSShawn Lin 
2456e0832faSShawn Lin #define to_qcom_pcie(x)		dev_get_drvdata((x)->dev)
2466e0832faSShawn Lin 
2476e0832faSShawn Lin static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
2486e0832faSShawn Lin {
2496e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 1);
2506e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2516e0832faSShawn Lin }
2526e0832faSShawn Lin 
2536e0832faSShawn Lin static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
2546e0832faSShawn Lin {
25564adde31SNiklas Cassel 	/* Ensure that PERST has been asserted for at least 100 ms */
25664adde31SNiklas Cassel 	msleep(100);
2576e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 0);
2586e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2596e0832faSShawn Lin }
2606e0832faSShawn Lin 
261886a9c13SRob Herring static int qcom_pcie_start_link(struct dw_pcie *pci)
2626e0832faSShawn Lin {
263886a9c13SRob Herring 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
2646e0832faSShawn Lin 
2656e0832faSShawn Lin 	/* Enable Link Training state machine */
266f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->ltssm_enable)
267f94c35e0SDmitry Baryshkov 		pcie->cfg->ops->ltssm_enable(pcie);
2686e0832faSShawn Lin 
269886a9c13SRob Herring 	return 0;
2706e0832faSShawn Lin }
2716e0832faSShawn Lin 
2726e0832faSShawn Lin static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
2736e0832faSShawn Lin {
2746e0832faSShawn Lin 	u32 val;
2756e0832faSShawn Lin 
2766e0832faSShawn Lin 	/* enable link training */
27739171b33SManivannan Sadhasivam 	val = readl(pcie->elbi + ELBI_SYS_CTRL);
27839171b33SManivannan Sadhasivam 	val |= ELBI_SYS_CTRL_LT_ENABLE;
27939171b33SManivannan Sadhasivam 	writel(val, pcie->elbi + ELBI_SYS_CTRL);
2806e0832faSShawn Lin }
2816e0832faSShawn Lin 
2826e0832faSShawn Lin static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
2836e0832faSShawn Lin {
2846e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
2856e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
2866e0832faSShawn Lin 	struct device *dev = pci->dev;
287383215ddSManivannan Sadhasivam 	bool is_apq = of_device_is_compatible(dev->of_node, "qcom,pcie-apq8064");
2886e0832faSShawn Lin 	int ret;
2896e0832faSShawn Lin 
2906e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
2916e0832faSShawn Lin 	res->supplies[1].supply = "vdda_phy";
2926e0832faSShawn Lin 	res->supplies[2].supply = "vdda_refclk";
2936e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
2946e0832faSShawn Lin 				      res->supplies);
2956e0832faSShawn Lin 	if (ret)
2966e0832faSShawn Lin 		return ret;
2976e0832faSShawn Lin 
2986a114526SAnsuel Smith 	res->clks[0].id = "iface";
2996a114526SAnsuel Smith 	res->clks[1].id = "core";
3006a114526SAnsuel Smith 	res->clks[2].id = "phy";
3016a114526SAnsuel Smith 	res->clks[3].id = "aux";
3026a114526SAnsuel Smith 	res->clks[4].id = "ref";
3036e0832faSShawn Lin 
3046a114526SAnsuel Smith 	/* iface, core, phy are required */
3056a114526SAnsuel Smith 	ret = devm_clk_bulk_get(dev, 3, res->clks);
3066a114526SAnsuel Smith 	if (ret < 0)
3076a114526SAnsuel Smith 		return ret;
3086e0832faSShawn Lin 
3096a114526SAnsuel Smith 	/* aux, ref are optional */
3106a114526SAnsuel Smith 	ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3);
3116a114526SAnsuel Smith 	if (ret < 0)
3126a114526SAnsuel Smith 		return ret;
3138b6f0330SAnsuel Smith 
314383215ddSManivannan Sadhasivam 	res->resets[0].id = "pci";
315383215ddSManivannan Sadhasivam 	res->resets[1].id = "axi";
316383215ddSManivannan Sadhasivam 	res->resets[2].id = "ahb";
317383215ddSManivannan Sadhasivam 	res->resets[3].id = "por";
318383215ddSManivannan Sadhasivam 	res->resets[4].id = "phy";
319383215ddSManivannan Sadhasivam 	res->resets[5].id = "ext";
3206e0832faSShawn Lin 
321383215ddSManivannan Sadhasivam 	/* ext is optional on APQ8016 */
322383215ddSManivannan Sadhasivam 	res->num_resets = is_apq ? 5 : 6;
323383215ddSManivannan Sadhasivam 	ret = devm_reset_control_bulk_get_exclusive(dev, res->num_resets, res->resets);
324383215ddSManivannan Sadhasivam 	if (ret < 0)
325383215ddSManivannan Sadhasivam 		return ret;
3266e0832faSShawn Lin 
327383215ddSManivannan Sadhasivam 	return 0;
3286e0832faSShawn Lin }
3296e0832faSShawn Lin 
3306e0832faSShawn Lin static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
3316e0832faSShawn Lin {
3326e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
3336e0832faSShawn Lin 
3346a114526SAnsuel Smith 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
335383215ddSManivannan Sadhasivam 	reset_control_bulk_assert(res->num_resets, res->resets);
336d3d4d028SAnsuel Smith 
33739171b33SManivannan Sadhasivam 	writel(1, pcie->parf + PARF_PHY_CTRL);
338d3d4d028SAnsuel Smith 
3396e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
3406e0832faSShawn Lin }
3416e0832faSShawn Lin 
3426e0832faSShawn Lin static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
3436e0832faSShawn Lin {
3446e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
3456e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
3466e0832faSShawn Lin 	struct device *dev = pci->dev;
3476e0832faSShawn Lin 	int ret;
3486e0832faSShawn Lin 
349d3d4d028SAnsuel Smith 	/* reset the PCIe interface as uboot can leave it undefined state */
350383215ddSManivannan Sadhasivam 	ret = reset_control_bulk_assert(res->num_resets, res->resets);
351383215ddSManivannan Sadhasivam 	if (ret < 0) {
352383215ddSManivannan Sadhasivam 		dev_err(dev, "cannot assert resets\n");
353383215ddSManivannan Sadhasivam 		return ret;
354383215ddSManivannan Sadhasivam 	}
355d3d4d028SAnsuel Smith 
3566e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
3576e0832faSShawn Lin 	if (ret < 0) {
3586e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
3596e0832faSShawn Lin 		return ret;
3606e0832faSShawn Lin 	}
3616e0832faSShawn Lin 
362383215ddSManivannan Sadhasivam 	ret = reset_control_bulk_deassert(res->num_resets, res->resets);
363383215ddSManivannan Sadhasivam 	if (ret < 0) {
364383215ddSManivannan Sadhasivam 		dev_err(dev, "cannot deassert resets\n");
365383215ddSManivannan Sadhasivam 		regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
366383215ddSManivannan Sadhasivam 		return ret;
3676a114526SAnsuel Smith 	}
3686a114526SAnsuel Smith 
36936d9018dSRobert Marko 	return 0;
37036d9018dSRobert Marko }
37136d9018dSRobert Marko 
37236d9018dSRobert Marko static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie)
37336d9018dSRobert Marko {
37436d9018dSRobert Marko 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
37536d9018dSRobert Marko 	struct dw_pcie *pci = pcie->pci;
37636d9018dSRobert Marko 	struct device *dev = pci->dev;
37736d9018dSRobert Marko 	struct device_node *node = dev->of_node;
37836d9018dSRobert Marko 	u32 val;
37936d9018dSRobert Marko 	int ret;
3806a114526SAnsuel Smith 
3816e0832faSShawn Lin 	/* enable PCIe clocks and resets */
38239171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
38317804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
38439171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
3856e0832faSShawn Lin 
38638f897aeSChristian Marangi 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
38738f897aeSChristian Marangi 	if (ret)
38836d9018dSRobert Marko 		return ret;
38938f897aeSChristian Marangi 
3908df093feSAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
3918df093feSAnsuel Smith 	    of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
3925149901eSAnsuel Smith 		writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
3935149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
3945149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
39539171b33SManivannan Sadhasivam 		       pcie->parf + PARF_PCS_DEEMPH);
3965149901eSAnsuel Smith 		writel(PCS_SWING_TX_SWING_FULL(120) |
3975149901eSAnsuel Smith 			       PCS_SWING_TX_SWING_LOW(120),
39839171b33SManivannan Sadhasivam 		       pcie->parf + PARF_PCS_SWING);
39939171b33SManivannan Sadhasivam 		writel(PHY_RX0_EQ(4), pcie->parf + PARF_CONFIG_BITS);
4005149901eSAnsuel Smith 	}
4015149901eSAnsuel Smith 
402de3c4bf6SAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
403de3c4bf6SAnsuel Smith 		/* set TX termination offset */
40439171b33SManivannan Sadhasivam 		val = readl(pcie->parf + PARF_PHY_CTRL);
405de3c4bf6SAnsuel Smith 		val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
406de3c4bf6SAnsuel Smith 		val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
40739171b33SManivannan Sadhasivam 		writel(val, pcie->parf + PARF_PHY_CTRL);
408de3c4bf6SAnsuel Smith 	}
409de3c4bf6SAnsuel Smith 
4106e0832faSShawn Lin 	/* enable external reference clock */
41139171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_REFCLK);
4122cfef197SAnsuel Smith 	/* USE_PAD is required only for ipq806x */
4132cfef197SAnsuel Smith 	if (!of_device_is_compatible(node, "qcom,pcie-apq8064"))
414de3c4bf6SAnsuel Smith 		val &= ~PHY_REFCLK_USE_PAD;
415de3c4bf6SAnsuel Smith 	val |= PHY_REFCLK_SSP_EN;
41639171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_REFCLK);
4176e0832faSShawn Lin 
4186e0832faSShawn Lin 	/* wait for clock acquisition */
4196e0832faSShawn Lin 	usleep_range(1000, 1500);
4206e0832faSShawn Lin 
4216e0832faSShawn Lin 	/* Set the Max TLP size to 2K, instead of using default of 4K */
4226e0832faSShawn Lin 	writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
42339171b33SManivannan Sadhasivam 	       pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL0);
4246e0832faSShawn Lin 	writel(CFG_BRIDGE_SB_INIT,
42539171b33SManivannan Sadhasivam 	       pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1);
4266e0832faSShawn Lin 
4276e0832faSShawn Lin 	return 0;
4286e0832faSShawn Lin }
4296e0832faSShawn Lin 
4306e0832faSShawn Lin static int qcom_pcie_get_resources_1_0_0(struct qcom_pcie *pcie)
4316e0832faSShawn Lin {
4326e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4336e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
4346e0832faSShawn Lin 	struct device *dev = pci->dev;
4355d4ffe5eSManivannan Sadhasivam 	int ret;
4366e0832faSShawn Lin 
4376e0832faSShawn Lin 	res->vdda = devm_regulator_get(dev, "vdda");
4386e0832faSShawn Lin 	if (IS_ERR(res->vdda))
4396e0832faSShawn Lin 		return PTR_ERR(res->vdda);
4406e0832faSShawn Lin 
4415d4ffe5eSManivannan Sadhasivam 	res->clks[0].id = "iface";
4425d4ffe5eSManivannan Sadhasivam 	res->clks[1].id = "aux";
4435d4ffe5eSManivannan Sadhasivam 	res->clks[2].id = "master_bus";
4445d4ffe5eSManivannan Sadhasivam 	res->clks[3].id = "slave_bus";
4456e0832faSShawn Lin 
4465d4ffe5eSManivannan Sadhasivam 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
4475d4ffe5eSManivannan Sadhasivam 	if (ret < 0)
4485d4ffe5eSManivannan Sadhasivam 		return ret;
4496e0832faSShawn Lin 
4506e0832faSShawn Lin 	res->core = devm_reset_control_get_exclusive(dev, "core");
4516e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->core);
4526e0832faSShawn Lin }
4536e0832faSShawn Lin 
4546e0832faSShawn Lin static void qcom_pcie_deinit_1_0_0(struct qcom_pcie *pcie)
4556e0832faSShawn Lin {
4566e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4576e0832faSShawn Lin 
4586e0832faSShawn Lin 	reset_control_assert(res->core);
4595d4ffe5eSManivannan Sadhasivam 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
4606e0832faSShawn Lin 	regulator_disable(res->vdda);
4616e0832faSShawn Lin }
4626e0832faSShawn Lin 
4636e0832faSShawn Lin static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie)
4646e0832faSShawn Lin {
4656e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4666e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
4676e0832faSShawn Lin 	struct device *dev = pci->dev;
4686e0832faSShawn Lin 	int ret;
4696e0832faSShawn Lin 
4706e0832faSShawn Lin 	ret = reset_control_deassert(res->core);
4716e0832faSShawn Lin 	if (ret) {
4726e0832faSShawn Lin 		dev_err(dev, "cannot deassert core reset\n");
4736e0832faSShawn Lin 		return ret;
4746e0832faSShawn Lin 	}
4756e0832faSShawn Lin 
4765d4ffe5eSManivannan Sadhasivam 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
4776e0832faSShawn Lin 	if (ret) {
4785d4ffe5eSManivannan Sadhasivam 		dev_err(dev, "cannot prepare/enable clocks\n");
4795d4ffe5eSManivannan Sadhasivam 		goto err_assert_reset;
4806e0832faSShawn Lin 	}
4816e0832faSShawn Lin 
4826e0832faSShawn Lin 	ret = regulator_enable(res->vdda);
4836e0832faSShawn Lin 	if (ret) {
4846e0832faSShawn Lin 		dev_err(dev, "cannot enable vdda regulator\n");
4855d4ffe5eSManivannan Sadhasivam 		goto err_disable_clks;
4866e0832faSShawn Lin 	}
4876e0832faSShawn Lin 
4886e0832faSShawn Lin 	return 0;
4895d4ffe5eSManivannan Sadhasivam 
4905d4ffe5eSManivannan Sadhasivam err_disable_clks:
4915d4ffe5eSManivannan Sadhasivam 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
4925d4ffe5eSManivannan Sadhasivam err_assert_reset:
4936e0832faSShawn Lin 	reset_control_assert(res->core);
4946e0832faSShawn Lin 
4956e0832faSShawn Lin 	return ret;
4966e0832faSShawn Lin }
4976e0832faSShawn Lin 
49836d9018dSRobert Marko static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
49936d9018dSRobert Marko {
50036d9018dSRobert Marko 	/* change DBI base address */
50139171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
50236d9018dSRobert Marko 
50336d9018dSRobert Marko 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
50439171b33SManivannan Sadhasivam 		u32 val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT);
50536d9018dSRobert Marko 
50617804668SManivannan Sadhasivam 		val |= EN;
50739171b33SManivannan Sadhasivam 		writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT);
50836d9018dSRobert Marko 	}
50936d9018dSRobert Marko 
51036d9018dSRobert Marko 	return 0;
51136d9018dSRobert Marko }
51236d9018dSRobert Marko 
5136e0832faSShawn Lin static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
5146e0832faSShawn Lin {
5156e0832faSShawn Lin 	u32 val;
5166e0832faSShawn Lin 
5176e0832faSShawn Lin 	/* enable link training */
51839171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_LTSSM);
51917804668SManivannan Sadhasivam 	val |= LTSSM_EN;
52039171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_LTSSM);
5216e0832faSShawn Lin }
5226e0832faSShawn Lin 
5236e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
5246e0832faSShawn Lin {
5256e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
5266e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
5276e0832faSShawn Lin 	struct device *dev = pci->dev;
5286e0832faSShawn Lin 	int ret;
5296e0832faSShawn Lin 
5306e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
5316e0832faSShawn Lin 	res->supplies[1].supply = "vddpe-3v3";
5326e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
5336e0832faSShawn Lin 				      res->supplies);
5346e0832faSShawn Lin 	if (ret)
5356e0832faSShawn Lin 		return ret;
5366e0832faSShawn Lin 
5375329bcc4SManivannan Sadhasivam 	res->clks[0].id = "aux";
5385329bcc4SManivannan Sadhasivam 	res->clks[1].id = "cfg";
5395329bcc4SManivannan Sadhasivam 	res->clks[2].id = "bus_master";
5405329bcc4SManivannan Sadhasivam 	res->clks[3].id = "bus_slave";
5416e0832faSShawn Lin 
5425329bcc4SManivannan Sadhasivam 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
5435329bcc4SManivannan Sadhasivam 	if (ret < 0)
5445329bcc4SManivannan Sadhasivam 		return ret;
5456e0832faSShawn Lin 
546affac98aSDmitry Baryshkov 	return 0;
5476e0832faSShawn Lin }
5486e0832faSShawn Lin 
5496e0832faSShawn Lin static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
5506e0832faSShawn Lin {
5516e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
5526e0832faSShawn Lin 
5535329bcc4SManivannan Sadhasivam 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
5546e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
5556e0832faSShawn Lin }
5566e0832faSShawn Lin 
5576e0832faSShawn Lin static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
5586e0832faSShawn Lin {
5596e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
5606e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
5616e0832faSShawn Lin 	struct device *dev = pci->dev;
5626e0832faSShawn Lin 	int ret;
5636e0832faSShawn Lin 
5646e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
5656e0832faSShawn Lin 	if (ret < 0) {
5666e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
5676e0832faSShawn Lin 		return ret;
5686e0832faSShawn Lin 	}
5696e0832faSShawn Lin 
5705329bcc4SManivannan Sadhasivam 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
5716e0832faSShawn Lin 	if (ret) {
5725329bcc4SManivannan Sadhasivam 		dev_err(dev, "cannot prepare/enable clocks\n");
5735329bcc4SManivannan Sadhasivam 		regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
5745329bcc4SManivannan Sadhasivam 		return ret;
5756e0832faSShawn Lin 	}
5766e0832faSShawn Lin 
5776e0832faSShawn Lin 	return 0;
5786e0832faSShawn Lin }
5796e0832faSShawn Lin 
5806e0832faSShawn Lin static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
5816e0832faSShawn Lin {
58236d9018dSRobert Marko 	u32 val;
5836e0832faSShawn Lin 
5846e0832faSShawn Lin 	/* enable PCIe clocks and resets */
58539171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
58617804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
58739171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
5886e0832faSShawn Lin 
5896e0832faSShawn Lin 	/* change DBI base address */
59039171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
5916e0832faSShawn Lin 
5926e0832faSShawn Lin 	/* MAC PHY_POWERDOWN MUX DISABLE  */
59339171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_SYS_CTRL);
59417804668SManivannan Sadhasivam 	val &= ~MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN;
59539171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_SYS_CTRL);
5966e0832faSShawn Lin 
59739171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
59817804668SManivannan Sadhasivam 	val |= BYPASS;
59939171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
6006e0832faSShawn Lin 
60139171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
60217804668SManivannan Sadhasivam 	val |= EN;
60339171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
6046e0832faSShawn Lin 
6056e0832faSShawn Lin 	return 0;
6066e0832faSShawn Lin }
6076e0832faSShawn Lin 
6086e0832faSShawn Lin static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
6096e0832faSShawn Lin {
6106e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
6116e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
6126e0832faSShawn Lin 	struct device *dev = pci->dev;
61367021ae0SBjorn Andersson 	bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
6145aa18097SBjorn Andersson 	int ret;
6156e0832faSShawn Lin 
6165aa18097SBjorn Andersson 	res->clks[0].id = "aux";
6175aa18097SBjorn Andersson 	res->clks[1].id = "master_bus";
6185aa18097SBjorn Andersson 	res->clks[2].id = "slave_bus";
61967021ae0SBjorn Andersson 	res->clks[3].id = "iface";
6206e0832faSShawn Lin 
62167021ae0SBjorn Andersson 	/* qcom,pcie-ipq4019 is defined without "iface" */
62267021ae0SBjorn Andersson 	res->num_clks = is_ipq ? 3 : 4;
6236e0832faSShawn Lin 
6245aa18097SBjorn Andersson 	ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
6255aa18097SBjorn Andersson 	if (ret < 0)
6265aa18097SBjorn Andersson 		return ret;
6276e0832faSShawn Lin 
6286e0832faSShawn Lin 	res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
6296e0832faSShawn Lin 	if (IS_ERR(res->axi_m_reset))
6306e0832faSShawn Lin 		return PTR_ERR(res->axi_m_reset);
6316e0832faSShawn Lin 
6326e0832faSShawn Lin 	res->axi_s_reset = devm_reset_control_get_exclusive(dev, "axi_s");
6336e0832faSShawn Lin 	if (IS_ERR(res->axi_s_reset))
6346e0832faSShawn Lin 		return PTR_ERR(res->axi_s_reset);
6356e0832faSShawn Lin 
63667021ae0SBjorn Andersson 	if (is_ipq) {
63767021ae0SBjorn Andersson 		/*
63867021ae0SBjorn Andersson 		 * These resources relates to the PHY or are secure clocks, but
63967021ae0SBjorn Andersson 		 * are controlled here for IPQ4019
64067021ae0SBjorn Andersson 		 */
6416e0832faSShawn Lin 		res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
6426e0832faSShawn Lin 		if (IS_ERR(res->pipe_reset))
6436e0832faSShawn Lin 			return PTR_ERR(res->pipe_reset);
6446e0832faSShawn Lin 
6456e0832faSShawn Lin 		res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
6466e0832faSShawn Lin 									 "axi_m_vmid");
6476e0832faSShawn Lin 		if (IS_ERR(res->axi_m_vmid_reset))
6486e0832faSShawn Lin 			return PTR_ERR(res->axi_m_vmid_reset);
6496e0832faSShawn Lin 
6506e0832faSShawn Lin 		res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
6516e0832faSShawn Lin 									"axi_s_xpu");
6526e0832faSShawn Lin 		if (IS_ERR(res->axi_s_xpu_reset))
6536e0832faSShawn Lin 			return PTR_ERR(res->axi_s_xpu_reset);
6546e0832faSShawn Lin 
6556e0832faSShawn Lin 		res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
6566e0832faSShawn Lin 		if (IS_ERR(res->parf_reset))
6576e0832faSShawn Lin 			return PTR_ERR(res->parf_reset);
6586e0832faSShawn Lin 
6596e0832faSShawn Lin 		res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
6606e0832faSShawn Lin 		if (IS_ERR(res->phy_reset))
6616e0832faSShawn Lin 			return PTR_ERR(res->phy_reset);
66267021ae0SBjorn Andersson 	}
6636e0832faSShawn Lin 
6646e0832faSShawn Lin 	res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
6656e0832faSShawn Lin 								   "axi_m_sticky");
6666e0832faSShawn Lin 	if (IS_ERR(res->axi_m_sticky_reset))
6676e0832faSShawn Lin 		return PTR_ERR(res->axi_m_sticky_reset);
6686e0832faSShawn Lin 
6696e0832faSShawn Lin 	res->pipe_sticky_reset = devm_reset_control_get_exclusive(dev,
6706e0832faSShawn Lin 								  "pipe_sticky");
6716e0832faSShawn Lin 	if (IS_ERR(res->pipe_sticky_reset))
6726e0832faSShawn Lin 		return PTR_ERR(res->pipe_sticky_reset);
6736e0832faSShawn Lin 
6746e0832faSShawn Lin 	res->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr");
6756e0832faSShawn Lin 	if (IS_ERR(res->pwr_reset))
6766e0832faSShawn Lin 		return PTR_ERR(res->pwr_reset);
6776e0832faSShawn Lin 
6786e0832faSShawn Lin 	res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
6796e0832faSShawn Lin 	if (IS_ERR(res->ahb_reset))
6806e0832faSShawn Lin 		return PTR_ERR(res->ahb_reset);
6816e0832faSShawn Lin 
68267021ae0SBjorn Andersson 	if (is_ipq) {
6836e0832faSShawn Lin 		res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
6846e0832faSShawn Lin 		if (IS_ERR(res->phy_ahb_reset))
6856e0832faSShawn Lin 			return PTR_ERR(res->phy_ahb_reset);
68667021ae0SBjorn Andersson 	}
6876e0832faSShawn Lin 
6886e0832faSShawn Lin 	return 0;
6896e0832faSShawn Lin }
6906e0832faSShawn Lin 
6916e0832faSShawn Lin static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
6926e0832faSShawn Lin {
6936e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
6946e0832faSShawn Lin 
6956e0832faSShawn Lin 	reset_control_assert(res->axi_m_reset);
6966e0832faSShawn Lin 	reset_control_assert(res->axi_s_reset);
6976e0832faSShawn Lin 	reset_control_assert(res->pipe_reset);
6986e0832faSShawn Lin 	reset_control_assert(res->pipe_sticky_reset);
6996e0832faSShawn Lin 	reset_control_assert(res->phy_reset);
7006e0832faSShawn Lin 	reset_control_assert(res->phy_ahb_reset);
7016e0832faSShawn Lin 	reset_control_assert(res->axi_m_sticky_reset);
7026e0832faSShawn Lin 	reset_control_assert(res->pwr_reset);
7036e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
7045aa18097SBjorn Andersson 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
7056e0832faSShawn Lin }
7066e0832faSShawn Lin 
7076e0832faSShawn Lin static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
7086e0832faSShawn Lin {
7096e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
7106e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
7116e0832faSShawn Lin 	struct device *dev = pci->dev;
7126e0832faSShawn Lin 	int ret;
7136e0832faSShawn Lin 
7146e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_reset);
7156e0832faSShawn Lin 	if (ret) {
7166e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master reset\n");
7176e0832faSShawn Lin 		return ret;
7186e0832faSShawn Lin 	}
7196e0832faSShawn Lin 
7206e0832faSShawn Lin 	ret = reset_control_assert(res->axi_s_reset);
7216e0832faSShawn Lin 	if (ret) {
7226e0832faSShawn Lin 		dev_err(dev, "cannot assert axi slave reset\n");
7236e0832faSShawn Lin 		return ret;
7246e0832faSShawn Lin 	}
7256e0832faSShawn Lin 
7266e0832faSShawn Lin 	usleep_range(10000, 12000);
7276e0832faSShawn Lin 
7286e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_reset);
7296e0832faSShawn Lin 	if (ret) {
7306e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe reset\n");
7316e0832faSShawn Lin 		return ret;
7326e0832faSShawn Lin 	}
7336e0832faSShawn Lin 
7346e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_sticky_reset);
7356e0832faSShawn Lin 	if (ret) {
7366e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe sticky reset\n");
7376e0832faSShawn Lin 		return ret;
7386e0832faSShawn Lin 	}
7396e0832faSShawn Lin 
7406e0832faSShawn Lin 	ret = reset_control_assert(res->phy_reset);
7416e0832faSShawn Lin 	if (ret) {
7426e0832faSShawn Lin 		dev_err(dev, "cannot assert phy reset\n");
7436e0832faSShawn Lin 		return ret;
7446e0832faSShawn Lin 	}
7456e0832faSShawn Lin 
7466e0832faSShawn Lin 	ret = reset_control_assert(res->phy_ahb_reset);
7476e0832faSShawn Lin 	if (ret) {
7486e0832faSShawn Lin 		dev_err(dev, "cannot assert phy ahb reset\n");
7496e0832faSShawn Lin 		return ret;
7506e0832faSShawn Lin 	}
7516e0832faSShawn Lin 
7526e0832faSShawn Lin 	usleep_range(10000, 12000);
7536e0832faSShawn Lin 
7546e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_sticky_reset);
7556e0832faSShawn Lin 	if (ret) {
7566e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master sticky reset\n");
7576e0832faSShawn Lin 		return ret;
7586e0832faSShawn Lin 	}
7596e0832faSShawn Lin 
7606e0832faSShawn Lin 	ret = reset_control_assert(res->pwr_reset);
7616e0832faSShawn Lin 	if (ret) {
7626e0832faSShawn Lin 		dev_err(dev, "cannot assert power reset\n");
7636e0832faSShawn Lin 		return ret;
7646e0832faSShawn Lin 	}
7656e0832faSShawn Lin 
7666e0832faSShawn Lin 	ret = reset_control_assert(res->ahb_reset);
7676e0832faSShawn Lin 	if (ret) {
7686e0832faSShawn Lin 		dev_err(dev, "cannot assert ahb reset\n");
7696e0832faSShawn Lin 		return ret;
7706e0832faSShawn Lin 	}
7716e0832faSShawn Lin 
7726e0832faSShawn Lin 	usleep_range(10000, 12000);
7736e0832faSShawn Lin 
7746e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_ahb_reset);
7756e0832faSShawn Lin 	if (ret) {
7766e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy ahb reset\n");
7776e0832faSShawn Lin 		return ret;
7786e0832faSShawn Lin 	}
7796e0832faSShawn Lin 
7806e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_reset);
7816e0832faSShawn Lin 	if (ret) {
7826e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy reset\n");
7836e0832faSShawn Lin 		goto err_rst_phy;
7846e0832faSShawn Lin 	}
7856e0832faSShawn Lin 
7866e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_reset);
7876e0832faSShawn Lin 	if (ret) {
7886e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe reset\n");
7896e0832faSShawn Lin 		goto err_rst_pipe;
7906e0832faSShawn Lin 	}
7916e0832faSShawn Lin 
7926e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_sticky_reset);
7936e0832faSShawn Lin 	if (ret) {
7946e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe sticky reset\n");
7956e0832faSShawn Lin 		goto err_rst_pipe_sticky;
7966e0832faSShawn Lin 	}
7976e0832faSShawn Lin 
7986e0832faSShawn Lin 	usleep_range(10000, 12000);
7996e0832faSShawn Lin 
8006e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_reset);
8016e0832faSShawn Lin 	if (ret) {
8026e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master reset\n");
8036e0832faSShawn Lin 		goto err_rst_axi_m;
8046e0832faSShawn Lin 	}
8056e0832faSShawn Lin 
8066e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_sticky_reset);
8076e0832faSShawn Lin 	if (ret) {
8086e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master sticky reset\n");
8096e0832faSShawn Lin 		goto err_rst_axi_m_sticky;
8106e0832faSShawn Lin 	}
8116e0832faSShawn Lin 
8126e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_s_reset);
8136e0832faSShawn Lin 	if (ret) {
8146e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi slave reset\n");
8156e0832faSShawn Lin 		goto err_rst_axi_s;
8166e0832faSShawn Lin 	}
8176e0832faSShawn Lin 
8186e0832faSShawn Lin 	ret = reset_control_deassert(res->pwr_reset);
8196e0832faSShawn Lin 	if (ret) {
8206e0832faSShawn Lin 		dev_err(dev, "cannot deassert power reset\n");
8216e0832faSShawn Lin 		goto err_rst_pwr;
8226e0832faSShawn Lin 	}
8236e0832faSShawn Lin 
8246e0832faSShawn Lin 	ret = reset_control_deassert(res->ahb_reset);
8256e0832faSShawn Lin 	if (ret) {
8266e0832faSShawn Lin 		dev_err(dev, "cannot deassert ahb reset\n");
8276e0832faSShawn Lin 		goto err_rst_ahb;
8286e0832faSShawn Lin 	}
8296e0832faSShawn Lin 
8306e0832faSShawn Lin 	usleep_range(10000, 12000);
8316e0832faSShawn Lin 
8325aa18097SBjorn Andersson 	ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
8335aa18097SBjorn Andersson 	if (ret)
8345aa18097SBjorn Andersson 		goto err_clks;
8356e0832faSShawn Lin 
83636d9018dSRobert Marko 	return 0;
83736d9018dSRobert Marko 
83836d9018dSRobert Marko err_clks:
83936d9018dSRobert Marko 	reset_control_assert(res->ahb_reset);
84036d9018dSRobert Marko err_rst_ahb:
84136d9018dSRobert Marko 	reset_control_assert(res->pwr_reset);
84236d9018dSRobert Marko err_rst_pwr:
84336d9018dSRobert Marko 	reset_control_assert(res->axi_s_reset);
84436d9018dSRobert Marko err_rst_axi_s:
84536d9018dSRobert Marko 	reset_control_assert(res->axi_m_sticky_reset);
84636d9018dSRobert Marko err_rst_axi_m_sticky:
84736d9018dSRobert Marko 	reset_control_assert(res->axi_m_reset);
84836d9018dSRobert Marko err_rst_axi_m:
84936d9018dSRobert Marko 	reset_control_assert(res->pipe_sticky_reset);
85036d9018dSRobert Marko err_rst_pipe_sticky:
85136d9018dSRobert Marko 	reset_control_assert(res->pipe_reset);
85236d9018dSRobert Marko err_rst_pipe:
85336d9018dSRobert Marko 	reset_control_assert(res->phy_reset);
85436d9018dSRobert Marko err_rst_phy:
85536d9018dSRobert Marko 	reset_control_assert(res->phy_ahb_reset);
85636d9018dSRobert Marko 	return ret;
85736d9018dSRobert Marko }
85836d9018dSRobert Marko 
85936d9018dSRobert Marko static int qcom_pcie_post_init_2_4_0(struct qcom_pcie *pcie)
86036d9018dSRobert Marko {
86136d9018dSRobert Marko 	u32 val;
86236d9018dSRobert Marko 
8636e0832faSShawn Lin 	/* enable PCIe clocks and resets */
86439171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
86517804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
86639171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
8676e0832faSShawn Lin 
8686e0832faSShawn Lin 	/* change DBI base address */
86939171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
8706e0832faSShawn Lin 
8716e0832faSShawn Lin 	/* MAC PHY_POWERDOWN MUX DISABLE  */
87239171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_SYS_CTRL);
87317804668SManivannan Sadhasivam 	val &= ~MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN;
87439171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_SYS_CTRL);
8756e0832faSShawn Lin 
87639171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
87717804668SManivannan Sadhasivam 	val |= BYPASS;
87839171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
8796e0832faSShawn Lin 
88039171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
88117804668SManivannan Sadhasivam 	val |= EN;
88239171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
8836e0832faSShawn Lin 
8846e0832faSShawn Lin 	return 0;
8856e0832faSShawn Lin }
8866e0832faSShawn Lin 
8876e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_3(struct qcom_pcie *pcie)
8886e0832faSShawn Lin {
8896e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
8906e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
8916e0832faSShawn Lin 	struct device *dev = pci->dev;
8926e0832faSShawn Lin 	int i;
8936e0832faSShawn Lin 	const char *rst_names[] = { "axi_m", "axi_s", "pipe",
8946e0832faSShawn Lin 				    "axi_m_sticky", "sticky",
8956e0832faSShawn Lin 				    "ahb", "sleep", };
896*b699ed9bSManivannan Sadhasivam 	int ret;
8976e0832faSShawn Lin 
898*b699ed9bSManivannan Sadhasivam 	res->clks[0].id = "iface";
899*b699ed9bSManivannan Sadhasivam 	res->clks[1].id = "axi_m";
900*b699ed9bSManivannan Sadhasivam 	res->clks[2].id = "axi_s";
901*b699ed9bSManivannan Sadhasivam 	res->clks[3].id = "ahb";
902*b699ed9bSManivannan Sadhasivam 	res->clks[4].id = "aux";
9036e0832faSShawn Lin 
904*b699ed9bSManivannan Sadhasivam 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
905*b699ed9bSManivannan Sadhasivam 	if (ret < 0)
906*b699ed9bSManivannan Sadhasivam 		return ret;
9076e0832faSShawn Lin 
9086e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(rst_names); i++) {
9096e0832faSShawn Lin 		res->rst[i] = devm_reset_control_get(dev, rst_names[i]);
9106e0832faSShawn Lin 		if (IS_ERR(res->rst[i]))
9116e0832faSShawn Lin 			return PTR_ERR(res->rst[i]);
9126e0832faSShawn Lin 	}
9136e0832faSShawn Lin 
9146e0832faSShawn Lin 	return 0;
9156e0832faSShawn Lin }
9166e0832faSShawn Lin 
9176e0832faSShawn Lin static void qcom_pcie_deinit_2_3_3(struct qcom_pcie *pcie)
9186e0832faSShawn Lin {
9196e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
9206e0832faSShawn Lin 
921*b699ed9bSManivannan Sadhasivam 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
9226e0832faSShawn Lin }
9236e0832faSShawn Lin 
9246e0832faSShawn Lin static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
9256e0832faSShawn Lin {
9266e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
9276e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
9286e0832faSShawn Lin 	struct device *dev = pci->dev;
9296e0832faSShawn Lin 	int i, ret;
9306e0832faSShawn Lin 
9316e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
9326e0832faSShawn Lin 		ret = reset_control_assert(res->rst[i]);
9336e0832faSShawn Lin 		if (ret) {
9346e0832faSShawn Lin 			dev_err(dev, "reset #%d assert failed (%d)\n", i, ret);
9356e0832faSShawn Lin 			return ret;
9366e0832faSShawn Lin 		}
9376e0832faSShawn Lin 	}
9386e0832faSShawn Lin 
9396e0832faSShawn Lin 	usleep_range(2000, 2500);
9406e0832faSShawn Lin 
9416e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
9426e0832faSShawn Lin 		ret = reset_control_deassert(res->rst[i]);
9436e0832faSShawn Lin 		if (ret) {
9446e0832faSShawn Lin 			dev_err(dev, "reset #%d deassert failed (%d)\n", i,
9456e0832faSShawn Lin 				ret);
9466e0832faSShawn Lin 			return ret;
9476e0832faSShawn Lin 		}
9486e0832faSShawn Lin 	}
9496e0832faSShawn Lin 
9506e0832faSShawn Lin 	/*
9516e0832faSShawn Lin 	 * Don't have a way to see if the reset has completed.
9526e0832faSShawn Lin 	 * Wait for some time.
9536e0832faSShawn Lin 	 */
9546e0832faSShawn Lin 	usleep_range(2000, 2500);
9556e0832faSShawn Lin 
956*b699ed9bSManivannan Sadhasivam 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
9576e0832faSShawn Lin 	if (ret) {
958*b699ed9bSManivannan Sadhasivam 		dev_err(dev, "cannot prepare/enable clocks\n");
959*b699ed9bSManivannan Sadhasivam 		goto err_assert_resets;
9606e0832faSShawn Lin 	}
9616e0832faSShawn Lin 
9626e0832faSShawn Lin 	return 0;
9636e0832faSShawn Lin 
964*b699ed9bSManivannan Sadhasivam err_assert_resets:
9656e0832faSShawn Lin 	/*
9666e0832faSShawn Lin 	 * Not checking for failure, will anyway return
9676e0832faSShawn Lin 	 * the original failure in 'ret'.
9686e0832faSShawn Lin 	 */
9696e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++)
9706e0832faSShawn Lin 		reset_control_assert(res->rst[i]);
9716e0832faSShawn Lin 
9726e0832faSShawn Lin 	return ret;
9736e0832faSShawn Lin }
9746e0832faSShawn Lin 
975a0e43bb9SRobert Marko static int qcom_pcie_post_init_2_3_3(struct qcom_pcie *pcie)
976a0e43bb9SRobert Marko {
977a0e43bb9SRobert Marko 	struct dw_pcie *pci = pcie->pci;
978a0e43bb9SRobert Marko 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
979a0e43bb9SRobert Marko 	u32 val;
980a0e43bb9SRobert Marko 
9816e0832faSShawn Lin 	writel(SLV_ADDR_SPACE_SZ,
98239171b33SManivannan Sadhasivam 		pcie->parf + PARF_SLV_ADDR_SPACE_SIZE_2_3_3);
9836e0832faSShawn Lin 
98439171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
98517804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
98639171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
9876e0832faSShawn Lin 
98839171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
9896e0832faSShawn Lin 
9906e0832faSShawn Lin 	writel(MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS
9916e0832faSShawn Lin 		| SLV_ACLK_CGC_DIS | CORE_CLK_CGC_DIS |
9926e0832faSShawn Lin 		AUX_PWR_DET | L23_CLK_RMV_DIS | L1_CLK_RMV_DIS,
99339171b33SManivannan Sadhasivam 		pcie->parf + PARF_SYS_CTRL);
99439171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_Q2A_FLUSH);
9956e0832faSShawn Lin 
9966e0832faSShawn Lin 	writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
99739171b33SManivannan Sadhasivam 	writel(DBI_RO_WR_EN, pci->dbi_base + MISC_CONTROL_1_REG);
9989a765805SBaruch Siach 	writel(PCIE_CAP_SLOT_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
9996e0832faSShawn Lin 
10006e0832faSShawn Lin 	val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
10016e0832faSShawn Lin 	val &= ~PCI_EXP_LNKCAP_ASPMS;
10026e0832faSShawn Lin 	writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
10036e0832faSShawn Lin 
10046e0832faSShawn Lin 	writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
10056e0832faSShawn Lin 		PCI_EXP_DEVCTL2);
10066e0832faSShawn Lin 
10076e0832faSShawn Lin 	return 0;
10086e0832faSShawn Lin }
10096e0832faSShawn Lin 
1010ed8cc3b1SBjorn Andersson static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
1011ed8cc3b1SBjorn Andersson {
1012ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1013ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1014ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
101570574511SJohan Hovold 	unsigned int num_clks, num_opt_clks;
10161c5aa037SDmitry Baryshkov 	unsigned int idx;
1017ed8cc3b1SBjorn Andersson 	int ret;
1018ed8cc3b1SBjorn Andersson 
1019ed8cc3b1SBjorn Andersson 	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
1020ed8cc3b1SBjorn Andersson 	if (IS_ERR(res->pci_reset))
1021ed8cc3b1SBjorn Andersson 		return PTR_ERR(res->pci_reset);
1022ed8cc3b1SBjorn Andersson 
1023ed8cc3b1SBjorn Andersson 	res->supplies[0].supply = "vdda";
1024ed8cc3b1SBjorn Andersson 	res->supplies[1].supply = "vddpe-3v3";
1025ed8cc3b1SBjorn Andersson 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
1026ed8cc3b1SBjorn Andersson 				      res->supplies);
1027ed8cc3b1SBjorn Andersson 	if (ret)
1028ed8cc3b1SBjorn Andersson 		return ret;
1029ed8cc3b1SBjorn Andersson 
10301c5aa037SDmitry Baryshkov 	idx = 0;
10311c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "aux";
10321c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "cfg";
10331c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "bus_master";
10341c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "bus_slave";
10351c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "slave_q2a";
10361c5aa037SDmitry Baryshkov 
103770574511SJohan Hovold 	num_clks = idx;
103870574511SJohan Hovold 
103970574511SJohan Hovold 	ret = devm_clk_bulk_get(dev, num_clks, res->clks);
104070574511SJohan Hovold 	if (ret < 0)
104170574511SJohan Hovold 		return ret;
104270574511SJohan Hovold 
1043014aa351SJohan Hovold 	res->clks[idx++].id = "tbu";
1044014aa351SJohan Hovold 	res->clks[idx++].id = "ddrss_sf_tbu";
1045014aa351SJohan Hovold 	res->clks[idx++].id = "aggre0";
1046014aa351SJohan Hovold 	res->clks[idx++].id = "aggre1";
104770574511SJohan Hovold 	res->clks[idx++].id = "noc_aggr_4";
104870574511SJohan Hovold 	res->clks[idx++].id = "noc_aggr_south_sf";
104970574511SJohan Hovold 	res->clks[idx++].id = "cnoc_qx";
105070574511SJohan Hovold 
105170574511SJohan Hovold 	num_opt_clks = idx - num_clks;
10521c5aa037SDmitry Baryshkov 	res->num_clks = idx;
1053ed8cc3b1SBjorn Andersson 
105470574511SJohan Hovold 	ret = devm_clk_bulk_get_optional(dev, num_opt_clks, res->clks + num_clks);
1055ed8cc3b1SBjorn Andersson 	if (ret < 0)
1056ed8cc3b1SBjorn Andersson 		return ret;
1057ed8cc3b1SBjorn Andersson 
1058affac98aSDmitry Baryshkov 	return 0;
1059ed8cc3b1SBjorn Andersson }
1060ed8cc3b1SBjorn Andersson 
1061ed8cc3b1SBjorn Andersson static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
1062ed8cc3b1SBjorn Andersson {
1063ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1064ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1065ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
1066ed8cc3b1SBjorn Andersson 	u32 val;
1067ed8cc3b1SBjorn Andersson 	int ret;
1068ed8cc3b1SBjorn Andersson 
1069ed8cc3b1SBjorn Andersson 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
1070ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1071ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot enable regulators\n");
1072ed8cc3b1SBjorn Andersson 		return ret;
1073ed8cc3b1SBjorn Andersson 	}
1074ed8cc3b1SBjorn Andersson 
10757081556fSDmitry Baryshkov 	ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
1076ed8cc3b1SBjorn Andersson 	if (ret < 0)
1077ed8cc3b1SBjorn Andersson 		goto err_disable_regulators;
1078ed8cc3b1SBjorn Andersson 
1079ed8cc3b1SBjorn Andersson 	ret = reset_control_assert(res->pci_reset);
1080ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1081fba31beaSManivannan Sadhasivam 		dev_err(dev, "cannot assert pci reset\n");
1082ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1083ed8cc3b1SBjorn Andersson 	}
1084ed8cc3b1SBjorn Andersson 
1085ed8cc3b1SBjorn Andersson 	usleep_range(1000, 1500);
1086ed8cc3b1SBjorn Andersson 
1087ed8cc3b1SBjorn Andersson 	ret = reset_control_deassert(res->pci_reset);
1088ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1089ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot deassert pci reset\n");
1090ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1091ed8cc3b1SBjorn Andersson 	}
1092ed8cc3b1SBjorn Andersson 
10931c5aa037SDmitry Baryshkov 	/* Wait for reset to complete, required on SM8450 */
10941c5aa037SDmitry Baryshkov 	usleep_range(1000, 1500);
10951c5aa037SDmitry Baryshkov 
1096ed8cc3b1SBjorn Andersson 	/* configure PCIe to RC mode */
109739171b33SManivannan Sadhasivam 	writel(DEVICE_TYPE_RC, pcie->parf + PARF_DEVICE_TYPE);
1098ed8cc3b1SBjorn Andersson 
1099ed8cc3b1SBjorn Andersson 	/* enable PCIe clocks and resets */
110039171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
110117804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
110239171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
1103ed8cc3b1SBjorn Andersson 
1104ed8cc3b1SBjorn Andersson 	/* change DBI base address */
110539171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
1106ed8cc3b1SBjorn Andersson 
1107ed8cc3b1SBjorn Andersson 	/* MAC PHY_POWERDOWN MUX DISABLE  */
110839171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_SYS_CTRL);
110917804668SManivannan Sadhasivam 	val &= ~MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN;
111039171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_SYS_CTRL);
1111ed8cc3b1SBjorn Andersson 
111239171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
111317804668SManivannan Sadhasivam 	val |= BYPASS;
111439171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
1115ed8cc3b1SBjorn Andersson 
11165147ba8aSKrishna chaitanya chundru 	/* Enable L1 and L1SS */
111739171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PM_CTRL);
11185147ba8aSKrishna chaitanya chundru 	val &= ~REQ_NOT_ENTR_L1;
111939171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PM_CTRL);
11205147ba8aSKrishna chaitanya chundru 
112139171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
112217804668SManivannan Sadhasivam 	val |= EN;
112339171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
1124ed8cc3b1SBjorn Andersson 
1125ed8cc3b1SBjorn Andersson 	return 0;
1126ed8cc3b1SBjorn Andersson err_disable_clocks:
11277081556fSDmitry Baryshkov 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
1128ed8cc3b1SBjorn Andersson err_disable_regulators:
1129ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1130ed8cc3b1SBjorn Andersson 
1131ed8cc3b1SBjorn Andersson 	return ret;
1132ed8cc3b1SBjorn Andersson }
1133ed8cc3b1SBjorn Andersson 
1134ed8cc3b1SBjorn Andersson static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
1135ed8cc3b1SBjorn Andersson {
1136ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1137ed8cc3b1SBjorn Andersson 
11387081556fSDmitry Baryshkov 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
11397eb5768cSDmitry Baryshkov 
1140ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1141ed8cc3b1SBjorn Andersson }
1142ed8cc3b1SBjorn Andersson 
11430cf7c2efSSelvam Sathappan Periakaruppan static int qcom_pcie_get_resources_2_9_0(struct qcom_pcie *pcie)
1144ed8cc3b1SBjorn Andersson {
11450cf7c2efSSelvam Sathappan Periakaruppan 	struct qcom_pcie_resources_2_9_0 *res = &pcie->res.v2_9_0;
11460cf7c2efSSelvam Sathappan Periakaruppan 	struct dw_pcie *pci = pcie->pci;
11470cf7c2efSSelvam Sathappan Periakaruppan 	struct device *dev = pci->dev;
11480cf7c2efSSelvam Sathappan Periakaruppan 	int ret;
1149ed8cc3b1SBjorn Andersson 
11500cf7c2efSSelvam Sathappan Periakaruppan 	res->clks[0].id = "iface";
11510cf7c2efSSelvam Sathappan Periakaruppan 	res->clks[1].id = "axi_m";
11520cf7c2efSSelvam Sathappan Periakaruppan 	res->clks[2].id = "axi_s";
11530cf7c2efSSelvam Sathappan Periakaruppan 	res->clks[3].id = "axi_bridge";
11540cf7c2efSSelvam Sathappan Periakaruppan 	res->clks[4].id = "rchng";
1155aa9c0df9SPrasad Malisetty 
11560cf7c2efSSelvam Sathappan Periakaruppan 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
11570cf7c2efSSelvam Sathappan Periakaruppan 	if (ret < 0)
11580cf7c2efSSelvam Sathappan Periakaruppan 		return ret;
11590cf7c2efSSelvam Sathappan Periakaruppan 
11600cf7c2efSSelvam Sathappan Periakaruppan 	res->rst = devm_reset_control_array_get_exclusive(dev);
11610cf7c2efSSelvam Sathappan Periakaruppan 	if (IS_ERR(res->rst))
11620cf7c2efSSelvam Sathappan Periakaruppan 		return PTR_ERR(res->rst);
11630cf7c2efSSelvam Sathappan Periakaruppan 
11640cf7c2efSSelvam Sathappan Periakaruppan 	return 0;
1165ed8cc3b1SBjorn Andersson }
1166ed8cc3b1SBjorn Andersson 
11670cf7c2efSSelvam Sathappan Periakaruppan static void qcom_pcie_deinit_2_9_0(struct qcom_pcie *pcie)
1168ed8cc3b1SBjorn Andersson {
11690cf7c2efSSelvam Sathappan Periakaruppan 	struct qcom_pcie_resources_2_9_0 *res = &pcie->res.v2_9_0;
1170ed8cc3b1SBjorn Andersson 
11710cf7c2efSSelvam Sathappan Periakaruppan 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
11720cf7c2efSSelvam Sathappan Periakaruppan }
11730cf7c2efSSelvam Sathappan Periakaruppan 
11740cf7c2efSSelvam Sathappan Periakaruppan static int qcom_pcie_init_2_9_0(struct qcom_pcie *pcie)
11750cf7c2efSSelvam Sathappan Periakaruppan {
11760cf7c2efSSelvam Sathappan Periakaruppan 	struct qcom_pcie_resources_2_9_0 *res = &pcie->res.v2_9_0;
11770cf7c2efSSelvam Sathappan Periakaruppan 	struct device *dev = pcie->pci->dev;
11780cf7c2efSSelvam Sathappan Periakaruppan 	int ret;
11790cf7c2efSSelvam Sathappan Periakaruppan 
11800cf7c2efSSelvam Sathappan Periakaruppan 	ret = reset_control_assert(res->rst);
11810cf7c2efSSelvam Sathappan Periakaruppan 	if (ret) {
11820cf7c2efSSelvam Sathappan Periakaruppan 		dev_err(dev, "reset assert failed (%d)\n", ret);
11830cf7c2efSSelvam Sathappan Periakaruppan 		return ret;
11840cf7c2efSSelvam Sathappan Periakaruppan 	}
11850cf7c2efSSelvam Sathappan Periakaruppan 
11860cf7c2efSSelvam Sathappan Periakaruppan 	/*
11870cf7c2efSSelvam Sathappan Periakaruppan 	 * Delay periods before and after reset deassert are working values
11880cf7c2efSSelvam Sathappan Periakaruppan 	 * from downstream Codeaurora kernel
11890cf7c2efSSelvam Sathappan Periakaruppan 	 */
11900cf7c2efSSelvam Sathappan Periakaruppan 	usleep_range(2000, 2500);
11910cf7c2efSSelvam Sathappan Periakaruppan 
11920cf7c2efSSelvam Sathappan Periakaruppan 	ret = reset_control_deassert(res->rst);
11930cf7c2efSSelvam Sathappan Periakaruppan 	if (ret) {
11940cf7c2efSSelvam Sathappan Periakaruppan 		dev_err(dev, "reset deassert failed (%d)\n", ret);
11950cf7c2efSSelvam Sathappan Periakaruppan 		return ret;
11960cf7c2efSSelvam Sathappan Periakaruppan 	}
11970cf7c2efSSelvam Sathappan Periakaruppan 
11980cf7c2efSSelvam Sathappan Periakaruppan 	usleep_range(2000, 2500);
11990cf7c2efSSelvam Sathappan Periakaruppan 
12000cf7c2efSSelvam Sathappan Periakaruppan 	return clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
12010cf7c2efSSelvam Sathappan Periakaruppan }
12020cf7c2efSSelvam Sathappan Periakaruppan 
12030cf7c2efSSelvam Sathappan Periakaruppan static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie)
12040cf7c2efSSelvam Sathappan Periakaruppan {
12050cf7c2efSSelvam Sathappan Periakaruppan 	struct dw_pcie *pci = pcie->pci;
12060cf7c2efSSelvam Sathappan Periakaruppan 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
12070cf7c2efSSelvam Sathappan Periakaruppan 	u32 val;
12080cf7c2efSSelvam Sathappan Periakaruppan 	int i;
12090cf7c2efSSelvam Sathappan Periakaruppan 
12100cf7c2efSSelvam Sathappan Periakaruppan 	writel(SLV_ADDR_SPACE_SZ,
121139171b33SManivannan Sadhasivam 		pcie->parf + PARF_SLV_ADDR_SPACE_SIZE);
12120cf7c2efSSelvam Sathappan Periakaruppan 
121339171b33SManivannan Sadhasivam 	val = readl(pcie->parf + PARF_PHY_CTRL);
121417804668SManivannan Sadhasivam 	val &= ~PHY_TEST_PWR_DOWN;
121539171b33SManivannan Sadhasivam 	writel(val, pcie->parf + PARF_PHY_CTRL);
12160cf7c2efSSelvam Sathappan Periakaruppan 
121739171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_DBI_BASE_ADDR);
12180cf7c2efSSelvam Sathappan Periakaruppan 
121939171b33SManivannan Sadhasivam 	writel(DEVICE_TYPE_RC, pcie->parf + PARF_DEVICE_TYPE);
12200cf7c2efSSelvam Sathappan Periakaruppan 	writel(BYPASS | MSTR_AXI_CLK_EN | AHB_CLK_EN,
122139171b33SManivannan Sadhasivam 		pcie->parf + PARF_MHI_CLOCK_RESET_CTRL);
12220cf7c2efSSelvam Sathappan Periakaruppan 	writel(GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS |
12230cf7c2efSSelvam Sathappan Periakaruppan 		GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL,
12240cf7c2efSSelvam Sathappan Periakaruppan 		pci->dbi_base + GEN3_RELATED_OFF);
12250cf7c2efSSelvam Sathappan Periakaruppan 
12260cf7c2efSSelvam Sathappan Periakaruppan 	writel(MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS |
12270cf7c2efSSelvam Sathappan Periakaruppan 		SLV_ACLK_CGC_DIS | CORE_CLK_CGC_DIS |
12280cf7c2efSSelvam Sathappan Periakaruppan 		AUX_PWR_DET | L23_CLK_RMV_DIS | L1_CLK_RMV_DIS,
122939171b33SManivannan Sadhasivam 		pcie->parf + PARF_SYS_CTRL);
12300cf7c2efSSelvam Sathappan Periakaruppan 
123139171b33SManivannan Sadhasivam 	writel(0, pcie->parf + PARF_Q2A_FLUSH);
12320cf7c2efSSelvam Sathappan Periakaruppan 
12330cf7c2efSSelvam Sathappan Periakaruppan 	dw_pcie_dbi_ro_wr_en(pci);
12340cf7c2efSSelvam Sathappan Periakaruppan 	writel(PCIE_CAP_SLOT_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
12350cf7c2efSSelvam Sathappan Periakaruppan 
12360cf7c2efSSelvam Sathappan Periakaruppan 	val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
12370cf7c2efSSelvam Sathappan Periakaruppan 	val &= ~PCI_EXP_LNKCAP_ASPMS;
12380cf7c2efSSelvam Sathappan Periakaruppan 	writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
12390cf7c2efSSelvam Sathappan Periakaruppan 
12400cf7c2efSSelvam Sathappan Periakaruppan 	writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
12410cf7c2efSSelvam Sathappan Periakaruppan 			PCI_EXP_DEVCTL2);
12420cf7c2efSSelvam Sathappan Periakaruppan 
12430cf7c2efSSelvam Sathappan Periakaruppan 	for (i = 0; i < 256; i++)
124439171b33SManivannan Sadhasivam 		writel(0, pcie->parf + PARF_BDF_TO_SID_TABLE_N + (4 * i));
12450cf7c2efSSelvam Sathappan Periakaruppan 
12460cf7c2efSSelvam Sathappan Periakaruppan 	return 0;
1247ed8cc3b1SBjorn Andersson }
1248ed8cc3b1SBjorn Andersson 
12496e0832faSShawn Lin static int qcom_pcie_link_up(struct dw_pcie *pci)
12506e0832faSShawn Lin {
12517b87ddc0SRob Herring 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
12527b87ddc0SRob Herring 	u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
12536e0832faSShawn Lin 
12546e0832faSShawn Lin 	return !!(val & PCI_EXP_LNKSTA_DLLLA);
12556e0832faSShawn Lin }
12566e0832faSShawn Lin 
12574c939882SManivannan Sadhasivam static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
12584c939882SManivannan Sadhasivam {
12594c939882SManivannan Sadhasivam 	/* iommu map structure */
12604c939882SManivannan Sadhasivam 	struct {
12614c939882SManivannan Sadhasivam 		u32 bdf;
12624c939882SManivannan Sadhasivam 		u32 phandle;
12634c939882SManivannan Sadhasivam 		u32 smmu_sid;
12644c939882SManivannan Sadhasivam 		u32 smmu_sid_len;
12654c939882SManivannan Sadhasivam 	} *map;
126639171b33SManivannan Sadhasivam 	void __iomem *bdf_to_sid_base = pcie->parf + PARF_BDF_TO_SID_TABLE_N;
12674c939882SManivannan Sadhasivam 	struct device *dev = pcie->pci->dev;
12684c939882SManivannan Sadhasivam 	u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
12694c939882SManivannan Sadhasivam 	int i, nr_map, size = 0;
12704c939882SManivannan Sadhasivam 	u32 smmu_sid_base;
12714c939882SManivannan Sadhasivam 
12724c939882SManivannan Sadhasivam 	of_get_property(dev->of_node, "iommu-map", &size);
12734c939882SManivannan Sadhasivam 	if (!size)
12744c939882SManivannan Sadhasivam 		return 0;
12754c939882SManivannan Sadhasivam 
12764c939882SManivannan Sadhasivam 	map = kzalloc(size, GFP_KERNEL);
12774c939882SManivannan Sadhasivam 	if (!map)
12784c939882SManivannan Sadhasivam 		return -ENOMEM;
12794c939882SManivannan Sadhasivam 
12804c939882SManivannan Sadhasivam 	of_property_read_u32_array(dev->of_node,
12814c939882SManivannan Sadhasivam 		"iommu-map", (u32 *)map, size / sizeof(u32));
12824c939882SManivannan Sadhasivam 
12834c939882SManivannan Sadhasivam 	nr_map = size / (sizeof(*map));
12844c939882SManivannan Sadhasivam 
12854c939882SManivannan Sadhasivam 	crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
12864c939882SManivannan Sadhasivam 
12874c939882SManivannan Sadhasivam 	/* Registers need to be zero out first */
12884c939882SManivannan Sadhasivam 	memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
12894c939882SManivannan Sadhasivam 
12904c939882SManivannan Sadhasivam 	/* Extract the SMMU SID base from the first entry of iommu-map */
12914c939882SManivannan Sadhasivam 	smmu_sid_base = map[0].smmu_sid;
12924c939882SManivannan Sadhasivam 
12934c939882SManivannan Sadhasivam 	/* Look for an available entry to hold the mapping */
12944c939882SManivannan Sadhasivam 	for (i = 0; i < nr_map; i++) {
12953f13d611SManivannan Sadhasivam 		__be16 bdf_be = cpu_to_be16(map[i].bdf);
12964c939882SManivannan Sadhasivam 		u32 val;
12974c939882SManivannan Sadhasivam 		u8 hash;
12984c939882SManivannan Sadhasivam 
12994c939882SManivannan Sadhasivam 		hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
13004c939882SManivannan Sadhasivam 			0);
13014c939882SManivannan Sadhasivam 
13024c939882SManivannan Sadhasivam 		val = readl(bdf_to_sid_base + hash * sizeof(u32));
13034c939882SManivannan Sadhasivam 
13044c939882SManivannan Sadhasivam 		/* If the register is already populated, look for next available entry */
13054c939882SManivannan Sadhasivam 		while (val) {
13064c939882SManivannan Sadhasivam 			u8 current_hash = hash++;
13074c939882SManivannan Sadhasivam 			u8 next_mask = 0xff;
13084c939882SManivannan Sadhasivam 
13094c939882SManivannan Sadhasivam 			/* If NEXT field is NULL then update it with next hash */
13104c939882SManivannan Sadhasivam 			if (!(val & next_mask)) {
13114c939882SManivannan Sadhasivam 				val |= (u32)hash;
13124c939882SManivannan Sadhasivam 				writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
13134c939882SManivannan Sadhasivam 			}
13144c939882SManivannan Sadhasivam 
13154c939882SManivannan Sadhasivam 			val = readl(bdf_to_sid_base + hash * sizeof(u32));
13164c939882SManivannan Sadhasivam 		}
13174c939882SManivannan Sadhasivam 
13184c939882SManivannan Sadhasivam 		/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
13194c939882SManivannan Sadhasivam 		val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
13204c939882SManivannan Sadhasivam 		writel(val, bdf_to_sid_base + hash * sizeof(u32));
13214c939882SManivannan Sadhasivam 	}
13224c939882SManivannan Sadhasivam 
13234c939882SManivannan Sadhasivam 	kfree(map);
13244c939882SManivannan Sadhasivam 
13254c939882SManivannan Sadhasivam 	return 0;
13264c939882SManivannan Sadhasivam }
13274c939882SManivannan Sadhasivam 
132860b3c27fSSerge Semin static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
13296e0832faSShawn Lin {
13306e0832faSShawn Lin 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
13316e0832faSShawn Lin 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
13326e0832faSShawn Lin 	int ret;
13336e0832faSShawn Lin 
13346e0832faSShawn Lin 	qcom_ep_reset_assert(pcie);
13356e0832faSShawn Lin 
1336f94c35e0SDmitry Baryshkov 	ret = pcie->cfg->ops->init(pcie);
13376e0832faSShawn Lin 	if (ret)
13386e0832faSShawn Lin 		return ret;
13396e0832faSShawn Lin 
1340f90747d1SDmitry Baryshkov 	ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
1341f90747d1SDmitry Baryshkov 	if (ret)
1342f90747d1SDmitry Baryshkov 		goto err_deinit;
1343f90747d1SDmitry Baryshkov 
13446e0832faSShawn Lin 	ret = phy_power_on(pcie->phy);
13456e0832faSShawn Lin 	if (ret)
13466e0832faSShawn Lin 		goto err_deinit;
13476e0832faSShawn Lin 
1348f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->post_init) {
1349f94c35e0SDmitry Baryshkov 		ret = pcie->cfg->ops->post_init(pcie);
13506e0832faSShawn Lin 		if (ret)
13516e0832faSShawn Lin 			goto err_disable_phy;
13526e0832faSShawn Lin 	}
13536e0832faSShawn Lin 
13546e0832faSShawn Lin 	qcom_ep_reset_deassert(pcie);
13556e0832faSShawn Lin 
1356f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->config_sid) {
1357f94c35e0SDmitry Baryshkov 		ret = pcie->cfg->ops->config_sid(pcie);
13584c939882SManivannan Sadhasivam 		if (ret)
13590e4d9a5cSJohan Hovold 			goto err_assert_reset;
13604c939882SManivannan Sadhasivam 	}
13614c939882SManivannan Sadhasivam 
13626e0832faSShawn Lin 	return 0;
1363886a9c13SRob Herring 
13640e4d9a5cSJohan Hovold err_assert_reset:
13654c939882SManivannan Sadhasivam 	qcom_ep_reset_assert(pcie);
13666e0832faSShawn Lin err_disable_phy:
13676e0832faSShawn Lin 	phy_power_off(pcie->phy);
13686e0832faSShawn Lin err_deinit:
1369f94c35e0SDmitry Baryshkov 	pcie->cfg->ops->deinit(pcie);
13706e0832faSShawn Lin 
13716e0832faSShawn Lin 	return ret;
13726e0832faSShawn Lin }
13736e0832faSShawn Lin 
1374997e010dSJohan Hovold static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp)
1375997e010dSJohan Hovold {
1376997e010dSJohan Hovold 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1377997e010dSJohan Hovold 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
1378997e010dSJohan Hovold 
1379997e010dSJohan Hovold 	qcom_ep_reset_assert(pcie);
1380997e010dSJohan Hovold 	phy_power_off(pcie->phy);
1381997e010dSJohan Hovold 	pcie->cfg->ops->deinit(pcie);
1382997e010dSJohan Hovold }
1383997e010dSJohan Hovold 
13846e0832faSShawn Lin static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
13856e0832faSShawn Lin 	.host_init	= qcom_pcie_host_init,
1386997e010dSJohan Hovold 	.host_deinit	= qcom_pcie_host_deinit,
13876e0832faSShawn Lin };
13886e0832faSShawn Lin 
13896e0832faSShawn Lin /* Qcom IP rev.: 2.1.0	Synopsys IP rev.: 4.01a */
13906e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_1_0 = {
13916e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_1_0,
13926e0832faSShawn Lin 	.init = qcom_pcie_init_2_1_0,
139336d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_2_1_0,
13946e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_1_0,
13956e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
13966e0832faSShawn Lin };
13976e0832faSShawn Lin 
13986e0832faSShawn Lin /* Qcom IP rev.: 1.0.0	Synopsys IP rev.: 4.11a */
13996e0832faSShawn Lin static const struct qcom_pcie_ops ops_1_0_0 = {
14006e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_1_0_0,
14016e0832faSShawn Lin 	.init = qcom_pcie_init_1_0_0,
140236d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_1_0_0,
14036e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_1_0_0,
14046e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
14056e0832faSShawn Lin };
14066e0832faSShawn Lin 
14076e0832faSShawn Lin /* Qcom IP rev.: 2.3.2	Synopsys IP rev.: 4.21a */
14086e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_2 = {
14096e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_2,
14106e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_2,
14116e0832faSShawn Lin 	.post_init = qcom_pcie_post_init_2_3_2,
14126e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_2,
14136e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14146e0832faSShawn Lin };
14156e0832faSShawn Lin 
14166e0832faSShawn Lin /* Qcom IP rev.: 2.4.0	Synopsys IP rev.: 4.20a */
14176e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_4_0 = {
14186e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_4_0,
14196e0832faSShawn Lin 	.init = qcom_pcie_init_2_4_0,
142036d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_2_4_0,
14216e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_4_0,
14226e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14236e0832faSShawn Lin };
14246e0832faSShawn Lin 
14256e0832faSShawn Lin /* Qcom IP rev.: 2.3.3	Synopsys IP rev.: 4.30a */
14266e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_3 = {
14276e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_3,
14286e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_3,
1429a0e43bb9SRobert Marko 	.post_init = qcom_pcie_post_init_2_3_3,
14306e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_3,
14316e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14326e0832faSShawn Lin };
14336e0832faSShawn Lin 
1434ed8cc3b1SBjorn Andersson /* Qcom IP rev.: 2.7.0	Synopsys IP rev.: 4.30a */
1435ed8cc3b1SBjorn Andersson static const struct qcom_pcie_ops ops_2_7_0 = {
1436ed8cc3b1SBjorn Andersson 	.get_resources = qcom_pcie_get_resources_2_7_0,
1437ed8cc3b1SBjorn Andersson 	.init = qcom_pcie_init_2_7_0,
1438ed8cc3b1SBjorn Andersson 	.deinit = qcom_pcie_deinit_2_7_0,
1439ed8cc3b1SBjorn Andersson 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
1440ed8cc3b1SBjorn Andersson };
1441ed8cc3b1SBjorn Andersson 
1442e1dd639eSManivannan Sadhasivam /* Qcom IP rev.: 1.9.0 */
1443e1dd639eSManivannan Sadhasivam static const struct qcom_pcie_ops ops_1_9_0 = {
1444e1dd639eSManivannan Sadhasivam 	.get_resources = qcom_pcie_get_resources_2_7_0,
1445e1dd639eSManivannan Sadhasivam 	.init = qcom_pcie_init_2_7_0,
1446e1dd639eSManivannan Sadhasivam 	.deinit = qcom_pcie_deinit_2_7_0,
1447e1dd639eSManivannan Sadhasivam 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14484c939882SManivannan Sadhasivam 	.config_sid = qcom_pcie_config_sid_sm8250,
1449e1dd639eSManivannan Sadhasivam };
1450e1dd639eSManivannan Sadhasivam 
14510cf7c2efSSelvam Sathappan Periakaruppan /* Qcom IP rev.: 2.9.0  Synopsys IP rev.: 5.00a */
14520cf7c2efSSelvam Sathappan Periakaruppan static const struct qcom_pcie_ops ops_2_9_0 = {
14530cf7c2efSSelvam Sathappan Periakaruppan 	.get_resources = qcom_pcie_get_resources_2_9_0,
14540cf7c2efSSelvam Sathappan Periakaruppan 	.init = qcom_pcie_init_2_9_0,
14550cf7c2efSSelvam Sathappan Periakaruppan 	.post_init = qcom_pcie_post_init_2_9_0,
14560cf7c2efSSelvam Sathappan Periakaruppan 	.deinit = qcom_pcie_deinit_2_9_0,
14570cf7c2efSSelvam Sathappan Periakaruppan 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14580cf7c2efSSelvam Sathappan Periakaruppan };
14590cf7c2efSSelvam Sathappan Periakaruppan 
146022311735SJohan Hovold static const struct qcom_pcie_cfg cfg_1_0_0 = {
1461b89ff410SPrasad Malisetty 	.ops = &ops_1_0_0,
1462b89ff410SPrasad Malisetty };
1463b89ff410SPrasad Malisetty 
146422311735SJohan Hovold static const struct qcom_pcie_cfg cfg_1_9_0 = {
146522311735SJohan Hovold 	.ops = &ops_1_9_0,
146622311735SJohan Hovold };
146722311735SJohan Hovold 
146822311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_1_0 = {
1469b89ff410SPrasad Malisetty 	.ops = &ops_2_1_0,
1470b89ff410SPrasad Malisetty };
1471b89ff410SPrasad Malisetty 
147222311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_3_2 = {
1473b89ff410SPrasad Malisetty 	.ops = &ops_2_3_2,
1474b89ff410SPrasad Malisetty };
1475b89ff410SPrasad Malisetty 
147622311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_3_3 = {
1477b89ff410SPrasad Malisetty 	.ops = &ops_2_3_3,
1478b89ff410SPrasad Malisetty };
1479b89ff410SPrasad Malisetty 
148022311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_4_0 = {
1481b89ff410SPrasad Malisetty 	.ops = &ops_2_4_0,
1482b89ff410SPrasad Malisetty };
1483b89ff410SPrasad Malisetty 
148422311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_7_0 = {
1485b89ff410SPrasad Malisetty 	.ops = &ops_2_7_0,
1486b89ff410SPrasad Malisetty };
1487b89ff410SPrasad Malisetty 
148822311735SJohan Hovold static const struct qcom_pcie_cfg cfg_2_9_0 = {
14890cf7c2efSSelvam Sathappan Periakaruppan 	.ops = &ops_2_9_0,
14900cf7c2efSSelvam Sathappan Periakaruppan };
14910cf7c2efSSelvam Sathappan Periakaruppan 
14926e0832faSShawn Lin static const struct dw_pcie_ops dw_pcie_ops = {
14936e0832faSShawn Lin 	.link_up = qcom_pcie_link_up,
1494886a9c13SRob Herring 	.start_link = qcom_pcie_start_link,
14956e0832faSShawn Lin };
14966e0832faSShawn Lin 
1497c4860af8SJohan Hovold static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
1498c4860af8SJohan Hovold {
1499c4860af8SJohan Hovold 	struct dw_pcie *pci = pcie->pci;
1500c4860af8SJohan Hovold 	int ret;
1501c4860af8SJohan Hovold 
1502c4860af8SJohan Hovold 	pcie->icc_mem = devm_of_icc_get(pci->dev, "pcie-mem");
1503c4860af8SJohan Hovold 	if (IS_ERR(pcie->icc_mem))
1504c4860af8SJohan Hovold 		return PTR_ERR(pcie->icc_mem);
1505c4860af8SJohan Hovold 
1506c4860af8SJohan Hovold 	/*
1507c4860af8SJohan Hovold 	 * Some Qualcomm platforms require interconnect bandwidth constraints
1508c4860af8SJohan Hovold 	 * to be set before enabling interconnect clocks.
1509c4860af8SJohan Hovold 	 *
1510c4860af8SJohan Hovold 	 * Set an initial peak bandwidth corresponding to single-lane Gen 1
1511c4860af8SJohan Hovold 	 * for the pcie-mem path.
1512c4860af8SJohan Hovold 	 */
1513c4860af8SJohan Hovold 	ret = icc_set_bw(pcie->icc_mem, 0, MBps_to_icc(250));
1514c4860af8SJohan Hovold 	if (ret) {
1515c4860af8SJohan Hovold 		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
1516c4860af8SJohan Hovold 			ret);
1517c4860af8SJohan Hovold 		return ret;
1518c4860af8SJohan Hovold 	}
1519c4860af8SJohan Hovold 
1520c4860af8SJohan Hovold 	return 0;
1521c4860af8SJohan Hovold }
1522c4860af8SJohan Hovold 
1523c4860af8SJohan Hovold static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
1524c4860af8SJohan Hovold {
1525c4860af8SJohan Hovold 	struct dw_pcie *pci = pcie->pci;
1526c4860af8SJohan Hovold 	u32 offset, status, bw;
1527c4860af8SJohan Hovold 	int speed, width;
1528c4860af8SJohan Hovold 	int ret;
1529c4860af8SJohan Hovold 
1530c4860af8SJohan Hovold 	if (!pcie->icc_mem)
1531c4860af8SJohan Hovold 		return;
1532c4860af8SJohan Hovold 
1533c4860af8SJohan Hovold 	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
1534c4860af8SJohan Hovold 	status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
1535c4860af8SJohan Hovold 
1536c4860af8SJohan Hovold 	/* Only update constraints if link is up. */
1537c4860af8SJohan Hovold 	if (!(status & PCI_EXP_LNKSTA_DLLLA))
1538c4860af8SJohan Hovold 		return;
1539c4860af8SJohan Hovold 
1540c4860af8SJohan Hovold 	speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
1541c4860af8SJohan Hovold 	width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
1542c4860af8SJohan Hovold 
1543c4860af8SJohan Hovold 	switch (speed) {
1544c4860af8SJohan Hovold 	case 1:
1545c4860af8SJohan Hovold 		bw = MBps_to_icc(250);
1546c4860af8SJohan Hovold 		break;
1547c4860af8SJohan Hovold 	case 2:
1548c4860af8SJohan Hovold 		bw = MBps_to_icc(500);
1549c4860af8SJohan Hovold 		break;
1550c4860af8SJohan Hovold 	default:
1551c4860af8SJohan Hovold 		WARN_ON_ONCE(1);
1552c4860af8SJohan Hovold 		fallthrough;
1553c4860af8SJohan Hovold 	case 3:
1554c4860af8SJohan Hovold 		bw = MBps_to_icc(985);
1555c4860af8SJohan Hovold 		break;
1556c4860af8SJohan Hovold 	}
1557c4860af8SJohan Hovold 
1558c4860af8SJohan Hovold 	ret = icc_set_bw(pcie->icc_mem, 0, width * bw);
1559c4860af8SJohan Hovold 	if (ret) {
1560c4860af8SJohan Hovold 		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
1561c4860af8SJohan Hovold 			ret);
1562c4860af8SJohan Hovold 	}
1563c4860af8SJohan Hovold }
1564c4860af8SJohan Hovold 
15656e0832faSShawn Lin static int qcom_pcie_probe(struct platform_device *pdev)
15666e0832faSShawn Lin {
15676e0832faSShawn Lin 	struct device *dev = &pdev->dev;
156860b3c27fSSerge Semin 	struct dw_pcie_rp *pp;
15696e0832faSShawn Lin 	struct dw_pcie *pci;
15706e0832faSShawn Lin 	struct qcom_pcie *pcie;
1571b89ff410SPrasad Malisetty 	const struct qcom_pcie_cfg *pcie_cfg;
15726e0832faSShawn Lin 	int ret;
15736e0832faSShawn Lin 
15744e0e9053SChristophe JAILLET 	pcie_cfg = of_device_get_match_data(dev);
15754e0e9053SChristophe JAILLET 	if (!pcie_cfg || !pcie_cfg->ops) {
15764e0e9053SChristophe JAILLET 		dev_err(dev, "Invalid platform data\n");
15774e0e9053SChristophe JAILLET 		return -EINVAL;
15784e0e9053SChristophe JAILLET 	}
15794e0e9053SChristophe JAILLET 
15806e0832faSShawn Lin 	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
15816e0832faSShawn Lin 	if (!pcie)
15826e0832faSShawn Lin 		return -ENOMEM;
15836e0832faSShawn Lin 
15846e0832faSShawn Lin 	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
15856e0832faSShawn Lin 	if (!pci)
15866e0832faSShawn Lin 		return -ENOMEM;
15876e0832faSShawn Lin 
15886e0832faSShawn Lin 	pm_runtime_enable(dev);
15896e5da6f7SBjorn Andersson 	ret = pm_runtime_get_sync(dev);
1590cb52a402SDinghao Liu 	if (ret < 0)
1591cb52a402SDinghao Liu 		goto err_pm_runtime_put;
15926e5da6f7SBjorn Andersson 
15936e0832faSShawn Lin 	pci->dev = dev;
15946e0832faSShawn Lin 	pci->ops = &dw_pcie_ops;
15956e0832faSShawn Lin 	pp = &pci->pp;
15966e0832faSShawn Lin 
15976e0832faSShawn Lin 	pcie->pci = pci;
15986e0832faSShawn Lin 
1599f94c35e0SDmitry Baryshkov 	pcie->cfg = pcie_cfg;
16006e0832faSShawn Lin 
160102b485e3SBjorn Andersson 	pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
16026e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->reset)) {
16036e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->reset);
16046e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16056e5da6f7SBjorn Andersson 	}
16066e0832faSShawn Lin 
1607936fa5cdSDejin Zheng 	pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
16086e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->parf)) {
16096e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->parf);
16106e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16116e5da6f7SBjorn Andersson 	}
16126e0832faSShawn Lin 
1613936fa5cdSDejin Zheng 	pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
16146e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->elbi)) {
16156e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->elbi);
16166e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16176e5da6f7SBjorn Andersson 	}
16186e0832faSShawn Lin 
16196e0832faSShawn Lin 	pcie->phy = devm_phy_optional_get(dev, "pciephy");
16206e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->phy)) {
16216e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->phy);
16226e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16236e5da6f7SBjorn Andersson 	}
16246e0832faSShawn Lin 
1625c4860af8SJohan Hovold 	ret = qcom_pcie_icc_init(pcie);
1626c4860af8SJohan Hovold 	if (ret)
1627c4860af8SJohan Hovold 		goto err_pm_runtime_put;
1628c4860af8SJohan Hovold 
1629f94c35e0SDmitry Baryshkov 	ret = pcie->cfg->ops->get_resources(pcie);
16306e0832faSShawn Lin 	if (ret)
16316e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16326e0832faSShawn Lin 
16336e0832faSShawn Lin 	pp->ops = &qcom_pcie_dw_ops;
16346e0832faSShawn Lin 
16356e0832faSShawn Lin 	ret = phy_init(pcie->phy);
163687d83b96SJohan Hovold 	if (ret)
16376e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16386e0832faSShawn Lin 
16396e0832faSShawn Lin 	platform_set_drvdata(pdev, pcie);
16406e0832faSShawn Lin 
16416e0832faSShawn Lin 	ret = dw_pcie_host_init(pp);
16426e0832faSShawn Lin 	if (ret) {
16436e0832faSShawn Lin 		dev_err(dev, "cannot initialize host\n");
164483013631SJohan Hovold 		goto err_phy_exit;
16456e0832faSShawn Lin 	}
16466e0832faSShawn Lin 
1647c4860af8SJohan Hovold 	qcom_pcie_icc_update(pcie);
1648c4860af8SJohan Hovold 
16496e0832faSShawn Lin 	return 0;
16506e5da6f7SBjorn Andersson 
165183013631SJohan Hovold err_phy_exit:
165283013631SJohan Hovold 	phy_exit(pcie->phy);
16536e5da6f7SBjorn Andersson err_pm_runtime_put:
16546e5da6f7SBjorn Andersson 	pm_runtime_put(dev);
16556e5da6f7SBjorn Andersson 	pm_runtime_disable(dev);
16566e5da6f7SBjorn Andersson 
16576e5da6f7SBjorn Andersson 	return ret;
16586e0832faSShawn Lin }
16596e0832faSShawn Lin 
16606e0832faSShawn Lin static const struct of_device_id qcom_pcie_match[] = {
1661d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
166222311735SJohan Hovold 	{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
1663d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
1664d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
166522311735SJohan Hovold 	{ .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
166622311735SJohan Hovold 	{ .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
166722311735SJohan Hovold 	{ .compatible = "qcom,pcie-ipq8074", .data = &cfg_2_3_3 },
1668f3561322SRobert Marko 	{ .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 },
1669d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
167022311735SJohan Hovold 	{ .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
167122311735SJohan Hovold 	{ .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 },
1672d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-sc7280", .data = &cfg_1_9_0 },
1673d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-sc8180x", .data = &cfg_1_9_0 },
1674d6cbfcd2SJohan Hovold 	{ .compatible = "qcom,pcie-sc8280xp", .data = &cfg_1_9_0 },
167522311735SJohan Hovold 	{ .compatible = "qcom,pcie-sdm845", .data = &cfg_2_7_0 },
167622311735SJohan Hovold 	{ .compatible = "qcom,pcie-sm8150", .data = &cfg_1_9_0 },
167722311735SJohan Hovold 	{ .compatible = "qcom,pcie-sm8250", .data = &cfg_1_9_0 },
1678720e0d91SDmitry Baryshkov 	{ .compatible = "qcom,pcie-sm8350", .data = &cfg_1_9_0 },
167922311735SJohan Hovold 	{ .compatible = "qcom,pcie-sm8450-pcie0", .data = &cfg_1_9_0 },
168022311735SJohan Hovold 	{ .compatible = "qcom,pcie-sm8450-pcie1", .data = &cfg_1_9_0 },
16816e0832faSShawn Lin 	{ }
16826e0832faSShawn Lin };
16836e0832faSShawn Lin 
1684322f0343SMarc Gonzalez static void qcom_fixup_class(struct pci_dev *dev)
1685322f0343SMarc Gonzalez {
1686904b10fbSPali Rohár 	dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
1687322f0343SMarc Gonzalez }
1688604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0101, qcom_fixup_class);
1689604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0104, qcom_fixup_class);
1690604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0106, qcom_fixup_class);
1691604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0107, qcom_fixup_class);
1692604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0302, qcom_fixup_class);
1693604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1000, qcom_fixup_class);
1694604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1001, qcom_fixup_class);
1695322f0343SMarc Gonzalez 
16966e0832faSShawn Lin static struct platform_driver qcom_pcie_driver = {
16976e0832faSShawn Lin 	.probe = qcom_pcie_probe,
16986e0832faSShawn Lin 	.driver = {
16996e0832faSShawn Lin 		.name = "qcom-pcie",
17006e0832faSShawn Lin 		.suppress_bind_attrs = true,
17016e0832faSShawn Lin 		.of_match_table = qcom_pcie_match,
17026e0832faSShawn Lin 	},
17036e0832faSShawn Lin };
17046e0832faSShawn Lin builtin_platform_driver(qcom_pcie_driver);
1705