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>
156e0832faSShawn Lin #include <linux/interrupt.h>
166e0832faSShawn Lin #include <linux/io.h>
176e0832faSShawn Lin #include <linux/iopoll.h>
186e0832faSShawn Lin #include <linux/kernel.h>
196e0832faSShawn Lin #include <linux/init.h>
206e0832faSShawn Lin #include <linux/of_device.h>
216e0832faSShawn Lin #include <linux/of_gpio.h>
226e0832faSShawn Lin #include <linux/pci.h>
236e0832faSShawn Lin #include <linux/pm_runtime.h>
246e0832faSShawn Lin #include <linux/platform_device.h>
256e0832faSShawn Lin #include <linux/phy/phy.h>
266e0832faSShawn Lin #include <linux/regulator/consumer.h>
276e0832faSShawn Lin #include <linux/reset.h>
286e0832faSShawn Lin #include <linux/slab.h>
296e0832faSShawn Lin #include <linux/types.h>
306e0832faSShawn Lin 
3151ed2c2bSSham Muthayyan #include "../../pci.h"
326e0832faSShawn Lin #include "pcie-designware.h"
336e0832faSShawn Lin 
346e0832faSShawn Lin #define PCIE20_PARF_SYS_CTRL			0x00
356e0832faSShawn Lin #define MST_WAKEUP_EN				BIT(13)
366e0832faSShawn Lin #define SLV_WAKEUP_EN				BIT(12)
376e0832faSShawn Lin #define MSTR_ACLK_CGC_DIS			BIT(10)
386e0832faSShawn Lin #define SLV_ACLK_CGC_DIS			BIT(9)
396e0832faSShawn Lin #define CORE_CLK_CGC_DIS			BIT(6)
406e0832faSShawn Lin #define AUX_PWR_DET				BIT(4)
416e0832faSShawn Lin #define L23_CLK_RMV_DIS				BIT(2)
426e0832faSShawn Lin #define L1_CLK_RMV_DIS				BIT(1)
436e0832faSShawn Lin 
446e0832faSShawn Lin #define PCIE20_PARF_PHY_CTRL			0x40
45de3c4bf6SAnsuel Smith #define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK	GENMASK(20, 16)
46de3c4bf6SAnsuel Smith #define PHY_CTRL_PHY_TX0_TERM_OFFSET(x)		((x) << 16)
47de3c4bf6SAnsuel Smith 
486e0832faSShawn Lin #define PCIE20_PARF_PHY_REFCLK			0x4C
49de3c4bf6SAnsuel Smith #define PHY_REFCLK_SSP_EN			BIT(16)
50de3c4bf6SAnsuel Smith #define PHY_REFCLK_USE_PAD			BIT(12)
51de3c4bf6SAnsuel Smith 
526e0832faSShawn Lin #define PCIE20_PARF_DBI_BASE_ADDR		0x168
536e0832faSShawn Lin #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE		0x16C
546e0832faSShawn Lin #define PCIE20_PARF_MHI_CLOCK_RESET_CTRL	0x174
556e0832faSShawn Lin #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT	0x178
566e0832faSShawn Lin #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2	0x1A8
576e0832faSShawn Lin #define PCIE20_PARF_LTSSM			0x1B0
586e0832faSShawn Lin #define PCIE20_PARF_SID_OFFSET			0x234
596e0832faSShawn Lin #define PCIE20_PARF_BDF_TRANSLATE_CFG		0x24C
60ed8cc3b1SBjorn Andersson #define PCIE20_PARF_DEVICE_TYPE			0x1000
614c939882SManivannan Sadhasivam #define PCIE20_PARF_BDF_TO_SID_TABLE_N		0x2000
626e0832faSShawn Lin 
636e0832faSShawn Lin #define PCIE20_ELBI_SYS_CTRL			0x04
646e0832faSShawn Lin #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE		BIT(0)
656e0832faSShawn Lin 
666e0832faSShawn Lin #define PCIE20_AXI_MSTR_RESP_COMP_CTRL0		0x818
676e0832faSShawn Lin #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K	0x4
686e0832faSShawn Lin #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_4K	0x5
696e0832faSShawn Lin #define PCIE20_AXI_MSTR_RESP_COMP_CTRL1		0x81c
706e0832faSShawn Lin #define CFG_BRIDGE_SB_INIT			BIT(0)
716e0832faSShawn Lin 
72*9a765805SBaruch Siach #define PCIE_CAP_SLOT_POWER_LIMIT_VAL		FIELD_PREP(PCI_EXP_SLTCAP_SPLV, \
73*9a765805SBaruch Siach 						250)
74*9a765805SBaruch Siach #define PCIE_CAP_SLOT_POWER_LIMIT_SCALE		FIELD_PREP(PCI_EXP_SLTCAP_SPLS, \
75*9a765805SBaruch Siach 						1)
76*9a765805SBaruch Siach #define PCIE_CAP_SLOT_VAL			(PCI_EXP_SLTCAP_ABP | \
77*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_PCP | \
78*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_MRLSP | \
79*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_AIP | \
80*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_PIP | \
81*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_HPS | \
82*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_HPC | \
83*9a765805SBaruch Siach 						PCI_EXP_SLTCAP_EIP | \
84*9a765805SBaruch Siach 						PCIE_CAP_SLOT_POWER_LIMIT_VAL | \
85*9a765805SBaruch Siach 						PCIE_CAP_SLOT_POWER_LIMIT_SCALE)
866e0832faSShawn Lin 
876e0832faSShawn Lin #define PCIE20_PARF_Q2A_FLUSH			0x1AC
886e0832faSShawn Lin 
896e0832faSShawn Lin #define PCIE20_MISC_CONTROL_1_REG		0x8BC
906e0832faSShawn Lin #define DBI_RO_WR_EN				1
916e0832faSShawn Lin 
926e0832faSShawn Lin #define PERST_DELAY_US				1000
935149901eSAnsuel Smith /* PARF registers */
945149901eSAnsuel Smith #define PCIE20_PARF_PCS_DEEMPH			0x34
955149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN1(x)		((x) << 16)
965149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x)	((x) << 8)
975149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x)	((x) << 0)
985149901eSAnsuel Smith 
995149901eSAnsuel Smith #define PCIE20_PARF_PCS_SWING			0x38
1005149901eSAnsuel Smith #define PCS_SWING_TX_SWING_FULL(x)		((x) << 8)
1015149901eSAnsuel Smith #define PCS_SWING_TX_SWING_LOW(x)		((x) << 0)
1025149901eSAnsuel Smith 
1035149901eSAnsuel Smith #define PCIE20_PARF_CONFIG_BITS		0x50
1045149901eSAnsuel Smith #define PHY_RX0_EQ(x)				((x) << 24)
1056e0832faSShawn Lin 
1066e0832faSShawn Lin #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE	0x358
1076e0832faSShawn Lin #define SLV_ADDR_SPACE_SZ			0x10000000
1086e0832faSShawn Lin 
10951ed2c2bSSham Muthayyan #define PCIE20_LNK_CONTROL2_LINK_STATUS2	0xa0
11051ed2c2bSSham Muthayyan 
111ed8cc3b1SBjorn Andersson #define DEVICE_TYPE_RC				0x4
112ed8cc3b1SBjorn Andersson 
1136e0832faSShawn Lin #define QCOM_PCIE_2_1_0_MAX_SUPPLY	3
1146a114526SAnsuel Smith #define QCOM_PCIE_2_1_0_MAX_CLOCKS	5
1154c939882SManivannan Sadhasivam 
1164c939882SManivannan Sadhasivam #define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
1174c939882SManivannan Sadhasivam 
1186e0832faSShawn Lin struct qcom_pcie_resources_2_1_0 {
1196a114526SAnsuel Smith 	struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
1206e0832faSShawn Lin 	struct reset_control *pci_reset;
1216e0832faSShawn Lin 	struct reset_control *axi_reset;
1226e0832faSShawn Lin 	struct reset_control *ahb_reset;
1236e0832faSShawn Lin 	struct reset_control *por_reset;
1246e0832faSShawn Lin 	struct reset_control *phy_reset;
125ee367e2cSAnsuel Smith 	struct reset_control *ext_reset;
1266e0832faSShawn Lin 	struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
1276e0832faSShawn Lin };
1286e0832faSShawn Lin 
1296e0832faSShawn Lin struct qcom_pcie_resources_1_0_0 {
1306e0832faSShawn Lin 	struct clk *iface;
1316e0832faSShawn Lin 	struct clk *aux;
1326e0832faSShawn Lin 	struct clk *master_bus;
1336e0832faSShawn Lin 	struct clk *slave_bus;
1346e0832faSShawn Lin 	struct reset_control *core;
1356e0832faSShawn Lin 	struct regulator *vdda;
1366e0832faSShawn Lin };
1376e0832faSShawn Lin 
1386e0832faSShawn Lin #define QCOM_PCIE_2_3_2_MAX_SUPPLY	2
1396e0832faSShawn Lin struct qcom_pcie_resources_2_3_2 {
1406e0832faSShawn Lin 	struct clk *aux_clk;
1416e0832faSShawn Lin 	struct clk *master_clk;
1426e0832faSShawn Lin 	struct clk *slave_clk;
1436e0832faSShawn Lin 	struct clk *cfg_clk;
1446e0832faSShawn Lin 	struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
1456e0832faSShawn Lin };
1466e0832faSShawn Lin 
14767021ae0SBjorn Andersson #define QCOM_PCIE_2_4_0_MAX_CLOCKS	4
1486e0832faSShawn Lin struct qcom_pcie_resources_2_4_0 {
1495aa18097SBjorn Andersson 	struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
1505aa18097SBjorn Andersson 	int num_clks;
1516e0832faSShawn Lin 	struct reset_control *axi_m_reset;
1526e0832faSShawn Lin 	struct reset_control *axi_s_reset;
1536e0832faSShawn Lin 	struct reset_control *pipe_reset;
1546e0832faSShawn Lin 	struct reset_control *axi_m_vmid_reset;
1556e0832faSShawn Lin 	struct reset_control *axi_s_xpu_reset;
1566e0832faSShawn Lin 	struct reset_control *parf_reset;
1576e0832faSShawn Lin 	struct reset_control *phy_reset;
1586e0832faSShawn Lin 	struct reset_control *axi_m_sticky_reset;
1596e0832faSShawn Lin 	struct reset_control *pipe_sticky_reset;
1606e0832faSShawn Lin 	struct reset_control *pwr_reset;
1616e0832faSShawn Lin 	struct reset_control *ahb_reset;
1626e0832faSShawn Lin 	struct reset_control *phy_ahb_reset;
1636e0832faSShawn Lin };
1646e0832faSShawn Lin 
1656e0832faSShawn Lin struct qcom_pcie_resources_2_3_3 {
1666e0832faSShawn Lin 	struct clk *iface;
1676e0832faSShawn Lin 	struct clk *axi_m_clk;
1686e0832faSShawn Lin 	struct clk *axi_s_clk;
1696e0832faSShawn Lin 	struct clk *ahb_clk;
1706e0832faSShawn Lin 	struct clk *aux_clk;
1716e0832faSShawn Lin 	struct reset_control *rst[7];
1726e0832faSShawn Lin };
1736e0832faSShawn Lin 
1747081556fSDmitry Baryshkov /* 6 clocks typically, 7 for sm8250 */
175ed8cc3b1SBjorn Andersson struct qcom_pcie_resources_2_7_0 {
1761c5aa037SDmitry Baryshkov 	struct clk_bulk_data clks[9];
1777081556fSDmitry Baryshkov 	int num_clks;
178ed8cc3b1SBjorn Andersson 	struct regulator_bulk_data supplies[2];
179ed8cc3b1SBjorn Andersson 	struct reset_control *pci_reset;
180ed8cc3b1SBjorn Andersson };
181ed8cc3b1SBjorn Andersson 
1826e0832faSShawn Lin union qcom_pcie_resources {
1836e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 v1_0_0;
1846e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 v2_1_0;
1856e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 v2_3_2;
1866e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 v2_3_3;
1876e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 v2_4_0;
188ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 v2_7_0;
1896e0832faSShawn Lin };
1906e0832faSShawn Lin 
1916e0832faSShawn Lin struct qcom_pcie;
1926e0832faSShawn Lin 
1936e0832faSShawn Lin struct qcom_pcie_ops {
1946e0832faSShawn Lin 	int (*get_resources)(struct qcom_pcie *pcie);
1956e0832faSShawn Lin 	int (*init)(struct qcom_pcie *pcie);
1966e0832faSShawn Lin 	int (*post_init)(struct qcom_pcie *pcie);
1976e0832faSShawn Lin 	void (*deinit)(struct qcom_pcie *pcie);
1986e0832faSShawn Lin 	void (*post_deinit)(struct qcom_pcie *pcie);
1996e0832faSShawn Lin 	void (*ltssm_enable)(struct qcom_pcie *pcie);
2004c939882SManivannan Sadhasivam 	int (*config_sid)(struct qcom_pcie *pcie);
2016e0832faSShawn Lin };
2026e0832faSShawn Lin 
203b89ff410SPrasad Malisetty struct qcom_pcie_cfg {
204b89ff410SPrasad Malisetty 	const struct qcom_pcie_ops *ops;
2051c5aa037SDmitry Baryshkov 	unsigned int has_tbu_clk:1;
2060614f98bSDmitry Baryshkov 	unsigned int has_ddrss_sf_tbu_clk:1;
2071c5aa037SDmitry Baryshkov 	unsigned int has_aggre0_clk:1;
2081c5aa037SDmitry Baryshkov 	unsigned int has_aggre1_clk:1;
209b89ff410SPrasad Malisetty };
210b89ff410SPrasad Malisetty 
2116e0832faSShawn Lin struct qcom_pcie {
2126e0832faSShawn Lin 	struct dw_pcie *pci;
2136e0832faSShawn Lin 	void __iomem *parf;			/* DT parf */
2146e0832faSShawn Lin 	void __iomem *elbi;			/* DT elbi */
2156e0832faSShawn Lin 	union qcom_pcie_resources res;
2166e0832faSShawn Lin 	struct phy *phy;
2176e0832faSShawn Lin 	struct gpio_desc *reset;
218f94c35e0SDmitry Baryshkov 	const struct qcom_pcie_cfg *cfg;
2196e0832faSShawn Lin };
2206e0832faSShawn Lin 
2216e0832faSShawn Lin #define to_qcom_pcie(x)		dev_get_drvdata((x)->dev)
2226e0832faSShawn Lin 
2236e0832faSShawn Lin static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
2246e0832faSShawn Lin {
2256e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 1);
2266e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2276e0832faSShawn Lin }
2286e0832faSShawn Lin 
2296e0832faSShawn Lin static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
2306e0832faSShawn Lin {
23164adde31SNiklas Cassel 	/* Ensure that PERST has been asserted for at least 100 ms */
23264adde31SNiklas Cassel 	msleep(100);
2336e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 0);
2346e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2356e0832faSShawn Lin }
2366e0832faSShawn Lin 
237886a9c13SRob Herring static int qcom_pcie_start_link(struct dw_pcie *pci)
2386e0832faSShawn Lin {
239886a9c13SRob Herring 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
2406e0832faSShawn Lin 
2416e0832faSShawn Lin 	/* Enable Link Training state machine */
242f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->ltssm_enable)
243f94c35e0SDmitry Baryshkov 		pcie->cfg->ops->ltssm_enable(pcie);
2446e0832faSShawn Lin 
245886a9c13SRob Herring 	return 0;
2466e0832faSShawn Lin }
2476e0832faSShawn Lin 
2486e0832faSShawn Lin static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
2496e0832faSShawn Lin {
2506e0832faSShawn Lin 	u32 val;
2516e0832faSShawn Lin 
2526e0832faSShawn Lin 	/* enable link training */
2536e0832faSShawn Lin 	val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL);
2546e0832faSShawn Lin 	val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
2556e0832faSShawn Lin 	writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
2566e0832faSShawn Lin }
2576e0832faSShawn Lin 
2586e0832faSShawn Lin static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
2596e0832faSShawn Lin {
2606e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
2616e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
2626e0832faSShawn Lin 	struct device *dev = pci->dev;
2636e0832faSShawn Lin 	int ret;
2646e0832faSShawn Lin 
2656e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
2666e0832faSShawn Lin 	res->supplies[1].supply = "vdda_phy";
2676e0832faSShawn Lin 	res->supplies[2].supply = "vdda_refclk";
2686e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
2696e0832faSShawn Lin 				      res->supplies);
2706e0832faSShawn Lin 	if (ret)
2716e0832faSShawn Lin 		return ret;
2726e0832faSShawn Lin 
2736a114526SAnsuel Smith 	res->clks[0].id = "iface";
2746a114526SAnsuel Smith 	res->clks[1].id = "core";
2756a114526SAnsuel Smith 	res->clks[2].id = "phy";
2766a114526SAnsuel Smith 	res->clks[3].id = "aux";
2776a114526SAnsuel Smith 	res->clks[4].id = "ref";
2786e0832faSShawn Lin 
2796a114526SAnsuel Smith 	/* iface, core, phy are required */
2806a114526SAnsuel Smith 	ret = devm_clk_bulk_get(dev, 3, res->clks);
2816a114526SAnsuel Smith 	if (ret < 0)
2826a114526SAnsuel Smith 		return ret;
2836e0832faSShawn Lin 
2846a114526SAnsuel Smith 	/* aux, ref are optional */
2856a114526SAnsuel Smith 	ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3);
2866a114526SAnsuel Smith 	if (ret < 0)
2876a114526SAnsuel Smith 		return ret;
2888b6f0330SAnsuel Smith 
2896e0832faSShawn Lin 	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
2906e0832faSShawn Lin 	if (IS_ERR(res->pci_reset))
2916e0832faSShawn Lin 		return PTR_ERR(res->pci_reset);
2926e0832faSShawn Lin 
2936e0832faSShawn Lin 	res->axi_reset = devm_reset_control_get_exclusive(dev, "axi");
2946e0832faSShawn Lin 	if (IS_ERR(res->axi_reset))
2956e0832faSShawn Lin 		return PTR_ERR(res->axi_reset);
2966e0832faSShawn Lin 
2976e0832faSShawn Lin 	res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
2986e0832faSShawn Lin 	if (IS_ERR(res->ahb_reset))
2996e0832faSShawn Lin 		return PTR_ERR(res->ahb_reset);
3006e0832faSShawn Lin 
3016e0832faSShawn Lin 	res->por_reset = devm_reset_control_get_exclusive(dev, "por");
3026e0832faSShawn Lin 	if (IS_ERR(res->por_reset))
3036e0832faSShawn Lin 		return PTR_ERR(res->por_reset);
3046e0832faSShawn Lin 
305ee367e2cSAnsuel Smith 	res->ext_reset = devm_reset_control_get_optional_exclusive(dev, "ext");
306ee367e2cSAnsuel Smith 	if (IS_ERR(res->ext_reset))
307ee367e2cSAnsuel Smith 		return PTR_ERR(res->ext_reset);
308ee367e2cSAnsuel Smith 
3096e0832faSShawn Lin 	res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
3106e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->phy_reset);
3116e0832faSShawn Lin }
3126e0832faSShawn Lin 
3136e0832faSShawn Lin static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
3146e0832faSShawn Lin {
3156e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
3166e0832faSShawn Lin 
3176a114526SAnsuel Smith 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
3186e0832faSShawn Lin 	reset_control_assert(res->pci_reset);
3196e0832faSShawn Lin 	reset_control_assert(res->axi_reset);
3206e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
3216e0832faSShawn Lin 	reset_control_assert(res->por_reset);
322ee367e2cSAnsuel Smith 	reset_control_assert(res->ext_reset);
323dd58318cSAbhishek Sahu 	reset_control_assert(res->phy_reset);
324d3d4d028SAnsuel Smith 
325d3d4d028SAnsuel Smith 	writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
326d3d4d028SAnsuel Smith 
3276e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
3286e0832faSShawn Lin }
3296e0832faSShawn Lin 
3306e0832faSShawn Lin static int qcom_pcie_init_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 	struct dw_pcie *pci = pcie->pci;
3346e0832faSShawn Lin 	struct device *dev = pci->dev;
3356e0832faSShawn Lin 	int ret;
3366e0832faSShawn Lin 
337d3d4d028SAnsuel Smith 	/* reset the PCIe interface as uboot can leave it undefined state */
338d3d4d028SAnsuel Smith 	reset_control_assert(res->pci_reset);
339d3d4d028SAnsuel Smith 	reset_control_assert(res->axi_reset);
340d3d4d028SAnsuel Smith 	reset_control_assert(res->ahb_reset);
341d3d4d028SAnsuel Smith 	reset_control_assert(res->por_reset);
342d3d4d028SAnsuel Smith 	reset_control_assert(res->ext_reset);
343d3d4d028SAnsuel Smith 	reset_control_assert(res->phy_reset);
344d3d4d028SAnsuel Smith 
3456e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
3466e0832faSShawn Lin 	if (ret < 0) {
3476e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
3486e0832faSShawn Lin 		return ret;
3496e0832faSShawn Lin 	}
3506e0832faSShawn Lin 
3516e0832faSShawn Lin 	ret = reset_control_deassert(res->ahb_reset);
3526e0832faSShawn Lin 	if (ret) {
3536e0832faSShawn Lin 		dev_err(dev, "cannot deassert ahb reset\n");
3546e0832faSShawn Lin 		goto err_deassert_ahb;
3556e0832faSShawn Lin 	}
3566e0832faSShawn Lin 
357ee367e2cSAnsuel Smith 	ret = reset_control_deassert(res->ext_reset);
358ee367e2cSAnsuel Smith 	if (ret) {
359ee367e2cSAnsuel Smith 		dev_err(dev, "cannot deassert ext reset\n");
3606a114526SAnsuel Smith 		goto err_deassert_ext;
361ee367e2cSAnsuel Smith 	}
362ee367e2cSAnsuel Smith 
3636a114526SAnsuel Smith 	ret = reset_control_deassert(res->phy_reset);
3646a114526SAnsuel Smith 	if (ret) {
3656a114526SAnsuel Smith 		dev_err(dev, "cannot deassert phy reset\n");
3666a114526SAnsuel Smith 		goto err_deassert_phy;
3676a114526SAnsuel Smith 	}
3686a114526SAnsuel Smith 
3696a114526SAnsuel Smith 	ret = reset_control_deassert(res->pci_reset);
3706a114526SAnsuel Smith 	if (ret) {
3716a114526SAnsuel Smith 		dev_err(dev, "cannot deassert pci reset\n");
3726a114526SAnsuel Smith 		goto err_deassert_pci;
3736a114526SAnsuel Smith 	}
3746a114526SAnsuel Smith 
3756a114526SAnsuel Smith 	ret = reset_control_deassert(res->por_reset);
3766a114526SAnsuel Smith 	if (ret) {
3776a114526SAnsuel Smith 		dev_err(dev, "cannot deassert por reset\n");
3786a114526SAnsuel Smith 		goto err_deassert_por;
3796a114526SAnsuel Smith 	}
3806a114526SAnsuel Smith 
3816a114526SAnsuel Smith 	ret = reset_control_deassert(res->axi_reset);
3826a114526SAnsuel Smith 	if (ret) {
3836a114526SAnsuel Smith 		dev_err(dev, "cannot deassert axi reset\n");
3846a114526SAnsuel Smith 		goto err_deassert_axi;
3856a114526SAnsuel Smith 	}
3866a114526SAnsuel Smith 
38736d9018dSRobert Marko 	return 0;
38836d9018dSRobert Marko 
38936d9018dSRobert Marko err_deassert_axi:
39036d9018dSRobert Marko 	reset_control_assert(res->por_reset);
39136d9018dSRobert Marko err_deassert_por:
39236d9018dSRobert Marko 	reset_control_assert(res->pci_reset);
39336d9018dSRobert Marko err_deassert_pci:
39436d9018dSRobert Marko 	reset_control_assert(res->phy_reset);
39536d9018dSRobert Marko err_deassert_phy:
39636d9018dSRobert Marko 	reset_control_assert(res->ext_reset);
39736d9018dSRobert Marko err_deassert_ext:
39836d9018dSRobert Marko 	reset_control_assert(res->ahb_reset);
39936d9018dSRobert Marko err_deassert_ahb:
40036d9018dSRobert Marko 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
40136d9018dSRobert Marko 
40236d9018dSRobert Marko 	return ret;
40336d9018dSRobert Marko }
40436d9018dSRobert Marko 
40536d9018dSRobert Marko static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie)
40636d9018dSRobert Marko {
40736d9018dSRobert Marko 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
40836d9018dSRobert Marko 	struct dw_pcie *pci = pcie->pci;
40936d9018dSRobert Marko 	struct device *dev = pci->dev;
41036d9018dSRobert Marko 	struct device_node *node = dev->of_node;
41136d9018dSRobert Marko 	u32 val;
41236d9018dSRobert Marko 	int ret;
41336d9018dSRobert Marko 
4146e0832faSShawn Lin 	/* enable PCIe clocks and resets */
4156e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
4166e0832faSShawn Lin 	val &= ~BIT(0);
4176e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
4186e0832faSShawn Lin 
41938f897aeSChristian Marangi 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
42038f897aeSChristian Marangi 	if (ret)
42136d9018dSRobert Marko 		return ret;
42238f897aeSChristian Marangi 
4238df093feSAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
4248df093feSAnsuel Smith 	    of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
4255149901eSAnsuel Smith 		writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
4265149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
4275149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
4285149901eSAnsuel Smith 		       pcie->parf + PCIE20_PARF_PCS_DEEMPH);
4295149901eSAnsuel Smith 		writel(PCS_SWING_TX_SWING_FULL(120) |
4305149901eSAnsuel Smith 			       PCS_SWING_TX_SWING_LOW(120),
4315149901eSAnsuel Smith 		       pcie->parf + PCIE20_PARF_PCS_SWING);
4325149901eSAnsuel Smith 		writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
4335149901eSAnsuel Smith 	}
4345149901eSAnsuel Smith 
435de3c4bf6SAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
436de3c4bf6SAnsuel Smith 		/* set TX termination offset */
437de3c4bf6SAnsuel Smith 		val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
438de3c4bf6SAnsuel Smith 		val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
439de3c4bf6SAnsuel Smith 		val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
440de3c4bf6SAnsuel Smith 		writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
441de3c4bf6SAnsuel Smith 	}
442de3c4bf6SAnsuel Smith 
4436e0832faSShawn Lin 	/* enable external reference clock */
4446e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
4452cfef197SAnsuel Smith 	/* USE_PAD is required only for ipq806x */
4462cfef197SAnsuel Smith 	if (!of_device_is_compatible(node, "qcom,pcie-apq8064"))
447de3c4bf6SAnsuel Smith 		val &= ~PHY_REFCLK_USE_PAD;
448de3c4bf6SAnsuel Smith 	val |= PHY_REFCLK_SSP_EN;
4496e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
4506e0832faSShawn Lin 
4516e0832faSShawn Lin 	/* wait for clock acquisition */
4526e0832faSShawn Lin 	usleep_range(1000, 1500);
4536e0832faSShawn Lin 
4546e0832faSShawn Lin 	/* Set the Max TLP size to 2K, instead of using default of 4K */
4556e0832faSShawn Lin 	writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
4566e0832faSShawn Lin 	       pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
4576e0832faSShawn Lin 	writel(CFG_BRIDGE_SB_INIT,
4586e0832faSShawn Lin 	       pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
4596e0832faSShawn Lin 
4606e0832faSShawn Lin 	return 0;
4616e0832faSShawn Lin }
4626e0832faSShawn Lin 
4636e0832faSShawn Lin static int qcom_pcie_get_resources_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 
4696e0832faSShawn Lin 	res->vdda = devm_regulator_get(dev, "vdda");
4706e0832faSShawn Lin 	if (IS_ERR(res->vdda))
4716e0832faSShawn Lin 		return PTR_ERR(res->vdda);
4726e0832faSShawn Lin 
4736e0832faSShawn Lin 	res->iface = devm_clk_get(dev, "iface");
4746e0832faSShawn Lin 	if (IS_ERR(res->iface))
4756e0832faSShawn Lin 		return PTR_ERR(res->iface);
4766e0832faSShawn Lin 
4776e0832faSShawn Lin 	res->aux = devm_clk_get(dev, "aux");
4786e0832faSShawn Lin 	if (IS_ERR(res->aux))
4796e0832faSShawn Lin 		return PTR_ERR(res->aux);
4806e0832faSShawn Lin 
4816e0832faSShawn Lin 	res->master_bus = devm_clk_get(dev, "master_bus");
4826e0832faSShawn Lin 	if (IS_ERR(res->master_bus))
4836e0832faSShawn Lin 		return PTR_ERR(res->master_bus);
4846e0832faSShawn Lin 
4856e0832faSShawn Lin 	res->slave_bus = devm_clk_get(dev, "slave_bus");
4866e0832faSShawn Lin 	if (IS_ERR(res->slave_bus))
4876e0832faSShawn Lin 		return PTR_ERR(res->slave_bus);
4886e0832faSShawn Lin 
4896e0832faSShawn Lin 	res->core = devm_reset_control_get_exclusive(dev, "core");
4906e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->core);
4916e0832faSShawn Lin }
4926e0832faSShawn Lin 
4936e0832faSShawn Lin static void qcom_pcie_deinit_1_0_0(struct qcom_pcie *pcie)
4946e0832faSShawn Lin {
4956e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4966e0832faSShawn Lin 
4976e0832faSShawn Lin 	reset_control_assert(res->core);
4986e0832faSShawn Lin 	clk_disable_unprepare(res->slave_bus);
4996e0832faSShawn Lin 	clk_disable_unprepare(res->master_bus);
5006e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
5016e0832faSShawn Lin 	clk_disable_unprepare(res->aux);
5026e0832faSShawn Lin 	regulator_disable(res->vdda);
5036e0832faSShawn Lin }
5046e0832faSShawn Lin 
5056e0832faSShawn Lin static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie)
5066e0832faSShawn Lin {
5076e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
5086e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
5096e0832faSShawn Lin 	struct device *dev = pci->dev;
5106e0832faSShawn Lin 	int ret;
5116e0832faSShawn Lin 
5126e0832faSShawn Lin 	ret = reset_control_deassert(res->core);
5136e0832faSShawn Lin 	if (ret) {
5146e0832faSShawn Lin 		dev_err(dev, "cannot deassert core reset\n");
5156e0832faSShawn Lin 		return ret;
5166e0832faSShawn Lin 	}
5176e0832faSShawn Lin 
5186e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux);
5196e0832faSShawn Lin 	if (ret) {
5206e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
5216e0832faSShawn Lin 		goto err_res;
5226e0832faSShawn Lin 	}
5236e0832faSShawn Lin 
5246e0832faSShawn Lin 	ret = clk_prepare_enable(res->iface);
5256e0832faSShawn Lin 	if (ret) {
5266e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable iface clock\n");
5276e0832faSShawn Lin 		goto err_aux;
5286e0832faSShawn Lin 	}
5296e0832faSShawn Lin 
5306e0832faSShawn Lin 	ret = clk_prepare_enable(res->master_bus);
5316e0832faSShawn Lin 	if (ret) {
5326e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable master_bus clock\n");
5336e0832faSShawn Lin 		goto err_iface;
5346e0832faSShawn Lin 	}
5356e0832faSShawn Lin 
5366e0832faSShawn Lin 	ret = clk_prepare_enable(res->slave_bus);
5376e0832faSShawn Lin 	if (ret) {
5386e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable slave_bus clock\n");
5396e0832faSShawn Lin 		goto err_master;
5406e0832faSShawn Lin 	}
5416e0832faSShawn Lin 
5426e0832faSShawn Lin 	ret = regulator_enable(res->vdda);
5436e0832faSShawn Lin 	if (ret) {
5446e0832faSShawn Lin 		dev_err(dev, "cannot enable vdda regulator\n");
5456e0832faSShawn Lin 		goto err_slave;
5466e0832faSShawn Lin 	}
5476e0832faSShawn Lin 
5486e0832faSShawn Lin 	return 0;
5496e0832faSShawn Lin err_slave:
5506e0832faSShawn Lin 	clk_disable_unprepare(res->slave_bus);
5516e0832faSShawn Lin err_master:
5526e0832faSShawn Lin 	clk_disable_unprepare(res->master_bus);
5536e0832faSShawn Lin err_iface:
5546e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
5556e0832faSShawn Lin err_aux:
5566e0832faSShawn Lin 	clk_disable_unprepare(res->aux);
5576e0832faSShawn Lin err_res:
5586e0832faSShawn Lin 	reset_control_assert(res->core);
5596e0832faSShawn Lin 
5606e0832faSShawn Lin 	return ret;
5616e0832faSShawn Lin }
5626e0832faSShawn Lin 
56336d9018dSRobert Marko static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
56436d9018dSRobert Marko {
56536d9018dSRobert Marko 	/* change DBI base address */
56636d9018dSRobert Marko 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
56736d9018dSRobert Marko 
56836d9018dSRobert Marko 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
56936d9018dSRobert Marko 		u32 val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
57036d9018dSRobert Marko 
57136d9018dSRobert Marko 		val |= BIT(31);
57236d9018dSRobert Marko 		writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
57336d9018dSRobert Marko 	}
57436d9018dSRobert Marko 
57536d9018dSRobert Marko 	return 0;
57636d9018dSRobert Marko }
57736d9018dSRobert Marko 
5786e0832faSShawn Lin static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
5796e0832faSShawn Lin {
5806e0832faSShawn Lin 	u32 val;
5816e0832faSShawn Lin 
5826e0832faSShawn Lin 	/* enable link training */
5836e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_LTSSM);
5846e0832faSShawn Lin 	val |= BIT(8);
5856e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_LTSSM);
5866e0832faSShawn Lin }
5876e0832faSShawn Lin 
5886e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
5896e0832faSShawn Lin {
5906e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
5916e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
5926e0832faSShawn Lin 	struct device *dev = pci->dev;
5936e0832faSShawn Lin 	int ret;
5946e0832faSShawn Lin 
5956e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
5966e0832faSShawn Lin 	res->supplies[1].supply = "vddpe-3v3";
5976e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
5986e0832faSShawn Lin 				      res->supplies);
5996e0832faSShawn Lin 	if (ret)
6006e0832faSShawn Lin 		return ret;
6016e0832faSShawn Lin 
6026e0832faSShawn Lin 	res->aux_clk = devm_clk_get(dev, "aux");
6036e0832faSShawn Lin 	if (IS_ERR(res->aux_clk))
6046e0832faSShawn Lin 		return PTR_ERR(res->aux_clk);
6056e0832faSShawn Lin 
6066e0832faSShawn Lin 	res->cfg_clk = devm_clk_get(dev, "cfg");
6076e0832faSShawn Lin 	if (IS_ERR(res->cfg_clk))
6086e0832faSShawn Lin 		return PTR_ERR(res->cfg_clk);
6096e0832faSShawn Lin 
6106e0832faSShawn Lin 	res->master_clk = devm_clk_get(dev, "bus_master");
6116e0832faSShawn Lin 	if (IS_ERR(res->master_clk))
6126e0832faSShawn Lin 		return PTR_ERR(res->master_clk);
6136e0832faSShawn Lin 
6146e0832faSShawn Lin 	res->slave_clk = devm_clk_get(dev, "bus_slave");
6156e0832faSShawn Lin 	if (IS_ERR(res->slave_clk))
6166e0832faSShawn Lin 		return PTR_ERR(res->slave_clk);
6176e0832faSShawn Lin 
618affac98aSDmitry Baryshkov 	return 0;
6196e0832faSShawn Lin }
6206e0832faSShawn Lin 
6216e0832faSShawn Lin static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
6226e0832faSShawn Lin {
6236e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
6246e0832faSShawn Lin 
6256e0832faSShawn Lin 	clk_disable_unprepare(res->slave_clk);
6266e0832faSShawn Lin 	clk_disable_unprepare(res->master_clk);
6276e0832faSShawn Lin 	clk_disable_unprepare(res->cfg_clk);
6286e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
6296e0832faSShawn Lin 
6306e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
6316e0832faSShawn Lin }
6326e0832faSShawn Lin 
6336e0832faSShawn Lin static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
6346e0832faSShawn Lin {
6356e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
6366e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
6376e0832faSShawn Lin 	struct device *dev = pci->dev;
6386e0832faSShawn Lin 	int ret;
6396e0832faSShawn Lin 
6406e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
6416e0832faSShawn Lin 	if (ret < 0) {
6426e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
6436e0832faSShawn Lin 		return ret;
6446e0832faSShawn Lin 	}
6456e0832faSShawn Lin 
6466e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux_clk);
6476e0832faSShawn Lin 	if (ret) {
6486e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
6496e0832faSShawn Lin 		goto err_aux_clk;
6506e0832faSShawn Lin 	}
6516e0832faSShawn Lin 
6526e0832faSShawn Lin 	ret = clk_prepare_enable(res->cfg_clk);
6536e0832faSShawn Lin 	if (ret) {
6546e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable cfg clock\n");
6556e0832faSShawn Lin 		goto err_cfg_clk;
6566e0832faSShawn Lin 	}
6576e0832faSShawn Lin 
6586e0832faSShawn Lin 	ret = clk_prepare_enable(res->master_clk);
6596e0832faSShawn Lin 	if (ret) {
6606e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable master clock\n");
6616e0832faSShawn Lin 		goto err_master_clk;
6626e0832faSShawn Lin 	}
6636e0832faSShawn Lin 
6646e0832faSShawn Lin 	ret = clk_prepare_enable(res->slave_clk);
6656e0832faSShawn Lin 	if (ret) {
6666e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable slave clock\n");
6676e0832faSShawn Lin 		goto err_slave_clk;
6686e0832faSShawn Lin 	}
6696e0832faSShawn Lin 
6706e0832faSShawn Lin 	return 0;
6716e0832faSShawn Lin 
6726e0832faSShawn Lin err_slave_clk:
6736e0832faSShawn Lin 	clk_disable_unprepare(res->master_clk);
6746e0832faSShawn Lin err_master_clk:
6756e0832faSShawn Lin 	clk_disable_unprepare(res->cfg_clk);
6766e0832faSShawn Lin err_cfg_clk:
6776e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
6786e0832faSShawn Lin 
6796e0832faSShawn Lin err_aux_clk:
6806e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
6816e0832faSShawn Lin 
6826e0832faSShawn Lin 	return ret;
6836e0832faSShawn Lin }
6846e0832faSShawn Lin 
6856e0832faSShawn Lin static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
6866e0832faSShawn Lin {
68736d9018dSRobert Marko 	u32 val;
6886e0832faSShawn Lin 
68936d9018dSRobert Marko 	/* enable PCIe clocks and resets */
69036d9018dSRobert Marko 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
69136d9018dSRobert Marko 	val &= ~BIT(0);
69236d9018dSRobert Marko 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
69336d9018dSRobert Marko 
69436d9018dSRobert Marko 	/* change DBI base address */
69536d9018dSRobert Marko 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
69636d9018dSRobert Marko 
69736d9018dSRobert Marko 	/* MAC PHY_POWERDOWN MUX DISABLE  */
69836d9018dSRobert Marko 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
69936d9018dSRobert Marko 	val &= ~BIT(29);
70036d9018dSRobert Marko 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
70136d9018dSRobert Marko 
70236d9018dSRobert Marko 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
70336d9018dSRobert Marko 	val |= BIT(4);
70436d9018dSRobert Marko 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
70536d9018dSRobert Marko 
70636d9018dSRobert Marko 	val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
70736d9018dSRobert Marko 	val |= BIT(31);
70836d9018dSRobert Marko 	writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
70936d9018dSRobert Marko 
7106e0832faSShawn Lin 	return 0;
7116e0832faSShawn Lin }
7126e0832faSShawn Lin 
7136e0832faSShawn Lin static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
7146e0832faSShawn Lin {
7156e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
7166e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
7176e0832faSShawn Lin 	struct device *dev = pci->dev;
71867021ae0SBjorn Andersson 	bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
7195aa18097SBjorn Andersson 	int ret;
7206e0832faSShawn Lin 
7215aa18097SBjorn Andersson 	res->clks[0].id = "aux";
7225aa18097SBjorn Andersson 	res->clks[1].id = "master_bus";
7235aa18097SBjorn Andersson 	res->clks[2].id = "slave_bus";
72467021ae0SBjorn Andersson 	res->clks[3].id = "iface";
7256e0832faSShawn Lin 
72667021ae0SBjorn Andersson 	/* qcom,pcie-ipq4019 is defined without "iface" */
72767021ae0SBjorn Andersson 	res->num_clks = is_ipq ? 3 : 4;
7286e0832faSShawn Lin 
7295aa18097SBjorn Andersson 	ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
7305aa18097SBjorn Andersson 	if (ret < 0)
7315aa18097SBjorn Andersson 		return ret;
7326e0832faSShawn Lin 
7336e0832faSShawn Lin 	res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
7346e0832faSShawn Lin 	if (IS_ERR(res->axi_m_reset))
7356e0832faSShawn Lin 		return PTR_ERR(res->axi_m_reset);
7366e0832faSShawn Lin 
7376e0832faSShawn Lin 	res->axi_s_reset = devm_reset_control_get_exclusive(dev, "axi_s");
7386e0832faSShawn Lin 	if (IS_ERR(res->axi_s_reset))
7396e0832faSShawn Lin 		return PTR_ERR(res->axi_s_reset);
7406e0832faSShawn Lin 
74167021ae0SBjorn Andersson 	if (is_ipq) {
74267021ae0SBjorn Andersson 		/*
74367021ae0SBjorn Andersson 		 * These resources relates to the PHY or are secure clocks, but
74467021ae0SBjorn Andersson 		 * are controlled here for IPQ4019
74567021ae0SBjorn Andersson 		 */
7466e0832faSShawn Lin 		res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
7476e0832faSShawn Lin 		if (IS_ERR(res->pipe_reset))
7486e0832faSShawn Lin 			return PTR_ERR(res->pipe_reset);
7496e0832faSShawn Lin 
7506e0832faSShawn Lin 		res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
7516e0832faSShawn Lin 									 "axi_m_vmid");
7526e0832faSShawn Lin 		if (IS_ERR(res->axi_m_vmid_reset))
7536e0832faSShawn Lin 			return PTR_ERR(res->axi_m_vmid_reset);
7546e0832faSShawn Lin 
7556e0832faSShawn Lin 		res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
7566e0832faSShawn Lin 									"axi_s_xpu");
7576e0832faSShawn Lin 		if (IS_ERR(res->axi_s_xpu_reset))
7586e0832faSShawn Lin 			return PTR_ERR(res->axi_s_xpu_reset);
7596e0832faSShawn Lin 
7606e0832faSShawn Lin 		res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
7616e0832faSShawn Lin 		if (IS_ERR(res->parf_reset))
7626e0832faSShawn Lin 			return PTR_ERR(res->parf_reset);
7636e0832faSShawn Lin 
7646e0832faSShawn Lin 		res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
7656e0832faSShawn Lin 		if (IS_ERR(res->phy_reset))
7666e0832faSShawn Lin 			return PTR_ERR(res->phy_reset);
76767021ae0SBjorn Andersson 	}
7686e0832faSShawn Lin 
7696e0832faSShawn Lin 	res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
7706e0832faSShawn Lin 								   "axi_m_sticky");
7716e0832faSShawn Lin 	if (IS_ERR(res->axi_m_sticky_reset))
7726e0832faSShawn Lin 		return PTR_ERR(res->axi_m_sticky_reset);
7736e0832faSShawn Lin 
7746e0832faSShawn Lin 	res->pipe_sticky_reset = devm_reset_control_get_exclusive(dev,
7756e0832faSShawn Lin 								  "pipe_sticky");
7766e0832faSShawn Lin 	if (IS_ERR(res->pipe_sticky_reset))
7776e0832faSShawn Lin 		return PTR_ERR(res->pipe_sticky_reset);
7786e0832faSShawn Lin 
7796e0832faSShawn Lin 	res->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr");
7806e0832faSShawn Lin 	if (IS_ERR(res->pwr_reset))
7816e0832faSShawn Lin 		return PTR_ERR(res->pwr_reset);
7826e0832faSShawn Lin 
7836e0832faSShawn Lin 	res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
7846e0832faSShawn Lin 	if (IS_ERR(res->ahb_reset))
7856e0832faSShawn Lin 		return PTR_ERR(res->ahb_reset);
7866e0832faSShawn Lin 
78767021ae0SBjorn Andersson 	if (is_ipq) {
7886e0832faSShawn Lin 		res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
7896e0832faSShawn Lin 		if (IS_ERR(res->phy_ahb_reset))
7906e0832faSShawn Lin 			return PTR_ERR(res->phy_ahb_reset);
79167021ae0SBjorn Andersson 	}
7926e0832faSShawn Lin 
7936e0832faSShawn Lin 	return 0;
7946e0832faSShawn Lin }
7956e0832faSShawn Lin 
7966e0832faSShawn Lin static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
7976e0832faSShawn Lin {
7986e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
7996e0832faSShawn Lin 
8006e0832faSShawn Lin 	reset_control_assert(res->axi_m_reset);
8016e0832faSShawn Lin 	reset_control_assert(res->axi_s_reset);
8026e0832faSShawn Lin 	reset_control_assert(res->pipe_reset);
8036e0832faSShawn Lin 	reset_control_assert(res->pipe_sticky_reset);
8046e0832faSShawn Lin 	reset_control_assert(res->phy_reset);
8056e0832faSShawn Lin 	reset_control_assert(res->phy_ahb_reset);
8066e0832faSShawn Lin 	reset_control_assert(res->axi_m_sticky_reset);
8076e0832faSShawn Lin 	reset_control_assert(res->pwr_reset);
8086e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
8095aa18097SBjorn Andersson 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
8106e0832faSShawn Lin }
8116e0832faSShawn Lin 
8126e0832faSShawn Lin static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
8136e0832faSShawn Lin {
8146e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
8156e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
8166e0832faSShawn Lin 	struct device *dev = pci->dev;
8176e0832faSShawn Lin 	int ret;
8186e0832faSShawn Lin 
8196e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_reset);
8206e0832faSShawn Lin 	if (ret) {
8216e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master reset\n");
8226e0832faSShawn Lin 		return ret;
8236e0832faSShawn Lin 	}
8246e0832faSShawn Lin 
8256e0832faSShawn Lin 	ret = reset_control_assert(res->axi_s_reset);
8266e0832faSShawn Lin 	if (ret) {
8276e0832faSShawn Lin 		dev_err(dev, "cannot assert axi slave reset\n");
8286e0832faSShawn Lin 		return ret;
8296e0832faSShawn Lin 	}
8306e0832faSShawn Lin 
8316e0832faSShawn Lin 	usleep_range(10000, 12000);
8326e0832faSShawn Lin 
8336e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_reset);
8346e0832faSShawn Lin 	if (ret) {
8356e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe reset\n");
8366e0832faSShawn Lin 		return ret;
8376e0832faSShawn Lin 	}
8386e0832faSShawn Lin 
8396e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_sticky_reset);
8406e0832faSShawn Lin 	if (ret) {
8416e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe sticky reset\n");
8426e0832faSShawn Lin 		return ret;
8436e0832faSShawn Lin 	}
8446e0832faSShawn Lin 
8456e0832faSShawn Lin 	ret = reset_control_assert(res->phy_reset);
8466e0832faSShawn Lin 	if (ret) {
8476e0832faSShawn Lin 		dev_err(dev, "cannot assert phy reset\n");
8486e0832faSShawn Lin 		return ret;
8496e0832faSShawn Lin 	}
8506e0832faSShawn Lin 
8516e0832faSShawn Lin 	ret = reset_control_assert(res->phy_ahb_reset);
8526e0832faSShawn Lin 	if (ret) {
8536e0832faSShawn Lin 		dev_err(dev, "cannot assert phy ahb reset\n");
8546e0832faSShawn Lin 		return ret;
8556e0832faSShawn Lin 	}
8566e0832faSShawn Lin 
8576e0832faSShawn Lin 	usleep_range(10000, 12000);
8586e0832faSShawn Lin 
8596e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_sticky_reset);
8606e0832faSShawn Lin 	if (ret) {
8616e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master sticky reset\n");
8626e0832faSShawn Lin 		return ret;
8636e0832faSShawn Lin 	}
8646e0832faSShawn Lin 
8656e0832faSShawn Lin 	ret = reset_control_assert(res->pwr_reset);
8666e0832faSShawn Lin 	if (ret) {
8676e0832faSShawn Lin 		dev_err(dev, "cannot assert power reset\n");
8686e0832faSShawn Lin 		return ret;
8696e0832faSShawn Lin 	}
8706e0832faSShawn Lin 
8716e0832faSShawn Lin 	ret = reset_control_assert(res->ahb_reset);
8726e0832faSShawn Lin 	if (ret) {
8736e0832faSShawn Lin 		dev_err(dev, "cannot assert ahb reset\n");
8746e0832faSShawn Lin 		return ret;
8756e0832faSShawn Lin 	}
8766e0832faSShawn Lin 
8776e0832faSShawn Lin 	usleep_range(10000, 12000);
8786e0832faSShawn Lin 
8796e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_ahb_reset);
8806e0832faSShawn Lin 	if (ret) {
8816e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy ahb reset\n");
8826e0832faSShawn Lin 		return ret;
8836e0832faSShawn Lin 	}
8846e0832faSShawn Lin 
8856e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_reset);
8866e0832faSShawn Lin 	if (ret) {
8876e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy reset\n");
8886e0832faSShawn Lin 		goto err_rst_phy;
8896e0832faSShawn Lin 	}
8906e0832faSShawn Lin 
8916e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_reset);
8926e0832faSShawn Lin 	if (ret) {
8936e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe reset\n");
8946e0832faSShawn Lin 		goto err_rst_pipe;
8956e0832faSShawn Lin 	}
8966e0832faSShawn Lin 
8976e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_sticky_reset);
8986e0832faSShawn Lin 	if (ret) {
8996e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe sticky reset\n");
9006e0832faSShawn Lin 		goto err_rst_pipe_sticky;
9016e0832faSShawn Lin 	}
9026e0832faSShawn Lin 
9036e0832faSShawn Lin 	usleep_range(10000, 12000);
9046e0832faSShawn Lin 
9056e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_reset);
9066e0832faSShawn Lin 	if (ret) {
9076e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master reset\n");
9086e0832faSShawn Lin 		goto err_rst_axi_m;
9096e0832faSShawn Lin 	}
9106e0832faSShawn Lin 
9116e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_sticky_reset);
9126e0832faSShawn Lin 	if (ret) {
9136e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master sticky reset\n");
9146e0832faSShawn Lin 		goto err_rst_axi_m_sticky;
9156e0832faSShawn Lin 	}
9166e0832faSShawn Lin 
9176e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_s_reset);
9186e0832faSShawn Lin 	if (ret) {
9196e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi slave reset\n");
9206e0832faSShawn Lin 		goto err_rst_axi_s;
9216e0832faSShawn Lin 	}
9226e0832faSShawn Lin 
9236e0832faSShawn Lin 	ret = reset_control_deassert(res->pwr_reset);
9246e0832faSShawn Lin 	if (ret) {
9256e0832faSShawn Lin 		dev_err(dev, "cannot deassert power reset\n");
9266e0832faSShawn Lin 		goto err_rst_pwr;
9276e0832faSShawn Lin 	}
9286e0832faSShawn Lin 
9296e0832faSShawn Lin 	ret = reset_control_deassert(res->ahb_reset);
9306e0832faSShawn Lin 	if (ret) {
9316e0832faSShawn Lin 		dev_err(dev, "cannot deassert ahb reset\n");
9326e0832faSShawn Lin 		goto err_rst_ahb;
9336e0832faSShawn Lin 	}
9346e0832faSShawn Lin 
9356e0832faSShawn Lin 	usleep_range(10000, 12000);
9366e0832faSShawn Lin 
9375aa18097SBjorn Andersson 	ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
9385aa18097SBjorn Andersson 	if (ret)
9395aa18097SBjorn Andersson 		goto err_clks;
9406e0832faSShawn Lin 
94136d9018dSRobert Marko 	return 0;
94236d9018dSRobert Marko 
94336d9018dSRobert Marko err_clks:
94436d9018dSRobert Marko 	reset_control_assert(res->ahb_reset);
94536d9018dSRobert Marko err_rst_ahb:
94636d9018dSRobert Marko 	reset_control_assert(res->pwr_reset);
94736d9018dSRobert Marko err_rst_pwr:
94836d9018dSRobert Marko 	reset_control_assert(res->axi_s_reset);
94936d9018dSRobert Marko err_rst_axi_s:
95036d9018dSRobert Marko 	reset_control_assert(res->axi_m_sticky_reset);
95136d9018dSRobert Marko err_rst_axi_m_sticky:
95236d9018dSRobert Marko 	reset_control_assert(res->axi_m_reset);
95336d9018dSRobert Marko err_rst_axi_m:
95436d9018dSRobert Marko 	reset_control_assert(res->pipe_sticky_reset);
95536d9018dSRobert Marko err_rst_pipe_sticky:
95636d9018dSRobert Marko 	reset_control_assert(res->pipe_reset);
95736d9018dSRobert Marko err_rst_pipe:
95836d9018dSRobert Marko 	reset_control_assert(res->phy_reset);
95936d9018dSRobert Marko err_rst_phy:
96036d9018dSRobert Marko 	reset_control_assert(res->phy_ahb_reset);
96136d9018dSRobert Marko 	return ret;
96236d9018dSRobert Marko }
96336d9018dSRobert Marko 
96436d9018dSRobert Marko static int qcom_pcie_post_init_2_4_0(struct qcom_pcie *pcie)
96536d9018dSRobert Marko {
96636d9018dSRobert Marko 	u32 val;
96736d9018dSRobert Marko 
9686e0832faSShawn Lin 	/* enable PCIe clocks and resets */
9696e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
9706e0832faSShawn Lin 	val &= ~BIT(0);
9716e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
9726e0832faSShawn Lin 
9736e0832faSShawn Lin 	/* change DBI base address */
9746e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
9756e0832faSShawn Lin 
9766e0832faSShawn Lin 	/* MAC PHY_POWERDOWN MUX DISABLE  */
9776e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
9786e0832faSShawn Lin 	val &= ~BIT(29);
9796e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
9806e0832faSShawn Lin 
9816e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
9826e0832faSShawn Lin 	val |= BIT(4);
9836e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
9846e0832faSShawn Lin 
9856e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
9866e0832faSShawn Lin 	val |= BIT(31);
9876e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
9886e0832faSShawn Lin 
9896e0832faSShawn Lin 	return 0;
9906e0832faSShawn Lin }
9916e0832faSShawn Lin 
9926e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_3(struct qcom_pcie *pcie)
9936e0832faSShawn Lin {
9946e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
9956e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
9966e0832faSShawn Lin 	struct device *dev = pci->dev;
9976e0832faSShawn Lin 	int i;
9986e0832faSShawn Lin 	const char *rst_names[] = { "axi_m", "axi_s", "pipe",
9996e0832faSShawn Lin 				    "axi_m_sticky", "sticky",
10006e0832faSShawn Lin 				    "ahb", "sleep", };
10016e0832faSShawn Lin 
10026e0832faSShawn Lin 	res->iface = devm_clk_get(dev, "iface");
10036e0832faSShawn Lin 	if (IS_ERR(res->iface))
10046e0832faSShawn Lin 		return PTR_ERR(res->iface);
10056e0832faSShawn Lin 
10066e0832faSShawn Lin 	res->axi_m_clk = devm_clk_get(dev, "axi_m");
10076e0832faSShawn Lin 	if (IS_ERR(res->axi_m_clk))
10086e0832faSShawn Lin 		return PTR_ERR(res->axi_m_clk);
10096e0832faSShawn Lin 
10106e0832faSShawn Lin 	res->axi_s_clk = devm_clk_get(dev, "axi_s");
10116e0832faSShawn Lin 	if (IS_ERR(res->axi_s_clk))
10126e0832faSShawn Lin 		return PTR_ERR(res->axi_s_clk);
10136e0832faSShawn Lin 
10146e0832faSShawn Lin 	res->ahb_clk = devm_clk_get(dev, "ahb");
10156e0832faSShawn Lin 	if (IS_ERR(res->ahb_clk))
10166e0832faSShawn Lin 		return PTR_ERR(res->ahb_clk);
10176e0832faSShawn Lin 
10186e0832faSShawn Lin 	res->aux_clk = devm_clk_get(dev, "aux");
10196e0832faSShawn Lin 	if (IS_ERR(res->aux_clk))
10206e0832faSShawn Lin 		return PTR_ERR(res->aux_clk);
10216e0832faSShawn Lin 
10226e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(rst_names); i++) {
10236e0832faSShawn Lin 		res->rst[i] = devm_reset_control_get(dev, rst_names[i]);
10246e0832faSShawn Lin 		if (IS_ERR(res->rst[i]))
10256e0832faSShawn Lin 			return PTR_ERR(res->rst[i]);
10266e0832faSShawn Lin 	}
10276e0832faSShawn Lin 
10286e0832faSShawn Lin 	return 0;
10296e0832faSShawn Lin }
10306e0832faSShawn Lin 
10316e0832faSShawn Lin static void qcom_pcie_deinit_2_3_3(struct qcom_pcie *pcie)
10326e0832faSShawn Lin {
10336e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
10346e0832faSShawn Lin 
10356e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
10366e0832faSShawn Lin 	clk_disable_unprepare(res->axi_m_clk);
10376e0832faSShawn Lin 	clk_disable_unprepare(res->axi_s_clk);
10386e0832faSShawn Lin 	clk_disable_unprepare(res->ahb_clk);
10396e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
10406e0832faSShawn Lin }
10416e0832faSShawn Lin 
10426e0832faSShawn Lin static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
10436e0832faSShawn Lin {
10446e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
10456e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
10466e0832faSShawn Lin 	struct device *dev = pci->dev;
10476e0832faSShawn Lin 	int i, ret;
10486e0832faSShawn Lin 
10496e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
10506e0832faSShawn Lin 		ret = reset_control_assert(res->rst[i]);
10516e0832faSShawn Lin 		if (ret) {
10526e0832faSShawn Lin 			dev_err(dev, "reset #%d assert failed (%d)\n", i, ret);
10536e0832faSShawn Lin 			return ret;
10546e0832faSShawn Lin 		}
10556e0832faSShawn Lin 	}
10566e0832faSShawn Lin 
10576e0832faSShawn Lin 	usleep_range(2000, 2500);
10586e0832faSShawn Lin 
10596e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
10606e0832faSShawn Lin 		ret = reset_control_deassert(res->rst[i]);
10616e0832faSShawn Lin 		if (ret) {
10626e0832faSShawn Lin 			dev_err(dev, "reset #%d deassert failed (%d)\n", i,
10636e0832faSShawn Lin 				ret);
10646e0832faSShawn Lin 			return ret;
10656e0832faSShawn Lin 		}
10666e0832faSShawn Lin 	}
10676e0832faSShawn Lin 
10686e0832faSShawn Lin 	/*
10696e0832faSShawn Lin 	 * Don't have a way to see if the reset has completed.
10706e0832faSShawn Lin 	 * Wait for some time.
10716e0832faSShawn Lin 	 */
10726e0832faSShawn Lin 	usleep_range(2000, 2500);
10736e0832faSShawn Lin 
10746e0832faSShawn Lin 	ret = clk_prepare_enable(res->iface);
10756e0832faSShawn Lin 	if (ret) {
10766e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable core clock\n");
10776e0832faSShawn Lin 		goto err_clk_iface;
10786e0832faSShawn Lin 	}
10796e0832faSShawn Lin 
10806e0832faSShawn Lin 	ret = clk_prepare_enable(res->axi_m_clk);
10816e0832faSShawn Lin 	if (ret) {
10826e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable core clock\n");
10836e0832faSShawn Lin 		goto err_clk_axi_m;
10846e0832faSShawn Lin 	}
10856e0832faSShawn Lin 
10866e0832faSShawn Lin 	ret = clk_prepare_enable(res->axi_s_clk);
10876e0832faSShawn Lin 	if (ret) {
10886e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable axi slave clock\n");
10896e0832faSShawn Lin 		goto err_clk_axi_s;
10906e0832faSShawn Lin 	}
10916e0832faSShawn Lin 
10926e0832faSShawn Lin 	ret = clk_prepare_enable(res->ahb_clk);
10936e0832faSShawn Lin 	if (ret) {
10946e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable ahb clock\n");
10956e0832faSShawn Lin 		goto err_clk_ahb;
10966e0832faSShawn Lin 	}
10976e0832faSShawn Lin 
10986e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux_clk);
10996e0832faSShawn Lin 	if (ret) {
11006e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
11016e0832faSShawn Lin 		goto err_clk_aux;
11026e0832faSShawn Lin 	}
11036e0832faSShawn Lin 
1104a0e43bb9SRobert Marko 	return 0;
1105a0e43bb9SRobert Marko 
1106a0e43bb9SRobert Marko err_clk_aux:
1107a0e43bb9SRobert Marko 	clk_disable_unprepare(res->ahb_clk);
1108a0e43bb9SRobert Marko err_clk_ahb:
1109a0e43bb9SRobert Marko 	clk_disable_unprepare(res->axi_s_clk);
1110a0e43bb9SRobert Marko err_clk_axi_s:
1111a0e43bb9SRobert Marko 	clk_disable_unprepare(res->axi_m_clk);
1112a0e43bb9SRobert Marko err_clk_axi_m:
1113a0e43bb9SRobert Marko 	clk_disable_unprepare(res->iface);
1114a0e43bb9SRobert Marko err_clk_iface:
1115a0e43bb9SRobert Marko 	/*
1116a0e43bb9SRobert Marko 	 * Not checking for failure, will anyway return
1117a0e43bb9SRobert Marko 	 * the original failure in 'ret'.
1118a0e43bb9SRobert Marko 	 */
1119a0e43bb9SRobert Marko 	for (i = 0; i < ARRAY_SIZE(res->rst); i++)
1120a0e43bb9SRobert Marko 		reset_control_assert(res->rst[i]);
1121a0e43bb9SRobert Marko 
1122a0e43bb9SRobert Marko 	return ret;
1123a0e43bb9SRobert Marko }
1124a0e43bb9SRobert Marko 
1125a0e43bb9SRobert Marko static int qcom_pcie_post_init_2_3_3(struct qcom_pcie *pcie)
1126a0e43bb9SRobert Marko {
1127a0e43bb9SRobert Marko 	struct dw_pcie *pci = pcie->pci;
1128a0e43bb9SRobert Marko 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
1129a0e43bb9SRobert Marko 	u32 val;
1130a0e43bb9SRobert Marko 
11316e0832faSShawn Lin 	writel(SLV_ADDR_SPACE_SZ,
11326e0832faSShawn Lin 		pcie->parf + PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE);
11336e0832faSShawn Lin 
11346e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
11356e0832faSShawn Lin 	val &= ~BIT(0);
11366e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
11376e0832faSShawn Lin 
11386e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
11396e0832faSShawn Lin 
11406e0832faSShawn Lin 	writel(MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS
11416e0832faSShawn Lin 		| SLV_ACLK_CGC_DIS | CORE_CLK_CGC_DIS |
11426e0832faSShawn Lin 		AUX_PWR_DET | L23_CLK_RMV_DIS | L1_CLK_RMV_DIS,
11436e0832faSShawn Lin 		pcie->parf + PCIE20_PARF_SYS_CTRL);
11446e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_Q2A_FLUSH);
11456e0832faSShawn Lin 
1146824001cbSAnsuel Smith 	writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
11476e0832faSShawn Lin 	writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
1148*9a765805SBaruch Siach 	writel(PCIE_CAP_SLOT_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
11496e0832faSShawn Lin 
11507b87ddc0SRob Herring 	val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
1151824001cbSAnsuel Smith 	val &= ~PCI_EXP_LNKCAP_ASPMS;
11527b87ddc0SRob Herring 	writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
11536e0832faSShawn Lin 
11547b87ddc0SRob Herring 	writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
11557b87ddc0SRob Herring 		PCI_EXP_DEVCTL2);
11566e0832faSShawn Lin 
11576e0832faSShawn Lin 	return 0;
11586e0832faSShawn Lin }
11596e0832faSShawn Lin 
1160ed8cc3b1SBjorn Andersson static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
1161ed8cc3b1SBjorn Andersson {
1162ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1163ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1164ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
11651c5aa037SDmitry Baryshkov 	unsigned int idx;
1166ed8cc3b1SBjorn Andersson 	int ret;
1167ed8cc3b1SBjorn Andersson 
1168ed8cc3b1SBjorn Andersson 	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
1169ed8cc3b1SBjorn Andersson 	if (IS_ERR(res->pci_reset))
1170ed8cc3b1SBjorn Andersson 		return PTR_ERR(res->pci_reset);
1171ed8cc3b1SBjorn Andersson 
1172ed8cc3b1SBjorn Andersson 	res->supplies[0].supply = "vdda";
1173ed8cc3b1SBjorn Andersson 	res->supplies[1].supply = "vddpe-3v3";
1174ed8cc3b1SBjorn Andersson 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
1175ed8cc3b1SBjorn Andersson 				      res->supplies);
1176ed8cc3b1SBjorn Andersson 	if (ret)
1177ed8cc3b1SBjorn Andersson 		return ret;
1178ed8cc3b1SBjorn Andersson 
11791c5aa037SDmitry Baryshkov 	idx = 0;
11801c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "aux";
11811c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "cfg";
11821c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "bus_master";
11831c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "bus_slave";
11841c5aa037SDmitry Baryshkov 	res->clks[idx++].id = "slave_q2a";
11851c5aa037SDmitry Baryshkov 	if (pcie->cfg->has_tbu_clk)
11861c5aa037SDmitry Baryshkov 		res->clks[idx++].id = "tbu";
11871c5aa037SDmitry Baryshkov 	if (pcie->cfg->has_ddrss_sf_tbu_clk)
11881c5aa037SDmitry Baryshkov 		res->clks[idx++].id = "ddrss_sf_tbu";
11891c5aa037SDmitry Baryshkov 	if (pcie->cfg->has_aggre0_clk)
11901c5aa037SDmitry Baryshkov 		res->clks[idx++].id = "aggre0";
11911c5aa037SDmitry Baryshkov 	if (pcie->cfg->has_aggre1_clk)
11921c5aa037SDmitry Baryshkov 		res->clks[idx++].id = "aggre1";
11931c5aa037SDmitry Baryshkov 
11941c5aa037SDmitry Baryshkov 	res->num_clks = idx;
1195ed8cc3b1SBjorn Andersson 
11967081556fSDmitry Baryshkov 	ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
1197ed8cc3b1SBjorn Andersson 	if (ret < 0)
1198ed8cc3b1SBjorn Andersson 		return ret;
1199ed8cc3b1SBjorn Andersson 
1200affac98aSDmitry Baryshkov 	return 0;
1201ed8cc3b1SBjorn Andersson }
1202ed8cc3b1SBjorn Andersson 
1203ed8cc3b1SBjorn Andersson static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
1204ed8cc3b1SBjorn Andersson {
1205ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1206ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1207ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
1208ed8cc3b1SBjorn Andersson 	u32 val;
1209ed8cc3b1SBjorn Andersson 	int ret;
1210ed8cc3b1SBjorn Andersson 
1211ed8cc3b1SBjorn Andersson 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
1212ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1213ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot enable regulators\n");
1214ed8cc3b1SBjorn Andersson 		return ret;
1215ed8cc3b1SBjorn Andersson 	}
1216ed8cc3b1SBjorn Andersson 
12177081556fSDmitry Baryshkov 	ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
1218ed8cc3b1SBjorn Andersson 	if (ret < 0)
1219ed8cc3b1SBjorn Andersson 		goto err_disable_regulators;
1220ed8cc3b1SBjorn Andersson 
1221ed8cc3b1SBjorn Andersson 	ret = reset_control_assert(res->pci_reset);
1222ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1223ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot deassert pci reset\n");
1224ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1225ed8cc3b1SBjorn Andersson 	}
1226ed8cc3b1SBjorn Andersson 
1227ed8cc3b1SBjorn Andersson 	usleep_range(1000, 1500);
1228ed8cc3b1SBjorn Andersson 
1229ed8cc3b1SBjorn Andersson 	ret = reset_control_deassert(res->pci_reset);
1230ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1231ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot deassert pci reset\n");
1232ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1233ed8cc3b1SBjorn Andersson 	}
1234ed8cc3b1SBjorn Andersson 
12351c5aa037SDmitry Baryshkov 	/* Wait for reset to complete, required on SM8450 */
12361c5aa037SDmitry Baryshkov 	usleep_range(1000, 1500);
12371c5aa037SDmitry Baryshkov 
1238ed8cc3b1SBjorn Andersson 	/* configure PCIe to RC mode */
1239ed8cc3b1SBjorn Andersson 	writel(DEVICE_TYPE_RC, pcie->parf + PCIE20_PARF_DEVICE_TYPE);
1240ed8cc3b1SBjorn Andersson 
1241ed8cc3b1SBjorn Andersson 	/* enable PCIe clocks and resets */
1242ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
1243ed8cc3b1SBjorn Andersson 	val &= ~BIT(0);
1244ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
1245ed8cc3b1SBjorn Andersson 
1246ed8cc3b1SBjorn Andersson 	/* change DBI base address */
1247ed8cc3b1SBjorn Andersson 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
1248ed8cc3b1SBjorn Andersson 
1249ed8cc3b1SBjorn Andersson 	/* MAC PHY_POWERDOWN MUX DISABLE  */
1250ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
1251ed8cc3b1SBjorn Andersson 	val &= ~BIT(29);
1252ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
1253ed8cc3b1SBjorn Andersson 
1254ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
1255ed8cc3b1SBjorn Andersson 	val |= BIT(4);
1256ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
1257ed8cc3b1SBjorn Andersson 
1258ed8cc3b1SBjorn Andersson 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
1259ed8cc3b1SBjorn Andersson 		val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
1260ed8cc3b1SBjorn Andersson 		val |= BIT(31);
1261ed8cc3b1SBjorn Andersson 		writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
1262ed8cc3b1SBjorn Andersson 	}
1263ed8cc3b1SBjorn Andersson 
1264ed8cc3b1SBjorn Andersson 	return 0;
1265ed8cc3b1SBjorn Andersson err_disable_clocks:
12667081556fSDmitry Baryshkov 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
1267ed8cc3b1SBjorn Andersson err_disable_regulators:
1268ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1269ed8cc3b1SBjorn Andersson 
1270ed8cc3b1SBjorn Andersson 	return ret;
1271ed8cc3b1SBjorn Andersson }
1272ed8cc3b1SBjorn Andersson 
1273ed8cc3b1SBjorn Andersson static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
1274ed8cc3b1SBjorn Andersson {
1275ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1276ed8cc3b1SBjorn Andersson 
12777081556fSDmitry Baryshkov 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
12787eb5768cSDmitry Baryshkov 
1279ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1280ed8cc3b1SBjorn Andersson }
1281ed8cc3b1SBjorn Andersson 
12826e0832faSShawn Lin static int qcom_pcie_link_up(struct dw_pcie *pci)
12836e0832faSShawn Lin {
12847b87ddc0SRob Herring 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
12857b87ddc0SRob Herring 	u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
12866e0832faSShawn Lin 
12876e0832faSShawn Lin 	return !!(val & PCI_EXP_LNKSTA_DLLLA);
12886e0832faSShawn Lin }
12896e0832faSShawn Lin 
12904c939882SManivannan Sadhasivam static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
12914c939882SManivannan Sadhasivam {
12924c939882SManivannan Sadhasivam 	/* iommu map structure */
12934c939882SManivannan Sadhasivam 	struct {
12944c939882SManivannan Sadhasivam 		u32 bdf;
12954c939882SManivannan Sadhasivam 		u32 phandle;
12964c939882SManivannan Sadhasivam 		u32 smmu_sid;
12974c939882SManivannan Sadhasivam 		u32 smmu_sid_len;
12984c939882SManivannan Sadhasivam 	} *map;
12994c939882SManivannan Sadhasivam 	void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
13004c939882SManivannan Sadhasivam 	struct device *dev = pcie->pci->dev;
13014c939882SManivannan Sadhasivam 	u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
13024c939882SManivannan Sadhasivam 	int i, nr_map, size = 0;
13034c939882SManivannan Sadhasivam 	u32 smmu_sid_base;
13044c939882SManivannan Sadhasivam 
13054c939882SManivannan Sadhasivam 	of_get_property(dev->of_node, "iommu-map", &size);
13064c939882SManivannan Sadhasivam 	if (!size)
13074c939882SManivannan Sadhasivam 		return 0;
13084c939882SManivannan Sadhasivam 
13094c939882SManivannan Sadhasivam 	map = kzalloc(size, GFP_KERNEL);
13104c939882SManivannan Sadhasivam 	if (!map)
13114c939882SManivannan Sadhasivam 		return -ENOMEM;
13124c939882SManivannan Sadhasivam 
13134c939882SManivannan Sadhasivam 	of_property_read_u32_array(dev->of_node,
13144c939882SManivannan Sadhasivam 		"iommu-map", (u32 *)map, size / sizeof(u32));
13154c939882SManivannan Sadhasivam 
13164c939882SManivannan Sadhasivam 	nr_map = size / (sizeof(*map));
13174c939882SManivannan Sadhasivam 
13184c939882SManivannan Sadhasivam 	crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
13194c939882SManivannan Sadhasivam 
13204c939882SManivannan Sadhasivam 	/* Registers need to be zero out first */
13214c939882SManivannan Sadhasivam 	memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
13224c939882SManivannan Sadhasivam 
13234c939882SManivannan Sadhasivam 	/* Extract the SMMU SID base from the first entry of iommu-map */
13244c939882SManivannan Sadhasivam 	smmu_sid_base = map[0].smmu_sid;
13254c939882SManivannan Sadhasivam 
13264c939882SManivannan Sadhasivam 	/* Look for an available entry to hold the mapping */
13274c939882SManivannan Sadhasivam 	for (i = 0; i < nr_map; i++) {
13283f13d611SManivannan Sadhasivam 		__be16 bdf_be = cpu_to_be16(map[i].bdf);
13294c939882SManivannan Sadhasivam 		u32 val;
13304c939882SManivannan Sadhasivam 		u8 hash;
13314c939882SManivannan Sadhasivam 
13324c939882SManivannan Sadhasivam 		hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
13334c939882SManivannan Sadhasivam 			0);
13344c939882SManivannan Sadhasivam 
13354c939882SManivannan Sadhasivam 		val = readl(bdf_to_sid_base + hash * sizeof(u32));
13364c939882SManivannan Sadhasivam 
13374c939882SManivannan Sadhasivam 		/* If the register is already populated, look for next available entry */
13384c939882SManivannan Sadhasivam 		while (val) {
13394c939882SManivannan Sadhasivam 			u8 current_hash = hash++;
13404c939882SManivannan Sadhasivam 			u8 next_mask = 0xff;
13414c939882SManivannan Sadhasivam 
13424c939882SManivannan Sadhasivam 			/* If NEXT field is NULL then update it with next hash */
13434c939882SManivannan Sadhasivam 			if (!(val & next_mask)) {
13444c939882SManivannan Sadhasivam 				val |= (u32)hash;
13454c939882SManivannan Sadhasivam 				writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
13464c939882SManivannan Sadhasivam 			}
13474c939882SManivannan Sadhasivam 
13484c939882SManivannan Sadhasivam 			val = readl(bdf_to_sid_base + hash * sizeof(u32));
13494c939882SManivannan Sadhasivam 		}
13504c939882SManivannan Sadhasivam 
13514c939882SManivannan Sadhasivam 		/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
13524c939882SManivannan Sadhasivam 		val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
13534c939882SManivannan Sadhasivam 		writel(val, bdf_to_sid_base + hash * sizeof(u32));
13544c939882SManivannan Sadhasivam 	}
13554c939882SManivannan Sadhasivam 
13564c939882SManivannan Sadhasivam 	kfree(map);
13574c939882SManivannan Sadhasivam 
13584c939882SManivannan Sadhasivam 	return 0;
13594c939882SManivannan Sadhasivam }
13604c939882SManivannan Sadhasivam 
13616e0832faSShawn Lin static int qcom_pcie_host_init(struct pcie_port *pp)
13626e0832faSShawn Lin {
13636e0832faSShawn Lin 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
13646e0832faSShawn Lin 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
13656e0832faSShawn Lin 	int ret;
13666e0832faSShawn Lin 
13676e0832faSShawn Lin 	qcom_ep_reset_assert(pcie);
13686e0832faSShawn Lin 
1369f94c35e0SDmitry Baryshkov 	ret = pcie->cfg->ops->init(pcie);
13706e0832faSShawn Lin 	if (ret)
13716e0832faSShawn Lin 		return ret;
13726e0832faSShawn Lin 
13736e0832faSShawn Lin 	ret = phy_power_on(pcie->phy);
13746e0832faSShawn Lin 	if (ret)
13756e0832faSShawn Lin 		goto err_deinit;
13766e0832faSShawn Lin 
1377f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->post_init) {
1378f94c35e0SDmitry Baryshkov 		ret = pcie->cfg->ops->post_init(pcie);
13796e0832faSShawn Lin 		if (ret)
13806e0832faSShawn Lin 			goto err_disable_phy;
13816e0832faSShawn Lin 	}
13826e0832faSShawn Lin 
13836e0832faSShawn Lin 	qcom_ep_reset_deassert(pcie);
13846e0832faSShawn Lin 
1385f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->config_sid) {
1386f94c35e0SDmitry Baryshkov 		ret = pcie->cfg->ops->config_sid(pcie);
13874c939882SManivannan Sadhasivam 		if (ret)
13884c939882SManivannan Sadhasivam 			goto err;
13894c939882SManivannan Sadhasivam 	}
13904c939882SManivannan Sadhasivam 
13916e0832faSShawn Lin 	return 0;
1392886a9c13SRob Herring 
13934c939882SManivannan Sadhasivam err:
13944c939882SManivannan Sadhasivam 	qcom_ep_reset_assert(pcie);
1395f94c35e0SDmitry Baryshkov 	if (pcie->cfg->ops->post_deinit)
1396f94c35e0SDmitry Baryshkov 		pcie->cfg->ops->post_deinit(pcie);
13976e0832faSShawn Lin err_disable_phy:
13986e0832faSShawn Lin 	phy_power_off(pcie->phy);
13996e0832faSShawn Lin err_deinit:
1400f94c35e0SDmitry Baryshkov 	pcie->cfg->ops->deinit(pcie);
14016e0832faSShawn Lin 
14026e0832faSShawn Lin 	return ret;
14036e0832faSShawn Lin }
14046e0832faSShawn Lin 
14056e0832faSShawn Lin static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
14066e0832faSShawn Lin 	.host_init = qcom_pcie_host_init,
14076e0832faSShawn Lin };
14086e0832faSShawn Lin 
14096e0832faSShawn Lin /* Qcom IP rev.: 2.1.0	Synopsys IP rev.: 4.01a */
14106e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_1_0 = {
14116e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_1_0,
14126e0832faSShawn Lin 	.init = qcom_pcie_init_2_1_0,
141336d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_2_1_0,
14146e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_1_0,
14156e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
14166e0832faSShawn Lin };
14176e0832faSShawn Lin 
14186e0832faSShawn Lin /* Qcom IP rev.: 1.0.0	Synopsys IP rev.: 4.11a */
14196e0832faSShawn Lin static const struct qcom_pcie_ops ops_1_0_0 = {
14206e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_1_0_0,
14216e0832faSShawn Lin 	.init = qcom_pcie_init_1_0_0,
142236d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_1_0_0,
14236e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_1_0_0,
14246e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
14256e0832faSShawn Lin };
14266e0832faSShawn Lin 
14276e0832faSShawn Lin /* Qcom IP rev.: 2.3.2	Synopsys IP rev.: 4.21a */
14286e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_2 = {
14296e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_2,
14306e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_2,
14316e0832faSShawn Lin 	.post_init = qcom_pcie_post_init_2_3_2,
14326e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_2,
14336e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14346e0832faSShawn Lin };
14356e0832faSShawn Lin 
14366e0832faSShawn Lin /* Qcom IP rev.: 2.4.0	Synopsys IP rev.: 4.20a */
14376e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_4_0 = {
14386e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_4_0,
14396e0832faSShawn Lin 	.init = qcom_pcie_init_2_4_0,
144036d9018dSRobert Marko 	.post_init = qcom_pcie_post_init_2_4_0,
14416e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_4_0,
14426e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14436e0832faSShawn Lin };
14446e0832faSShawn Lin 
14456e0832faSShawn Lin /* Qcom IP rev.: 2.3.3	Synopsys IP rev.: 4.30a */
14466e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_3 = {
14476e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_3,
14486e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_3,
1449a0e43bb9SRobert Marko 	.post_init = qcom_pcie_post_init_2_3_3,
14506e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_3,
14516e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14526e0832faSShawn Lin };
14536e0832faSShawn Lin 
1454ed8cc3b1SBjorn Andersson /* Qcom IP rev.: 2.7.0	Synopsys IP rev.: 4.30a */
1455ed8cc3b1SBjorn Andersson static const struct qcom_pcie_ops ops_2_7_0 = {
1456ed8cc3b1SBjorn Andersson 	.get_resources = qcom_pcie_get_resources_2_7_0,
1457ed8cc3b1SBjorn Andersson 	.init = qcom_pcie_init_2_7_0,
1458ed8cc3b1SBjorn Andersson 	.deinit = qcom_pcie_deinit_2_7_0,
1459ed8cc3b1SBjorn Andersson 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
1460ed8cc3b1SBjorn Andersson };
1461ed8cc3b1SBjorn Andersson 
1462e1dd639eSManivannan Sadhasivam /* Qcom IP rev.: 1.9.0 */
1463e1dd639eSManivannan Sadhasivam static const struct qcom_pcie_ops ops_1_9_0 = {
1464e1dd639eSManivannan Sadhasivam 	.get_resources = qcom_pcie_get_resources_2_7_0,
1465e1dd639eSManivannan Sadhasivam 	.init = qcom_pcie_init_2_7_0,
1466e1dd639eSManivannan Sadhasivam 	.deinit = qcom_pcie_deinit_2_7_0,
1467e1dd639eSManivannan Sadhasivam 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14684c939882SManivannan Sadhasivam 	.config_sid = qcom_pcie_config_sid_sm8250,
1469e1dd639eSManivannan Sadhasivam };
1470e1dd639eSManivannan Sadhasivam 
1471b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg apq8084_cfg = {
1472b89ff410SPrasad Malisetty 	.ops = &ops_1_0_0,
1473b89ff410SPrasad Malisetty };
1474b89ff410SPrasad Malisetty 
1475b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg ipq8064_cfg = {
1476b89ff410SPrasad Malisetty 	.ops = &ops_2_1_0,
1477b89ff410SPrasad Malisetty };
1478b89ff410SPrasad Malisetty 
1479b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg msm8996_cfg = {
1480b89ff410SPrasad Malisetty 	.ops = &ops_2_3_2,
1481b89ff410SPrasad Malisetty };
1482b89ff410SPrasad Malisetty 
1483b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg ipq8074_cfg = {
1484b89ff410SPrasad Malisetty 	.ops = &ops_2_3_3,
1485b89ff410SPrasad Malisetty };
1486b89ff410SPrasad Malisetty 
1487b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg ipq4019_cfg = {
1488b89ff410SPrasad Malisetty 	.ops = &ops_2_4_0,
1489b89ff410SPrasad Malisetty };
1490b89ff410SPrasad Malisetty 
1491b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg sdm845_cfg = {
1492b89ff410SPrasad Malisetty 	.ops = &ops_2_7_0,
14931c5aa037SDmitry Baryshkov 	.has_tbu_clk = true,
1494b89ff410SPrasad Malisetty };
1495b89ff410SPrasad Malisetty 
1496a935601eSBhupesh Sharma static const struct qcom_pcie_cfg sm8150_cfg = {
1497a935601eSBhupesh Sharma 	/* sm8150 has qcom IP rev 1.5.0. However 1.5.0 ops are same as
1498a935601eSBhupesh Sharma 	 * 1.9.0, so reuse the same.
1499a935601eSBhupesh Sharma 	 */
1500a935601eSBhupesh Sharma 	.ops = &ops_1_9_0,
1501a935601eSBhupesh Sharma };
1502a935601eSBhupesh Sharma 
1503b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg sm8250_cfg = {
1504b89ff410SPrasad Malisetty 	.ops = &ops_1_9_0,
15051c5aa037SDmitry Baryshkov 	.has_tbu_clk = true,
15060614f98bSDmitry Baryshkov 	.has_ddrss_sf_tbu_clk = true,
1507b89ff410SPrasad Malisetty };
1508b89ff410SPrasad Malisetty 
15091c5aa037SDmitry Baryshkov static const struct qcom_pcie_cfg sm8450_pcie0_cfg = {
15101c5aa037SDmitry Baryshkov 	.ops = &ops_1_9_0,
15111c5aa037SDmitry Baryshkov 	.has_ddrss_sf_tbu_clk = true,
15121c5aa037SDmitry Baryshkov 	.has_aggre0_clk = true,
15131c5aa037SDmitry Baryshkov 	.has_aggre1_clk = true,
15141c5aa037SDmitry Baryshkov };
15151c5aa037SDmitry Baryshkov 
15161c5aa037SDmitry Baryshkov static const struct qcom_pcie_cfg sm8450_pcie1_cfg = {
15171c5aa037SDmitry Baryshkov 	.ops = &ops_1_9_0,
15181c5aa037SDmitry Baryshkov 	.has_ddrss_sf_tbu_clk = true,
15191c5aa037SDmitry Baryshkov 	.has_aggre1_clk = true,
1520b89ff410SPrasad Malisetty };
1521b89ff410SPrasad Malisetty 
1522b89ff410SPrasad Malisetty static const struct qcom_pcie_cfg sc7280_cfg = {
1523b89ff410SPrasad Malisetty 	.ops = &ops_1_9_0,
15241c5aa037SDmitry Baryshkov 	.has_tbu_clk = true,
1525b89ff410SPrasad Malisetty };
1526b89ff410SPrasad Malisetty 
1527134b5ce3SBjorn Andersson static const struct qcom_pcie_cfg sc8180x_cfg = {
1528134b5ce3SBjorn Andersson 	.ops = &ops_1_9_0,
1529134b5ce3SBjorn Andersson 	.has_tbu_clk = true,
1530134b5ce3SBjorn Andersson };
1531134b5ce3SBjorn Andersson 
15326e0832faSShawn Lin static const struct dw_pcie_ops dw_pcie_ops = {
15336e0832faSShawn Lin 	.link_up = qcom_pcie_link_up,
1534886a9c13SRob Herring 	.start_link = qcom_pcie_start_link,
15356e0832faSShawn Lin };
15366e0832faSShawn Lin 
15376e0832faSShawn Lin static int qcom_pcie_probe(struct platform_device *pdev)
15386e0832faSShawn Lin {
15396e0832faSShawn Lin 	struct device *dev = &pdev->dev;
15406e0832faSShawn Lin 	struct pcie_port *pp;
15416e0832faSShawn Lin 	struct dw_pcie *pci;
15426e0832faSShawn Lin 	struct qcom_pcie *pcie;
1543b89ff410SPrasad Malisetty 	const struct qcom_pcie_cfg *pcie_cfg;
15446e0832faSShawn Lin 	int ret;
15456e0832faSShawn Lin 
15464e0e9053SChristophe JAILLET 	pcie_cfg = of_device_get_match_data(dev);
15474e0e9053SChristophe JAILLET 	if (!pcie_cfg || !pcie_cfg->ops) {
15484e0e9053SChristophe JAILLET 		dev_err(dev, "Invalid platform data\n");
15494e0e9053SChristophe JAILLET 		return -EINVAL;
15504e0e9053SChristophe JAILLET 	}
15514e0e9053SChristophe JAILLET 
15526e0832faSShawn Lin 	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
15536e0832faSShawn Lin 	if (!pcie)
15546e0832faSShawn Lin 		return -ENOMEM;
15556e0832faSShawn Lin 
15566e0832faSShawn Lin 	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
15576e0832faSShawn Lin 	if (!pci)
15586e0832faSShawn Lin 		return -ENOMEM;
15596e0832faSShawn Lin 
15606e0832faSShawn Lin 	pm_runtime_enable(dev);
15616e5da6f7SBjorn Andersson 	ret = pm_runtime_get_sync(dev);
1562cb52a402SDinghao Liu 	if (ret < 0)
1563cb52a402SDinghao Liu 		goto err_pm_runtime_put;
15646e5da6f7SBjorn Andersson 
15656e0832faSShawn Lin 	pci->dev = dev;
15666e0832faSShawn Lin 	pci->ops = &dw_pcie_ops;
15676e0832faSShawn Lin 	pp = &pci->pp;
15686e0832faSShawn Lin 
15696e0832faSShawn Lin 	pcie->pci = pci;
15706e0832faSShawn Lin 
1571f94c35e0SDmitry Baryshkov 	pcie->cfg = pcie_cfg;
15726e0832faSShawn Lin 
157302b485e3SBjorn Andersson 	pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
15746e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->reset)) {
15756e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->reset);
15766e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15776e5da6f7SBjorn Andersson 	}
15786e0832faSShawn Lin 
1579936fa5cdSDejin Zheng 	pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
15806e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->parf)) {
15816e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->parf);
15826e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15836e5da6f7SBjorn Andersson 	}
15846e0832faSShawn Lin 
1585936fa5cdSDejin Zheng 	pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
15866e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->elbi)) {
15876e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->elbi);
15886e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15896e5da6f7SBjorn Andersson 	}
15906e0832faSShawn Lin 
15916e0832faSShawn Lin 	pcie->phy = devm_phy_optional_get(dev, "pciephy");
15926e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->phy)) {
15936e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->phy);
15946e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15956e5da6f7SBjorn Andersson 	}
15966e0832faSShawn Lin 
1597f94c35e0SDmitry Baryshkov 	ret = pcie->cfg->ops->get_resources(pcie);
15986e0832faSShawn Lin 	if (ret)
15996e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16006e0832faSShawn Lin 
16016e0832faSShawn Lin 	pp->ops = &qcom_pcie_dw_ops;
16026e0832faSShawn Lin 
16036e0832faSShawn Lin 	ret = phy_init(pcie->phy);
160487d83b96SJohan Hovold 	if (ret)
16056e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
16066e0832faSShawn Lin 
16076e0832faSShawn Lin 	platform_set_drvdata(pdev, pcie);
16086e0832faSShawn Lin 
16096e0832faSShawn Lin 	ret = dw_pcie_host_init(pp);
16106e0832faSShawn Lin 	if (ret) {
16116e0832faSShawn Lin 		dev_err(dev, "cannot initialize host\n");
161283013631SJohan Hovold 		goto err_phy_exit;
16136e0832faSShawn Lin 	}
16146e0832faSShawn Lin 
16156e0832faSShawn Lin 	return 0;
16166e5da6f7SBjorn Andersson 
161783013631SJohan Hovold err_phy_exit:
161883013631SJohan Hovold 	phy_exit(pcie->phy);
16196e5da6f7SBjorn Andersson err_pm_runtime_put:
16206e5da6f7SBjorn Andersson 	pm_runtime_put(dev);
16216e5da6f7SBjorn Andersson 	pm_runtime_disable(dev);
16226e5da6f7SBjorn Andersson 
16236e5da6f7SBjorn Andersson 	return ret;
16246e0832faSShawn Lin }
16256e0832faSShawn Lin 
16266e0832faSShawn Lin static const struct of_device_id qcom_pcie_match[] = {
1627b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-apq8084", .data = &apq8084_cfg },
1628b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-ipq8064", .data = &ipq8064_cfg },
1629b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-ipq8064-v2", .data = &ipq8064_cfg },
1630b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-apq8064", .data = &ipq8064_cfg },
1631b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-msm8996", .data = &msm8996_cfg },
1632b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-ipq8074", .data = &ipq8074_cfg },
1633b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-ipq4019", .data = &ipq4019_cfg },
1634b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-qcs404", .data = &ipq4019_cfg },
1635b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-sdm845", .data = &sdm845_cfg },
1636a935601eSBhupesh Sharma 	{ .compatible = "qcom,pcie-sm8150", .data = &sm8150_cfg },
1637b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-sm8250", .data = &sm8250_cfg },
1638134b5ce3SBjorn Andersson 	{ .compatible = "qcom,pcie-sc8180x", .data = &sc8180x_cfg },
16391c5aa037SDmitry Baryshkov 	{ .compatible = "qcom,pcie-sm8450-pcie0", .data = &sm8450_pcie0_cfg },
16401c5aa037SDmitry Baryshkov 	{ .compatible = "qcom,pcie-sm8450-pcie1", .data = &sm8450_pcie1_cfg },
1641b89ff410SPrasad Malisetty 	{ .compatible = "qcom,pcie-sc7280", .data = &sc7280_cfg },
16426e0832faSShawn Lin 	{ }
16436e0832faSShawn Lin };
16446e0832faSShawn Lin 
1645322f0343SMarc Gonzalez static void qcom_fixup_class(struct pci_dev *dev)
1646322f0343SMarc Gonzalez {
1647904b10fbSPali Rohár 	dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
1648322f0343SMarc Gonzalez }
1649604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0101, qcom_fixup_class);
1650604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0104, qcom_fixup_class);
1651604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0106, qcom_fixup_class);
1652604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0107, qcom_fixup_class);
1653604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0302, qcom_fixup_class);
1654604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1000, qcom_fixup_class);
1655604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1001, qcom_fixup_class);
1656322f0343SMarc Gonzalez 
16576e0832faSShawn Lin static struct platform_driver qcom_pcie_driver = {
16586e0832faSShawn Lin 	.probe = qcom_pcie_probe,
16596e0832faSShawn Lin 	.driver = {
16606e0832faSShawn Lin 		.name = "qcom-pcie",
16616e0832faSShawn Lin 		.suppress_bind_attrs = true,
16626e0832faSShawn Lin 		.of_match_table = qcom_pcie_match,
16636e0832faSShawn Lin 	},
16646e0832faSShawn Lin };
16656e0832faSShawn Lin builtin_platform_driver(qcom_pcie_driver);
1666