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>
12*4c939882SManivannan 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
61*4c939882SManivannan 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 
726e0832faSShawn Lin #define PCIE_CAP_LINK1_VAL			0x2FD7F
736e0832faSShawn Lin 
746e0832faSShawn Lin #define PCIE20_PARF_Q2A_FLUSH			0x1AC
756e0832faSShawn Lin 
766e0832faSShawn Lin #define PCIE20_MISC_CONTROL_1_REG		0x8BC
776e0832faSShawn Lin #define DBI_RO_WR_EN				1
786e0832faSShawn Lin 
796e0832faSShawn Lin #define PERST_DELAY_US				1000
805149901eSAnsuel Smith /* PARF registers */
815149901eSAnsuel Smith #define PCIE20_PARF_PCS_DEEMPH			0x34
825149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN1(x)		((x) << 16)
835149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x)	((x) << 8)
845149901eSAnsuel Smith #define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x)	((x) << 0)
855149901eSAnsuel Smith 
865149901eSAnsuel Smith #define PCIE20_PARF_PCS_SWING			0x38
875149901eSAnsuel Smith #define PCS_SWING_TX_SWING_FULL(x)		((x) << 8)
885149901eSAnsuel Smith #define PCS_SWING_TX_SWING_LOW(x)		((x) << 0)
895149901eSAnsuel Smith 
905149901eSAnsuel Smith #define PCIE20_PARF_CONFIG_BITS		0x50
915149901eSAnsuel Smith #define PHY_RX0_EQ(x)				((x) << 24)
926e0832faSShawn Lin 
936e0832faSShawn Lin #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE	0x358
946e0832faSShawn Lin #define SLV_ADDR_SPACE_SZ			0x10000000
956e0832faSShawn Lin 
9651ed2c2bSSham Muthayyan #define PCIE20_LNK_CONTROL2_LINK_STATUS2	0xa0
9751ed2c2bSSham Muthayyan 
98ed8cc3b1SBjorn Andersson #define DEVICE_TYPE_RC				0x4
99ed8cc3b1SBjorn Andersson 
1006e0832faSShawn Lin #define QCOM_PCIE_2_1_0_MAX_SUPPLY	3
1016a114526SAnsuel Smith #define QCOM_PCIE_2_1_0_MAX_CLOCKS	5
102*4c939882SManivannan Sadhasivam 
103*4c939882SManivannan Sadhasivam #define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
104*4c939882SManivannan Sadhasivam 
1056e0832faSShawn Lin struct qcom_pcie_resources_2_1_0 {
1066a114526SAnsuel Smith 	struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
1076e0832faSShawn Lin 	struct reset_control *pci_reset;
1086e0832faSShawn Lin 	struct reset_control *axi_reset;
1096e0832faSShawn Lin 	struct reset_control *ahb_reset;
1106e0832faSShawn Lin 	struct reset_control *por_reset;
1116e0832faSShawn Lin 	struct reset_control *phy_reset;
112ee367e2cSAnsuel Smith 	struct reset_control *ext_reset;
1136e0832faSShawn Lin 	struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
1146e0832faSShawn Lin };
1156e0832faSShawn Lin 
1166e0832faSShawn Lin struct qcom_pcie_resources_1_0_0 {
1176e0832faSShawn Lin 	struct clk *iface;
1186e0832faSShawn Lin 	struct clk *aux;
1196e0832faSShawn Lin 	struct clk *master_bus;
1206e0832faSShawn Lin 	struct clk *slave_bus;
1216e0832faSShawn Lin 	struct reset_control *core;
1226e0832faSShawn Lin 	struct regulator *vdda;
1236e0832faSShawn Lin };
1246e0832faSShawn Lin 
1256e0832faSShawn Lin #define QCOM_PCIE_2_3_2_MAX_SUPPLY	2
1266e0832faSShawn Lin struct qcom_pcie_resources_2_3_2 {
1276e0832faSShawn Lin 	struct clk *aux_clk;
1286e0832faSShawn Lin 	struct clk *master_clk;
1296e0832faSShawn Lin 	struct clk *slave_clk;
1306e0832faSShawn Lin 	struct clk *cfg_clk;
1316e0832faSShawn Lin 	struct clk *pipe_clk;
1326e0832faSShawn Lin 	struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
1336e0832faSShawn Lin };
1346e0832faSShawn Lin 
13567021ae0SBjorn Andersson #define QCOM_PCIE_2_4_0_MAX_CLOCKS	4
1366e0832faSShawn Lin struct qcom_pcie_resources_2_4_0 {
1375aa18097SBjorn Andersson 	struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
1385aa18097SBjorn Andersson 	int num_clks;
1396e0832faSShawn Lin 	struct reset_control *axi_m_reset;
1406e0832faSShawn Lin 	struct reset_control *axi_s_reset;
1416e0832faSShawn Lin 	struct reset_control *pipe_reset;
1426e0832faSShawn Lin 	struct reset_control *axi_m_vmid_reset;
1436e0832faSShawn Lin 	struct reset_control *axi_s_xpu_reset;
1446e0832faSShawn Lin 	struct reset_control *parf_reset;
1456e0832faSShawn Lin 	struct reset_control *phy_reset;
1466e0832faSShawn Lin 	struct reset_control *axi_m_sticky_reset;
1476e0832faSShawn Lin 	struct reset_control *pipe_sticky_reset;
1486e0832faSShawn Lin 	struct reset_control *pwr_reset;
1496e0832faSShawn Lin 	struct reset_control *ahb_reset;
1506e0832faSShawn Lin 	struct reset_control *phy_ahb_reset;
1516e0832faSShawn Lin };
1526e0832faSShawn Lin 
1536e0832faSShawn Lin struct qcom_pcie_resources_2_3_3 {
1546e0832faSShawn Lin 	struct clk *iface;
1556e0832faSShawn Lin 	struct clk *axi_m_clk;
1566e0832faSShawn Lin 	struct clk *axi_s_clk;
1576e0832faSShawn Lin 	struct clk *ahb_clk;
1586e0832faSShawn Lin 	struct clk *aux_clk;
1596e0832faSShawn Lin 	struct reset_control *rst[7];
1606e0832faSShawn Lin };
1616e0832faSShawn Lin 
162ed8cc3b1SBjorn Andersson struct qcom_pcie_resources_2_7_0 {
163ed8cc3b1SBjorn Andersson 	struct clk_bulk_data clks[6];
164ed8cc3b1SBjorn Andersson 	struct regulator_bulk_data supplies[2];
165ed8cc3b1SBjorn Andersson 	struct reset_control *pci_reset;
166ed8cc3b1SBjorn Andersson 	struct clk *pipe_clk;
167ed8cc3b1SBjorn Andersson };
168ed8cc3b1SBjorn Andersson 
1696e0832faSShawn Lin union qcom_pcie_resources {
1706e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 v1_0_0;
1716e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 v2_1_0;
1726e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 v2_3_2;
1736e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 v2_3_3;
1746e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 v2_4_0;
175ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 v2_7_0;
1766e0832faSShawn Lin };
1776e0832faSShawn Lin 
1786e0832faSShawn Lin struct qcom_pcie;
1796e0832faSShawn Lin 
1806e0832faSShawn Lin struct qcom_pcie_ops {
1816e0832faSShawn Lin 	int (*get_resources)(struct qcom_pcie *pcie);
1826e0832faSShawn Lin 	int (*init)(struct qcom_pcie *pcie);
1836e0832faSShawn Lin 	int (*post_init)(struct qcom_pcie *pcie);
1846e0832faSShawn Lin 	void (*deinit)(struct qcom_pcie *pcie);
1856e0832faSShawn Lin 	void (*post_deinit)(struct qcom_pcie *pcie);
1866e0832faSShawn Lin 	void (*ltssm_enable)(struct qcom_pcie *pcie);
187*4c939882SManivannan Sadhasivam 	int (*config_sid)(struct qcom_pcie *pcie);
1886e0832faSShawn Lin };
1896e0832faSShawn Lin 
1906e0832faSShawn Lin struct qcom_pcie {
1916e0832faSShawn Lin 	struct dw_pcie *pci;
1926e0832faSShawn Lin 	void __iomem *parf;			/* DT parf */
1936e0832faSShawn Lin 	void __iomem *elbi;			/* DT elbi */
1946e0832faSShawn Lin 	union qcom_pcie_resources res;
1956e0832faSShawn Lin 	struct phy *phy;
1966e0832faSShawn Lin 	struct gpio_desc *reset;
1976e0832faSShawn Lin 	const struct qcom_pcie_ops *ops;
1986e0832faSShawn Lin };
1996e0832faSShawn Lin 
2006e0832faSShawn Lin #define to_qcom_pcie(x)		dev_get_drvdata((x)->dev)
2016e0832faSShawn Lin 
2026e0832faSShawn Lin static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
2036e0832faSShawn Lin {
2046e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 1);
2056e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2066e0832faSShawn Lin }
2076e0832faSShawn Lin 
2086e0832faSShawn Lin static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
2096e0832faSShawn Lin {
21064adde31SNiklas Cassel 	/* Ensure that PERST has been asserted for at least 100 ms */
21164adde31SNiklas Cassel 	msleep(100);
2126e0832faSShawn Lin 	gpiod_set_value_cansleep(pcie->reset, 0);
2136e0832faSShawn Lin 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
2146e0832faSShawn Lin }
2156e0832faSShawn Lin 
216886a9c13SRob Herring static int qcom_pcie_start_link(struct dw_pcie *pci)
2176e0832faSShawn Lin {
218886a9c13SRob Herring 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
2196e0832faSShawn Lin 
2206e0832faSShawn Lin 	/* Enable Link Training state machine */
2216e0832faSShawn Lin 	if (pcie->ops->ltssm_enable)
2226e0832faSShawn Lin 		pcie->ops->ltssm_enable(pcie);
2236e0832faSShawn Lin 
224886a9c13SRob Herring 	return 0;
2256e0832faSShawn Lin }
2266e0832faSShawn Lin 
2276e0832faSShawn Lin static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
2286e0832faSShawn Lin {
2296e0832faSShawn Lin 	u32 val;
2306e0832faSShawn Lin 
2316e0832faSShawn Lin 	/* enable link training */
2326e0832faSShawn Lin 	val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL);
2336e0832faSShawn Lin 	val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
2346e0832faSShawn Lin 	writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
2356e0832faSShawn Lin }
2366e0832faSShawn Lin 
2376e0832faSShawn Lin static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
2386e0832faSShawn Lin {
2396e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
2406e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
2416e0832faSShawn Lin 	struct device *dev = pci->dev;
2426e0832faSShawn Lin 	int ret;
2436e0832faSShawn Lin 
2446e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
2456e0832faSShawn Lin 	res->supplies[1].supply = "vdda_phy";
2466e0832faSShawn Lin 	res->supplies[2].supply = "vdda_refclk";
2476e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
2486e0832faSShawn Lin 				      res->supplies);
2496e0832faSShawn Lin 	if (ret)
2506e0832faSShawn Lin 		return ret;
2516e0832faSShawn Lin 
2526a114526SAnsuel Smith 	res->clks[0].id = "iface";
2536a114526SAnsuel Smith 	res->clks[1].id = "core";
2546a114526SAnsuel Smith 	res->clks[2].id = "phy";
2556a114526SAnsuel Smith 	res->clks[3].id = "aux";
2566a114526SAnsuel Smith 	res->clks[4].id = "ref";
2576e0832faSShawn Lin 
2586a114526SAnsuel Smith 	/* iface, core, phy are required */
2596a114526SAnsuel Smith 	ret = devm_clk_bulk_get(dev, 3, res->clks);
2606a114526SAnsuel Smith 	if (ret < 0)
2616a114526SAnsuel Smith 		return ret;
2626e0832faSShawn Lin 
2636a114526SAnsuel Smith 	/* aux, ref are optional */
2646a114526SAnsuel Smith 	ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3);
2656a114526SAnsuel Smith 	if (ret < 0)
2666a114526SAnsuel Smith 		return ret;
2678b6f0330SAnsuel Smith 
2686e0832faSShawn Lin 	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
2696e0832faSShawn Lin 	if (IS_ERR(res->pci_reset))
2706e0832faSShawn Lin 		return PTR_ERR(res->pci_reset);
2716e0832faSShawn Lin 
2726e0832faSShawn Lin 	res->axi_reset = devm_reset_control_get_exclusive(dev, "axi");
2736e0832faSShawn Lin 	if (IS_ERR(res->axi_reset))
2746e0832faSShawn Lin 		return PTR_ERR(res->axi_reset);
2756e0832faSShawn Lin 
2766e0832faSShawn Lin 	res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
2776e0832faSShawn Lin 	if (IS_ERR(res->ahb_reset))
2786e0832faSShawn Lin 		return PTR_ERR(res->ahb_reset);
2796e0832faSShawn Lin 
2806e0832faSShawn Lin 	res->por_reset = devm_reset_control_get_exclusive(dev, "por");
2816e0832faSShawn Lin 	if (IS_ERR(res->por_reset))
2826e0832faSShawn Lin 		return PTR_ERR(res->por_reset);
2836e0832faSShawn Lin 
284ee367e2cSAnsuel Smith 	res->ext_reset = devm_reset_control_get_optional_exclusive(dev, "ext");
285ee367e2cSAnsuel Smith 	if (IS_ERR(res->ext_reset))
286ee367e2cSAnsuel Smith 		return PTR_ERR(res->ext_reset);
287ee367e2cSAnsuel Smith 
2886e0832faSShawn Lin 	res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
2896e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->phy_reset);
2906e0832faSShawn Lin }
2916e0832faSShawn Lin 
2926e0832faSShawn Lin static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
2936e0832faSShawn Lin {
2946e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
2956e0832faSShawn Lin 
2966a114526SAnsuel Smith 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
2976e0832faSShawn Lin 	reset_control_assert(res->pci_reset);
2986e0832faSShawn Lin 	reset_control_assert(res->axi_reset);
2996e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
3006e0832faSShawn Lin 	reset_control_assert(res->por_reset);
301ee367e2cSAnsuel Smith 	reset_control_assert(res->ext_reset);
302dd58318cSAbhishek Sahu 	reset_control_assert(res->phy_reset);
303d3d4d028SAnsuel Smith 
304d3d4d028SAnsuel Smith 	writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
305d3d4d028SAnsuel Smith 
3066e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
3076e0832faSShawn Lin }
3086e0832faSShawn Lin 
3096e0832faSShawn Lin static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
3106e0832faSShawn Lin {
3116e0832faSShawn Lin 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
3126e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
3136e0832faSShawn Lin 	struct device *dev = pci->dev;
3145149901eSAnsuel Smith 	struct device_node *node = dev->of_node;
3156e0832faSShawn Lin 	u32 val;
3166e0832faSShawn Lin 	int ret;
3176e0832faSShawn Lin 
318d3d4d028SAnsuel Smith 	/* reset the PCIe interface as uboot can leave it undefined state */
319d3d4d028SAnsuel Smith 	reset_control_assert(res->pci_reset);
320d3d4d028SAnsuel Smith 	reset_control_assert(res->axi_reset);
321d3d4d028SAnsuel Smith 	reset_control_assert(res->ahb_reset);
322d3d4d028SAnsuel Smith 	reset_control_assert(res->por_reset);
323d3d4d028SAnsuel Smith 	reset_control_assert(res->ext_reset);
324d3d4d028SAnsuel Smith 	reset_control_assert(res->phy_reset);
325d3d4d028SAnsuel Smith 
326d3d4d028SAnsuel Smith 	writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
327d3d4d028SAnsuel Smith 
3286e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
3296e0832faSShawn Lin 	if (ret < 0) {
3306e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
3316e0832faSShawn Lin 		return ret;
3326e0832faSShawn Lin 	}
3336e0832faSShawn Lin 
3346e0832faSShawn Lin 	ret = reset_control_deassert(res->ahb_reset);
3356e0832faSShawn Lin 	if (ret) {
3366e0832faSShawn Lin 		dev_err(dev, "cannot deassert ahb reset\n");
3376e0832faSShawn Lin 		goto err_deassert_ahb;
3386e0832faSShawn Lin 	}
3396e0832faSShawn Lin 
340ee367e2cSAnsuel Smith 	ret = reset_control_deassert(res->ext_reset);
341ee367e2cSAnsuel Smith 	if (ret) {
342ee367e2cSAnsuel Smith 		dev_err(dev, "cannot deassert ext reset\n");
3436a114526SAnsuel Smith 		goto err_deassert_ext;
344ee367e2cSAnsuel Smith 	}
345ee367e2cSAnsuel Smith 
3466a114526SAnsuel Smith 	ret = reset_control_deassert(res->phy_reset);
3476a114526SAnsuel Smith 	if (ret) {
3486a114526SAnsuel Smith 		dev_err(dev, "cannot deassert phy reset\n");
3496a114526SAnsuel Smith 		goto err_deassert_phy;
3506a114526SAnsuel Smith 	}
3516a114526SAnsuel Smith 
3526a114526SAnsuel Smith 	ret = reset_control_deassert(res->pci_reset);
3536a114526SAnsuel Smith 	if (ret) {
3546a114526SAnsuel Smith 		dev_err(dev, "cannot deassert pci reset\n");
3556a114526SAnsuel Smith 		goto err_deassert_pci;
3566a114526SAnsuel Smith 	}
3576a114526SAnsuel Smith 
3586a114526SAnsuel Smith 	ret = reset_control_deassert(res->por_reset);
3596a114526SAnsuel Smith 	if (ret) {
3606a114526SAnsuel Smith 		dev_err(dev, "cannot deassert por reset\n");
3616a114526SAnsuel Smith 		goto err_deassert_por;
3626a114526SAnsuel Smith 	}
3636a114526SAnsuel Smith 
3646a114526SAnsuel Smith 	ret = reset_control_deassert(res->axi_reset);
3656a114526SAnsuel Smith 	if (ret) {
3666a114526SAnsuel Smith 		dev_err(dev, "cannot deassert axi reset\n");
3676a114526SAnsuel Smith 		goto err_deassert_axi;
3686a114526SAnsuel Smith 	}
3696a114526SAnsuel Smith 
3706a114526SAnsuel Smith 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
3716a114526SAnsuel Smith 	if (ret)
3726a114526SAnsuel Smith 		goto err_clks;
3736a114526SAnsuel Smith 
3746e0832faSShawn Lin 	/* enable PCIe clocks and resets */
3756e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
3766e0832faSShawn Lin 	val &= ~BIT(0);
3776e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
3786e0832faSShawn Lin 
3798df093feSAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
3808df093feSAnsuel Smith 	    of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
3815149901eSAnsuel Smith 		writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
3825149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
3835149901eSAnsuel Smith 			       PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
3845149901eSAnsuel Smith 		       pcie->parf + PCIE20_PARF_PCS_DEEMPH);
3855149901eSAnsuel Smith 		writel(PCS_SWING_TX_SWING_FULL(120) |
3865149901eSAnsuel Smith 			       PCS_SWING_TX_SWING_LOW(120),
3875149901eSAnsuel Smith 		       pcie->parf + PCIE20_PARF_PCS_SWING);
3885149901eSAnsuel Smith 		writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
3895149901eSAnsuel Smith 	}
3905149901eSAnsuel Smith 
391de3c4bf6SAnsuel Smith 	if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
392de3c4bf6SAnsuel Smith 		/* set TX termination offset */
393de3c4bf6SAnsuel Smith 		val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
394de3c4bf6SAnsuel Smith 		val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
395de3c4bf6SAnsuel Smith 		val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
396de3c4bf6SAnsuel Smith 		writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
397de3c4bf6SAnsuel Smith 	}
398de3c4bf6SAnsuel Smith 
3996e0832faSShawn Lin 	/* enable external reference clock */
4006e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
401de3c4bf6SAnsuel Smith 	val &= ~PHY_REFCLK_USE_PAD;
402de3c4bf6SAnsuel Smith 	val |= PHY_REFCLK_SSP_EN;
4036e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
4046e0832faSShawn Lin 
4056e0832faSShawn Lin 	/* wait for clock acquisition */
4066e0832faSShawn Lin 	usleep_range(1000, 1500);
4076e0832faSShawn Lin 
4086e0832faSShawn Lin 	/* Set the Max TLP size to 2K, instead of using default of 4K */
4096e0832faSShawn Lin 	writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
4106e0832faSShawn Lin 	       pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
4116e0832faSShawn Lin 	writel(CFG_BRIDGE_SB_INIT,
4126e0832faSShawn Lin 	       pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
4136e0832faSShawn Lin 
4146e0832faSShawn Lin 	return 0;
4156e0832faSShawn Lin 
4166a114526SAnsuel Smith err_clks:
4176a114526SAnsuel Smith 	reset_control_assert(res->axi_reset);
4186a114526SAnsuel Smith err_deassert_axi:
4196a114526SAnsuel Smith 	reset_control_assert(res->por_reset);
4206a114526SAnsuel Smith err_deassert_por:
4216a114526SAnsuel Smith 	reset_control_assert(res->pci_reset);
4226a114526SAnsuel Smith err_deassert_pci:
4236a114526SAnsuel Smith 	reset_control_assert(res->phy_reset);
4246a114526SAnsuel Smith err_deassert_phy:
4256a114526SAnsuel Smith 	reset_control_assert(res->ext_reset);
4266a114526SAnsuel Smith err_deassert_ext:
4276a114526SAnsuel Smith 	reset_control_assert(res->ahb_reset);
4286e0832faSShawn Lin err_deassert_ahb:
4296e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
4306e0832faSShawn Lin 
4316e0832faSShawn Lin 	return ret;
4326e0832faSShawn Lin }
4336e0832faSShawn Lin 
4346e0832faSShawn Lin static int qcom_pcie_get_resources_1_0_0(struct qcom_pcie *pcie)
4356e0832faSShawn Lin {
4366e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4376e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
4386e0832faSShawn Lin 	struct device *dev = pci->dev;
4396e0832faSShawn Lin 
4406e0832faSShawn Lin 	res->vdda = devm_regulator_get(dev, "vdda");
4416e0832faSShawn Lin 	if (IS_ERR(res->vdda))
4426e0832faSShawn Lin 		return PTR_ERR(res->vdda);
4436e0832faSShawn Lin 
4446e0832faSShawn Lin 	res->iface = devm_clk_get(dev, "iface");
4456e0832faSShawn Lin 	if (IS_ERR(res->iface))
4466e0832faSShawn Lin 		return PTR_ERR(res->iface);
4476e0832faSShawn Lin 
4486e0832faSShawn Lin 	res->aux = devm_clk_get(dev, "aux");
4496e0832faSShawn Lin 	if (IS_ERR(res->aux))
4506e0832faSShawn Lin 		return PTR_ERR(res->aux);
4516e0832faSShawn Lin 
4526e0832faSShawn Lin 	res->master_bus = devm_clk_get(dev, "master_bus");
4536e0832faSShawn Lin 	if (IS_ERR(res->master_bus))
4546e0832faSShawn Lin 		return PTR_ERR(res->master_bus);
4556e0832faSShawn Lin 
4566e0832faSShawn Lin 	res->slave_bus = devm_clk_get(dev, "slave_bus");
4576e0832faSShawn Lin 	if (IS_ERR(res->slave_bus))
4586e0832faSShawn Lin 		return PTR_ERR(res->slave_bus);
4596e0832faSShawn Lin 
4606e0832faSShawn Lin 	res->core = devm_reset_control_get_exclusive(dev, "core");
4616e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->core);
4626e0832faSShawn Lin }
4636e0832faSShawn Lin 
4646e0832faSShawn Lin static void qcom_pcie_deinit_1_0_0(struct qcom_pcie *pcie)
4656e0832faSShawn Lin {
4666e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4676e0832faSShawn Lin 
4686e0832faSShawn Lin 	reset_control_assert(res->core);
4696e0832faSShawn Lin 	clk_disable_unprepare(res->slave_bus);
4706e0832faSShawn Lin 	clk_disable_unprepare(res->master_bus);
4716e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
4726e0832faSShawn Lin 	clk_disable_unprepare(res->aux);
4736e0832faSShawn Lin 	regulator_disable(res->vdda);
4746e0832faSShawn Lin }
4756e0832faSShawn Lin 
4766e0832faSShawn Lin static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie)
4776e0832faSShawn Lin {
4786e0832faSShawn Lin 	struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
4796e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
4806e0832faSShawn Lin 	struct device *dev = pci->dev;
4816e0832faSShawn Lin 	int ret;
4826e0832faSShawn Lin 
4836e0832faSShawn Lin 	ret = reset_control_deassert(res->core);
4846e0832faSShawn Lin 	if (ret) {
4856e0832faSShawn Lin 		dev_err(dev, "cannot deassert core reset\n");
4866e0832faSShawn Lin 		return ret;
4876e0832faSShawn Lin 	}
4886e0832faSShawn Lin 
4896e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux);
4906e0832faSShawn Lin 	if (ret) {
4916e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
4926e0832faSShawn Lin 		goto err_res;
4936e0832faSShawn Lin 	}
4946e0832faSShawn Lin 
4956e0832faSShawn Lin 	ret = clk_prepare_enable(res->iface);
4966e0832faSShawn Lin 	if (ret) {
4976e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable iface clock\n");
4986e0832faSShawn Lin 		goto err_aux;
4996e0832faSShawn Lin 	}
5006e0832faSShawn Lin 
5016e0832faSShawn Lin 	ret = clk_prepare_enable(res->master_bus);
5026e0832faSShawn Lin 	if (ret) {
5036e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable master_bus clock\n");
5046e0832faSShawn Lin 		goto err_iface;
5056e0832faSShawn Lin 	}
5066e0832faSShawn Lin 
5076e0832faSShawn Lin 	ret = clk_prepare_enable(res->slave_bus);
5086e0832faSShawn Lin 	if (ret) {
5096e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable slave_bus clock\n");
5106e0832faSShawn Lin 		goto err_master;
5116e0832faSShawn Lin 	}
5126e0832faSShawn Lin 
5136e0832faSShawn Lin 	ret = regulator_enable(res->vdda);
5146e0832faSShawn Lin 	if (ret) {
5156e0832faSShawn Lin 		dev_err(dev, "cannot enable vdda regulator\n");
5166e0832faSShawn Lin 		goto err_slave;
5176e0832faSShawn Lin 	}
5186e0832faSShawn Lin 
5196e0832faSShawn Lin 	/* change DBI base address */
5206e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
5216e0832faSShawn Lin 
5226e0832faSShawn Lin 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
5236e0832faSShawn Lin 		u32 val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
5246e0832faSShawn Lin 
5256e0832faSShawn Lin 		val |= BIT(31);
5266e0832faSShawn Lin 		writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
5276e0832faSShawn Lin 	}
5286e0832faSShawn Lin 
5296e0832faSShawn Lin 	return 0;
5306e0832faSShawn Lin err_slave:
5316e0832faSShawn Lin 	clk_disable_unprepare(res->slave_bus);
5326e0832faSShawn Lin err_master:
5336e0832faSShawn Lin 	clk_disable_unprepare(res->master_bus);
5346e0832faSShawn Lin err_iface:
5356e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
5366e0832faSShawn Lin err_aux:
5376e0832faSShawn Lin 	clk_disable_unprepare(res->aux);
5386e0832faSShawn Lin err_res:
5396e0832faSShawn Lin 	reset_control_assert(res->core);
5406e0832faSShawn Lin 
5416e0832faSShawn Lin 	return ret;
5426e0832faSShawn Lin }
5436e0832faSShawn Lin 
5446e0832faSShawn Lin static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
5456e0832faSShawn Lin {
5466e0832faSShawn Lin 	u32 val;
5476e0832faSShawn Lin 
5486e0832faSShawn Lin 	/* enable link training */
5496e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_LTSSM);
5506e0832faSShawn Lin 	val |= BIT(8);
5516e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_LTSSM);
5526e0832faSShawn Lin }
5536e0832faSShawn Lin 
5546e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
5556e0832faSShawn Lin {
5566e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
5576e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
5586e0832faSShawn Lin 	struct device *dev = pci->dev;
5596e0832faSShawn Lin 	int ret;
5606e0832faSShawn Lin 
5616e0832faSShawn Lin 	res->supplies[0].supply = "vdda";
5626e0832faSShawn Lin 	res->supplies[1].supply = "vddpe-3v3";
5636e0832faSShawn Lin 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
5646e0832faSShawn Lin 				      res->supplies);
5656e0832faSShawn Lin 	if (ret)
5666e0832faSShawn Lin 		return ret;
5676e0832faSShawn Lin 
5686e0832faSShawn Lin 	res->aux_clk = devm_clk_get(dev, "aux");
5696e0832faSShawn Lin 	if (IS_ERR(res->aux_clk))
5706e0832faSShawn Lin 		return PTR_ERR(res->aux_clk);
5716e0832faSShawn Lin 
5726e0832faSShawn Lin 	res->cfg_clk = devm_clk_get(dev, "cfg");
5736e0832faSShawn Lin 	if (IS_ERR(res->cfg_clk))
5746e0832faSShawn Lin 		return PTR_ERR(res->cfg_clk);
5756e0832faSShawn Lin 
5766e0832faSShawn Lin 	res->master_clk = devm_clk_get(dev, "bus_master");
5776e0832faSShawn Lin 	if (IS_ERR(res->master_clk))
5786e0832faSShawn Lin 		return PTR_ERR(res->master_clk);
5796e0832faSShawn Lin 
5806e0832faSShawn Lin 	res->slave_clk = devm_clk_get(dev, "bus_slave");
5816e0832faSShawn Lin 	if (IS_ERR(res->slave_clk))
5826e0832faSShawn Lin 		return PTR_ERR(res->slave_clk);
5836e0832faSShawn Lin 
5846e0832faSShawn Lin 	res->pipe_clk = devm_clk_get(dev, "pipe");
5856e0832faSShawn Lin 	return PTR_ERR_OR_ZERO(res->pipe_clk);
5866e0832faSShawn Lin }
5876e0832faSShawn Lin 
5886e0832faSShawn Lin static void qcom_pcie_deinit_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 
5926e0832faSShawn Lin 	clk_disable_unprepare(res->slave_clk);
5936e0832faSShawn Lin 	clk_disable_unprepare(res->master_clk);
5946e0832faSShawn Lin 	clk_disable_unprepare(res->cfg_clk);
5956e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
5966e0832faSShawn Lin 
5976e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
5986e0832faSShawn Lin }
5996e0832faSShawn Lin 
6006e0832faSShawn Lin static void qcom_pcie_post_deinit_2_3_2(struct qcom_pcie *pcie)
6016e0832faSShawn Lin {
6026e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
6036e0832faSShawn Lin 
6046e0832faSShawn Lin 	clk_disable_unprepare(res->pipe_clk);
6056e0832faSShawn Lin }
6066e0832faSShawn Lin 
6076e0832faSShawn Lin static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
6086e0832faSShawn Lin {
6096e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
6106e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
6116e0832faSShawn Lin 	struct device *dev = pci->dev;
6126e0832faSShawn Lin 	u32 val;
6136e0832faSShawn Lin 	int ret;
6146e0832faSShawn Lin 
6156e0832faSShawn Lin 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
6166e0832faSShawn Lin 	if (ret < 0) {
6176e0832faSShawn Lin 		dev_err(dev, "cannot enable regulators\n");
6186e0832faSShawn Lin 		return ret;
6196e0832faSShawn Lin 	}
6206e0832faSShawn Lin 
6216e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux_clk);
6226e0832faSShawn Lin 	if (ret) {
6236e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
6246e0832faSShawn Lin 		goto err_aux_clk;
6256e0832faSShawn Lin 	}
6266e0832faSShawn Lin 
6276e0832faSShawn Lin 	ret = clk_prepare_enable(res->cfg_clk);
6286e0832faSShawn Lin 	if (ret) {
6296e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable cfg clock\n");
6306e0832faSShawn Lin 		goto err_cfg_clk;
6316e0832faSShawn Lin 	}
6326e0832faSShawn Lin 
6336e0832faSShawn Lin 	ret = clk_prepare_enable(res->master_clk);
6346e0832faSShawn Lin 	if (ret) {
6356e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable master clock\n");
6366e0832faSShawn Lin 		goto err_master_clk;
6376e0832faSShawn Lin 	}
6386e0832faSShawn Lin 
6396e0832faSShawn Lin 	ret = clk_prepare_enable(res->slave_clk);
6406e0832faSShawn Lin 	if (ret) {
6416e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable slave clock\n");
6426e0832faSShawn Lin 		goto err_slave_clk;
6436e0832faSShawn Lin 	}
6446e0832faSShawn Lin 
6456e0832faSShawn Lin 	/* enable PCIe clocks and resets */
6466e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
6476e0832faSShawn Lin 	val &= ~BIT(0);
6486e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
6496e0832faSShawn Lin 
6506e0832faSShawn Lin 	/* change DBI base address */
6516e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
6526e0832faSShawn Lin 
6536e0832faSShawn Lin 	/* MAC PHY_POWERDOWN MUX DISABLE  */
6546e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
6556e0832faSShawn Lin 	val &= ~BIT(29);
6566e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
6576e0832faSShawn Lin 
6586e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
6596e0832faSShawn Lin 	val |= BIT(4);
6606e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
6616e0832faSShawn Lin 
6626e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
6636e0832faSShawn Lin 	val |= BIT(31);
6646e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
6656e0832faSShawn Lin 
6666e0832faSShawn Lin 	return 0;
6676e0832faSShawn Lin 
6686e0832faSShawn Lin err_slave_clk:
6696e0832faSShawn Lin 	clk_disable_unprepare(res->master_clk);
6706e0832faSShawn Lin err_master_clk:
6716e0832faSShawn Lin 	clk_disable_unprepare(res->cfg_clk);
6726e0832faSShawn Lin err_cfg_clk:
6736e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
6746e0832faSShawn Lin 
6756e0832faSShawn Lin err_aux_clk:
6766e0832faSShawn Lin 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
6776e0832faSShawn Lin 
6786e0832faSShawn Lin 	return ret;
6796e0832faSShawn Lin }
6806e0832faSShawn Lin 
6816e0832faSShawn Lin static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
6826e0832faSShawn Lin {
6836e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
6846e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
6856e0832faSShawn Lin 	struct device *dev = pci->dev;
6866e0832faSShawn Lin 	int ret;
6876e0832faSShawn Lin 
6886e0832faSShawn Lin 	ret = clk_prepare_enable(res->pipe_clk);
6896e0832faSShawn Lin 	if (ret) {
6906e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable pipe clock\n");
6916e0832faSShawn Lin 		return ret;
6926e0832faSShawn Lin 	}
6936e0832faSShawn Lin 
6946e0832faSShawn Lin 	return 0;
6956e0832faSShawn Lin }
6966e0832faSShawn Lin 
6976e0832faSShawn Lin static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
6986e0832faSShawn Lin {
6996e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
7006e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
7016e0832faSShawn Lin 	struct device *dev = pci->dev;
70267021ae0SBjorn Andersson 	bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
7035aa18097SBjorn Andersson 	int ret;
7046e0832faSShawn Lin 
7055aa18097SBjorn Andersson 	res->clks[0].id = "aux";
7065aa18097SBjorn Andersson 	res->clks[1].id = "master_bus";
7075aa18097SBjorn Andersson 	res->clks[2].id = "slave_bus";
70867021ae0SBjorn Andersson 	res->clks[3].id = "iface";
7096e0832faSShawn Lin 
71067021ae0SBjorn Andersson 	/* qcom,pcie-ipq4019 is defined without "iface" */
71167021ae0SBjorn Andersson 	res->num_clks = is_ipq ? 3 : 4;
7126e0832faSShawn Lin 
7135aa18097SBjorn Andersson 	ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
7145aa18097SBjorn Andersson 	if (ret < 0)
7155aa18097SBjorn Andersson 		return ret;
7166e0832faSShawn Lin 
7176e0832faSShawn Lin 	res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
7186e0832faSShawn Lin 	if (IS_ERR(res->axi_m_reset))
7196e0832faSShawn Lin 		return PTR_ERR(res->axi_m_reset);
7206e0832faSShawn Lin 
7216e0832faSShawn Lin 	res->axi_s_reset = devm_reset_control_get_exclusive(dev, "axi_s");
7226e0832faSShawn Lin 	if (IS_ERR(res->axi_s_reset))
7236e0832faSShawn Lin 		return PTR_ERR(res->axi_s_reset);
7246e0832faSShawn Lin 
72567021ae0SBjorn Andersson 	if (is_ipq) {
72667021ae0SBjorn Andersson 		/*
72767021ae0SBjorn Andersson 		 * These resources relates to the PHY or are secure clocks, but
72867021ae0SBjorn Andersson 		 * are controlled here for IPQ4019
72967021ae0SBjorn Andersson 		 */
7306e0832faSShawn Lin 		res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
7316e0832faSShawn Lin 		if (IS_ERR(res->pipe_reset))
7326e0832faSShawn Lin 			return PTR_ERR(res->pipe_reset);
7336e0832faSShawn Lin 
7346e0832faSShawn Lin 		res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
7356e0832faSShawn Lin 									 "axi_m_vmid");
7366e0832faSShawn Lin 		if (IS_ERR(res->axi_m_vmid_reset))
7376e0832faSShawn Lin 			return PTR_ERR(res->axi_m_vmid_reset);
7386e0832faSShawn Lin 
7396e0832faSShawn Lin 		res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
7406e0832faSShawn Lin 									"axi_s_xpu");
7416e0832faSShawn Lin 		if (IS_ERR(res->axi_s_xpu_reset))
7426e0832faSShawn Lin 			return PTR_ERR(res->axi_s_xpu_reset);
7436e0832faSShawn Lin 
7446e0832faSShawn Lin 		res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
7456e0832faSShawn Lin 		if (IS_ERR(res->parf_reset))
7466e0832faSShawn Lin 			return PTR_ERR(res->parf_reset);
7476e0832faSShawn Lin 
7486e0832faSShawn Lin 		res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
7496e0832faSShawn Lin 		if (IS_ERR(res->phy_reset))
7506e0832faSShawn Lin 			return PTR_ERR(res->phy_reset);
75167021ae0SBjorn Andersson 	}
7526e0832faSShawn Lin 
7536e0832faSShawn Lin 	res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
7546e0832faSShawn Lin 								   "axi_m_sticky");
7556e0832faSShawn Lin 	if (IS_ERR(res->axi_m_sticky_reset))
7566e0832faSShawn Lin 		return PTR_ERR(res->axi_m_sticky_reset);
7576e0832faSShawn Lin 
7586e0832faSShawn Lin 	res->pipe_sticky_reset = devm_reset_control_get_exclusive(dev,
7596e0832faSShawn Lin 								  "pipe_sticky");
7606e0832faSShawn Lin 	if (IS_ERR(res->pipe_sticky_reset))
7616e0832faSShawn Lin 		return PTR_ERR(res->pipe_sticky_reset);
7626e0832faSShawn Lin 
7636e0832faSShawn Lin 	res->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr");
7646e0832faSShawn Lin 	if (IS_ERR(res->pwr_reset))
7656e0832faSShawn Lin 		return PTR_ERR(res->pwr_reset);
7666e0832faSShawn Lin 
7676e0832faSShawn Lin 	res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
7686e0832faSShawn Lin 	if (IS_ERR(res->ahb_reset))
7696e0832faSShawn Lin 		return PTR_ERR(res->ahb_reset);
7706e0832faSShawn Lin 
77167021ae0SBjorn Andersson 	if (is_ipq) {
7726e0832faSShawn Lin 		res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
7736e0832faSShawn Lin 		if (IS_ERR(res->phy_ahb_reset))
7746e0832faSShawn Lin 			return PTR_ERR(res->phy_ahb_reset);
77567021ae0SBjorn Andersson 	}
7766e0832faSShawn Lin 
7776e0832faSShawn Lin 	return 0;
7786e0832faSShawn Lin }
7796e0832faSShawn Lin 
7806e0832faSShawn Lin static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
7816e0832faSShawn Lin {
7826e0832faSShawn Lin 	struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
7836e0832faSShawn Lin 
7846e0832faSShawn Lin 	reset_control_assert(res->axi_m_reset);
7856e0832faSShawn Lin 	reset_control_assert(res->axi_s_reset);
7866e0832faSShawn Lin 	reset_control_assert(res->pipe_reset);
7876e0832faSShawn Lin 	reset_control_assert(res->pipe_sticky_reset);
7886e0832faSShawn Lin 	reset_control_assert(res->phy_reset);
7896e0832faSShawn Lin 	reset_control_assert(res->phy_ahb_reset);
7906e0832faSShawn Lin 	reset_control_assert(res->axi_m_sticky_reset);
7916e0832faSShawn Lin 	reset_control_assert(res->pwr_reset);
7926e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
7935aa18097SBjorn Andersson 	clk_bulk_disable_unprepare(res->num_clks, res->clks);
7946e0832faSShawn Lin }
7956e0832faSShawn Lin 
7966e0832faSShawn Lin static int qcom_pcie_init_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 	struct dw_pcie *pci = pcie->pci;
8006e0832faSShawn Lin 	struct device *dev = pci->dev;
8016e0832faSShawn Lin 	u32 val;
8026e0832faSShawn Lin 	int ret;
8036e0832faSShawn Lin 
8046e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_reset);
8056e0832faSShawn Lin 	if (ret) {
8066e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master reset\n");
8076e0832faSShawn Lin 		return ret;
8086e0832faSShawn Lin 	}
8096e0832faSShawn Lin 
8106e0832faSShawn Lin 	ret = reset_control_assert(res->axi_s_reset);
8116e0832faSShawn Lin 	if (ret) {
8126e0832faSShawn Lin 		dev_err(dev, "cannot assert axi slave reset\n");
8136e0832faSShawn Lin 		return ret;
8146e0832faSShawn Lin 	}
8156e0832faSShawn Lin 
8166e0832faSShawn Lin 	usleep_range(10000, 12000);
8176e0832faSShawn Lin 
8186e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_reset);
8196e0832faSShawn Lin 	if (ret) {
8206e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe reset\n");
8216e0832faSShawn Lin 		return ret;
8226e0832faSShawn Lin 	}
8236e0832faSShawn Lin 
8246e0832faSShawn Lin 	ret = reset_control_assert(res->pipe_sticky_reset);
8256e0832faSShawn Lin 	if (ret) {
8266e0832faSShawn Lin 		dev_err(dev, "cannot assert pipe sticky reset\n");
8276e0832faSShawn Lin 		return ret;
8286e0832faSShawn Lin 	}
8296e0832faSShawn Lin 
8306e0832faSShawn Lin 	ret = reset_control_assert(res->phy_reset);
8316e0832faSShawn Lin 	if (ret) {
8326e0832faSShawn Lin 		dev_err(dev, "cannot assert phy reset\n");
8336e0832faSShawn Lin 		return ret;
8346e0832faSShawn Lin 	}
8356e0832faSShawn Lin 
8366e0832faSShawn Lin 	ret = reset_control_assert(res->phy_ahb_reset);
8376e0832faSShawn Lin 	if (ret) {
8386e0832faSShawn Lin 		dev_err(dev, "cannot assert phy ahb reset\n");
8396e0832faSShawn Lin 		return ret;
8406e0832faSShawn Lin 	}
8416e0832faSShawn Lin 
8426e0832faSShawn Lin 	usleep_range(10000, 12000);
8436e0832faSShawn Lin 
8446e0832faSShawn Lin 	ret = reset_control_assert(res->axi_m_sticky_reset);
8456e0832faSShawn Lin 	if (ret) {
8466e0832faSShawn Lin 		dev_err(dev, "cannot assert axi master sticky reset\n");
8476e0832faSShawn Lin 		return ret;
8486e0832faSShawn Lin 	}
8496e0832faSShawn Lin 
8506e0832faSShawn Lin 	ret = reset_control_assert(res->pwr_reset);
8516e0832faSShawn Lin 	if (ret) {
8526e0832faSShawn Lin 		dev_err(dev, "cannot assert power reset\n");
8536e0832faSShawn Lin 		return ret;
8546e0832faSShawn Lin 	}
8556e0832faSShawn Lin 
8566e0832faSShawn Lin 	ret = reset_control_assert(res->ahb_reset);
8576e0832faSShawn Lin 	if (ret) {
8586e0832faSShawn Lin 		dev_err(dev, "cannot assert ahb reset\n");
8596e0832faSShawn Lin 		return ret;
8606e0832faSShawn Lin 	}
8616e0832faSShawn Lin 
8626e0832faSShawn Lin 	usleep_range(10000, 12000);
8636e0832faSShawn Lin 
8646e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_ahb_reset);
8656e0832faSShawn Lin 	if (ret) {
8666e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy ahb reset\n");
8676e0832faSShawn Lin 		return ret;
8686e0832faSShawn Lin 	}
8696e0832faSShawn Lin 
8706e0832faSShawn Lin 	ret = reset_control_deassert(res->phy_reset);
8716e0832faSShawn Lin 	if (ret) {
8726e0832faSShawn Lin 		dev_err(dev, "cannot deassert phy reset\n");
8736e0832faSShawn Lin 		goto err_rst_phy;
8746e0832faSShawn Lin 	}
8756e0832faSShawn Lin 
8766e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_reset);
8776e0832faSShawn Lin 	if (ret) {
8786e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe reset\n");
8796e0832faSShawn Lin 		goto err_rst_pipe;
8806e0832faSShawn Lin 	}
8816e0832faSShawn Lin 
8826e0832faSShawn Lin 	ret = reset_control_deassert(res->pipe_sticky_reset);
8836e0832faSShawn Lin 	if (ret) {
8846e0832faSShawn Lin 		dev_err(dev, "cannot deassert pipe sticky reset\n");
8856e0832faSShawn Lin 		goto err_rst_pipe_sticky;
8866e0832faSShawn Lin 	}
8876e0832faSShawn Lin 
8886e0832faSShawn Lin 	usleep_range(10000, 12000);
8896e0832faSShawn Lin 
8906e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_reset);
8916e0832faSShawn Lin 	if (ret) {
8926e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master reset\n");
8936e0832faSShawn Lin 		goto err_rst_axi_m;
8946e0832faSShawn Lin 	}
8956e0832faSShawn Lin 
8966e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_m_sticky_reset);
8976e0832faSShawn Lin 	if (ret) {
8986e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi master sticky reset\n");
8996e0832faSShawn Lin 		goto err_rst_axi_m_sticky;
9006e0832faSShawn Lin 	}
9016e0832faSShawn Lin 
9026e0832faSShawn Lin 	ret = reset_control_deassert(res->axi_s_reset);
9036e0832faSShawn Lin 	if (ret) {
9046e0832faSShawn Lin 		dev_err(dev, "cannot deassert axi slave reset\n");
9056e0832faSShawn Lin 		goto err_rst_axi_s;
9066e0832faSShawn Lin 	}
9076e0832faSShawn Lin 
9086e0832faSShawn Lin 	ret = reset_control_deassert(res->pwr_reset);
9096e0832faSShawn Lin 	if (ret) {
9106e0832faSShawn Lin 		dev_err(dev, "cannot deassert power reset\n");
9116e0832faSShawn Lin 		goto err_rst_pwr;
9126e0832faSShawn Lin 	}
9136e0832faSShawn Lin 
9146e0832faSShawn Lin 	ret = reset_control_deassert(res->ahb_reset);
9156e0832faSShawn Lin 	if (ret) {
9166e0832faSShawn Lin 		dev_err(dev, "cannot deassert ahb reset\n");
9176e0832faSShawn Lin 		goto err_rst_ahb;
9186e0832faSShawn Lin 	}
9196e0832faSShawn Lin 
9206e0832faSShawn Lin 	usleep_range(10000, 12000);
9216e0832faSShawn Lin 
9225aa18097SBjorn Andersson 	ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
9235aa18097SBjorn Andersson 	if (ret)
9245aa18097SBjorn Andersson 		goto err_clks;
9256e0832faSShawn Lin 
9266e0832faSShawn Lin 	/* enable PCIe clocks and resets */
9276e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
9286e0832faSShawn Lin 	val &= ~BIT(0);
9296e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
9306e0832faSShawn Lin 
9316e0832faSShawn Lin 	/* change DBI base address */
9326e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
9336e0832faSShawn Lin 
9346e0832faSShawn Lin 	/* MAC PHY_POWERDOWN MUX DISABLE  */
9356e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
9366e0832faSShawn Lin 	val &= ~BIT(29);
9376e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
9386e0832faSShawn Lin 
9396e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
9406e0832faSShawn Lin 	val |= BIT(4);
9416e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
9426e0832faSShawn Lin 
9436e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
9446e0832faSShawn Lin 	val |= BIT(31);
9456e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
9466e0832faSShawn Lin 
9476e0832faSShawn Lin 	return 0;
9486e0832faSShawn Lin 
9495aa18097SBjorn Andersson err_clks:
9506e0832faSShawn Lin 	reset_control_assert(res->ahb_reset);
9516e0832faSShawn Lin err_rst_ahb:
9526e0832faSShawn Lin 	reset_control_assert(res->pwr_reset);
9536e0832faSShawn Lin err_rst_pwr:
9546e0832faSShawn Lin 	reset_control_assert(res->axi_s_reset);
9556e0832faSShawn Lin err_rst_axi_s:
9566e0832faSShawn Lin 	reset_control_assert(res->axi_m_sticky_reset);
9576e0832faSShawn Lin err_rst_axi_m_sticky:
9586e0832faSShawn Lin 	reset_control_assert(res->axi_m_reset);
9596e0832faSShawn Lin err_rst_axi_m:
9606e0832faSShawn Lin 	reset_control_assert(res->pipe_sticky_reset);
9616e0832faSShawn Lin err_rst_pipe_sticky:
9626e0832faSShawn Lin 	reset_control_assert(res->pipe_reset);
9636e0832faSShawn Lin err_rst_pipe:
9646e0832faSShawn Lin 	reset_control_assert(res->phy_reset);
9656e0832faSShawn Lin err_rst_phy:
9666e0832faSShawn Lin 	reset_control_assert(res->phy_ahb_reset);
9676e0832faSShawn Lin 	return ret;
9686e0832faSShawn Lin }
9696e0832faSShawn Lin 
9706e0832faSShawn Lin static int qcom_pcie_get_resources_2_3_3(struct qcom_pcie *pcie)
9716e0832faSShawn Lin {
9726e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
9736e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
9746e0832faSShawn Lin 	struct device *dev = pci->dev;
9756e0832faSShawn Lin 	int i;
9766e0832faSShawn Lin 	const char *rst_names[] = { "axi_m", "axi_s", "pipe",
9776e0832faSShawn Lin 				    "axi_m_sticky", "sticky",
9786e0832faSShawn Lin 				    "ahb", "sleep", };
9796e0832faSShawn Lin 
9806e0832faSShawn Lin 	res->iface = devm_clk_get(dev, "iface");
9816e0832faSShawn Lin 	if (IS_ERR(res->iface))
9826e0832faSShawn Lin 		return PTR_ERR(res->iface);
9836e0832faSShawn Lin 
9846e0832faSShawn Lin 	res->axi_m_clk = devm_clk_get(dev, "axi_m");
9856e0832faSShawn Lin 	if (IS_ERR(res->axi_m_clk))
9866e0832faSShawn Lin 		return PTR_ERR(res->axi_m_clk);
9876e0832faSShawn Lin 
9886e0832faSShawn Lin 	res->axi_s_clk = devm_clk_get(dev, "axi_s");
9896e0832faSShawn Lin 	if (IS_ERR(res->axi_s_clk))
9906e0832faSShawn Lin 		return PTR_ERR(res->axi_s_clk);
9916e0832faSShawn Lin 
9926e0832faSShawn Lin 	res->ahb_clk = devm_clk_get(dev, "ahb");
9936e0832faSShawn Lin 	if (IS_ERR(res->ahb_clk))
9946e0832faSShawn Lin 		return PTR_ERR(res->ahb_clk);
9956e0832faSShawn Lin 
9966e0832faSShawn Lin 	res->aux_clk = devm_clk_get(dev, "aux");
9976e0832faSShawn Lin 	if (IS_ERR(res->aux_clk))
9986e0832faSShawn Lin 		return PTR_ERR(res->aux_clk);
9996e0832faSShawn Lin 
10006e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(rst_names); i++) {
10016e0832faSShawn Lin 		res->rst[i] = devm_reset_control_get(dev, rst_names[i]);
10026e0832faSShawn Lin 		if (IS_ERR(res->rst[i]))
10036e0832faSShawn Lin 			return PTR_ERR(res->rst[i]);
10046e0832faSShawn Lin 	}
10056e0832faSShawn Lin 
10066e0832faSShawn Lin 	return 0;
10076e0832faSShawn Lin }
10086e0832faSShawn Lin 
10096e0832faSShawn Lin static void qcom_pcie_deinit_2_3_3(struct qcom_pcie *pcie)
10106e0832faSShawn Lin {
10116e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
10126e0832faSShawn Lin 
10136e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
10146e0832faSShawn Lin 	clk_disable_unprepare(res->axi_m_clk);
10156e0832faSShawn Lin 	clk_disable_unprepare(res->axi_s_clk);
10166e0832faSShawn Lin 	clk_disable_unprepare(res->ahb_clk);
10176e0832faSShawn Lin 	clk_disable_unprepare(res->aux_clk);
10186e0832faSShawn Lin }
10196e0832faSShawn Lin 
10206e0832faSShawn Lin static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
10216e0832faSShawn Lin {
10226e0832faSShawn Lin 	struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
10236e0832faSShawn Lin 	struct dw_pcie *pci = pcie->pci;
10246e0832faSShawn Lin 	struct device *dev = pci->dev;
10257b87ddc0SRob Herring 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
10266e0832faSShawn Lin 	int i, ret;
10276e0832faSShawn Lin 	u32 val;
10286e0832faSShawn Lin 
10296e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
10306e0832faSShawn Lin 		ret = reset_control_assert(res->rst[i]);
10316e0832faSShawn Lin 		if (ret) {
10326e0832faSShawn Lin 			dev_err(dev, "reset #%d assert failed (%d)\n", i, ret);
10336e0832faSShawn Lin 			return ret;
10346e0832faSShawn Lin 		}
10356e0832faSShawn Lin 	}
10366e0832faSShawn Lin 
10376e0832faSShawn Lin 	usleep_range(2000, 2500);
10386e0832faSShawn Lin 
10396e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
10406e0832faSShawn Lin 		ret = reset_control_deassert(res->rst[i]);
10416e0832faSShawn Lin 		if (ret) {
10426e0832faSShawn Lin 			dev_err(dev, "reset #%d deassert failed (%d)\n", i,
10436e0832faSShawn Lin 				ret);
10446e0832faSShawn Lin 			return ret;
10456e0832faSShawn Lin 		}
10466e0832faSShawn Lin 	}
10476e0832faSShawn Lin 
10486e0832faSShawn Lin 	/*
10496e0832faSShawn Lin 	 * Don't have a way to see if the reset has completed.
10506e0832faSShawn Lin 	 * Wait for some time.
10516e0832faSShawn Lin 	 */
10526e0832faSShawn Lin 	usleep_range(2000, 2500);
10536e0832faSShawn Lin 
10546e0832faSShawn Lin 	ret = clk_prepare_enable(res->iface);
10556e0832faSShawn Lin 	if (ret) {
10566e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable core clock\n");
10576e0832faSShawn Lin 		goto err_clk_iface;
10586e0832faSShawn Lin 	}
10596e0832faSShawn Lin 
10606e0832faSShawn Lin 	ret = clk_prepare_enable(res->axi_m_clk);
10616e0832faSShawn Lin 	if (ret) {
10626e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable core clock\n");
10636e0832faSShawn Lin 		goto err_clk_axi_m;
10646e0832faSShawn Lin 	}
10656e0832faSShawn Lin 
10666e0832faSShawn Lin 	ret = clk_prepare_enable(res->axi_s_clk);
10676e0832faSShawn Lin 	if (ret) {
10686e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable axi slave clock\n");
10696e0832faSShawn Lin 		goto err_clk_axi_s;
10706e0832faSShawn Lin 	}
10716e0832faSShawn Lin 
10726e0832faSShawn Lin 	ret = clk_prepare_enable(res->ahb_clk);
10736e0832faSShawn Lin 	if (ret) {
10746e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable ahb clock\n");
10756e0832faSShawn Lin 		goto err_clk_ahb;
10766e0832faSShawn Lin 	}
10776e0832faSShawn Lin 
10786e0832faSShawn Lin 	ret = clk_prepare_enable(res->aux_clk);
10796e0832faSShawn Lin 	if (ret) {
10806e0832faSShawn Lin 		dev_err(dev, "cannot prepare/enable aux clock\n");
10816e0832faSShawn Lin 		goto err_clk_aux;
10826e0832faSShawn Lin 	}
10836e0832faSShawn Lin 
10846e0832faSShawn Lin 	writel(SLV_ADDR_SPACE_SZ,
10856e0832faSShawn Lin 		pcie->parf + PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE);
10866e0832faSShawn Lin 
10876e0832faSShawn Lin 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
10886e0832faSShawn Lin 	val &= ~BIT(0);
10896e0832faSShawn Lin 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
10906e0832faSShawn Lin 
10916e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
10926e0832faSShawn Lin 
10936e0832faSShawn Lin 	writel(MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS
10946e0832faSShawn Lin 		| SLV_ACLK_CGC_DIS | CORE_CLK_CGC_DIS |
10956e0832faSShawn Lin 		AUX_PWR_DET | L23_CLK_RMV_DIS | L1_CLK_RMV_DIS,
10966e0832faSShawn Lin 		pcie->parf + PCIE20_PARF_SYS_CTRL);
10976e0832faSShawn Lin 	writel(0, pcie->parf + PCIE20_PARF_Q2A_FLUSH);
10986e0832faSShawn Lin 
1099824001cbSAnsuel Smith 	writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
11006e0832faSShawn Lin 	writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
11017b87ddc0SRob Herring 	writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
11026e0832faSShawn Lin 
11037b87ddc0SRob Herring 	val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
1104824001cbSAnsuel Smith 	val &= ~PCI_EXP_LNKCAP_ASPMS;
11057b87ddc0SRob Herring 	writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
11066e0832faSShawn Lin 
11077b87ddc0SRob Herring 	writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
11087b87ddc0SRob Herring 		PCI_EXP_DEVCTL2);
11096e0832faSShawn Lin 
11106e0832faSShawn Lin 	return 0;
11116e0832faSShawn Lin 
11126e0832faSShawn Lin err_clk_aux:
11136e0832faSShawn Lin 	clk_disable_unprepare(res->ahb_clk);
11146e0832faSShawn Lin err_clk_ahb:
11156e0832faSShawn Lin 	clk_disable_unprepare(res->axi_s_clk);
11166e0832faSShawn Lin err_clk_axi_s:
11176e0832faSShawn Lin 	clk_disable_unprepare(res->axi_m_clk);
11186e0832faSShawn Lin err_clk_axi_m:
11196e0832faSShawn Lin 	clk_disable_unprepare(res->iface);
11206e0832faSShawn Lin err_clk_iface:
11216e0832faSShawn Lin 	/*
11226e0832faSShawn Lin 	 * Not checking for failure, will anyway return
11236e0832faSShawn Lin 	 * the original failure in 'ret'.
11246e0832faSShawn Lin 	 */
11256e0832faSShawn Lin 	for (i = 0; i < ARRAY_SIZE(res->rst); i++)
11266e0832faSShawn Lin 		reset_control_assert(res->rst[i]);
11276e0832faSShawn Lin 
11286e0832faSShawn Lin 	return ret;
11296e0832faSShawn Lin }
11306e0832faSShawn Lin 
1131ed8cc3b1SBjorn Andersson static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
1132ed8cc3b1SBjorn Andersson {
1133ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1134ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1135ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
1136ed8cc3b1SBjorn Andersson 	int ret;
1137ed8cc3b1SBjorn Andersson 
1138ed8cc3b1SBjorn Andersson 	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
1139ed8cc3b1SBjorn Andersson 	if (IS_ERR(res->pci_reset))
1140ed8cc3b1SBjorn Andersson 		return PTR_ERR(res->pci_reset);
1141ed8cc3b1SBjorn Andersson 
1142ed8cc3b1SBjorn Andersson 	res->supplies[0].supply = "vdda";
1143ed8cc3b1SBjorn Andersson 	res->supplies[1].supply = "vddpe-3v3";
1144ed8cc3b1SBjorn Andersson 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
1145ed8cc3b1SBjorn Andersson 				      res->supplies);
1146ed8cc3b1SBjorn Andersson 	if (ret)
1147ed8cc3b1SBjorn Andersson 		return ret;
1148ed8cc3b1SBjorn Andersson 
1149ed8cc3b1SBjorn Andersson 	res->clks[0].id = "aux";
1150ed8cc3b1SBjorn Andersson 	res->clks[1].id = "cfg";
1151ed8cc3b1SBjorn Andersson 	res->clks[2].id = "bus_master";
1152ed8cc3b1SBjorn Andersson 	res->clks[3].id = "bus_slave";
1153ed8cc3b1SBjorn Andersson 	res->clks[4].id = "slave_q2a";
1154ed8cc3b1SBjorn Andersson 	res->clks[5].id = "tbu";
1155ed8cc3b1SBjorn Andersson 
1156ed8cc3b1SBjorn Andersson 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
1157ed8cc3b1SBjorn Andersson 	if (ret < 0)
1158ed8cc3b1SBjorn Andersson 		return ret;
1159ed8cc3b1SBjorn Andersson 
1160ed8cc3b1SBjorn Andersson 	res->pipe_clk = devm_clk_get(dev, "pipe");
1161ed8cc3b1SBjorn Andersson 	return PTR_ERR_OR_ZERO(res->pipe_clk);
1162ed8cc3b1SBjorn Andersson }
1163ed8cc3b1SBjorn Andersson 
1164ed8cc3b1SBjorn Andersson static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
1165ed8cc3b1SBjorn Andersson {
1166ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1167ed8cc3b1SBjorn Andersson 	struct dw_pcie *pci = pcie->pci;
1168ed8cc3b1SBjorn Andersson 	struct device *dev = pci->dev;
1169ed8cc3b1SBjorn Andersson 	u32 val;
1170ed8cc3b1SBjorn Andersson 	int ret;
1171ed8cc3b1SBjorn Andersson 
1172ed8cc3b1SBjorn Andersson 	ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
1173ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1174ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot enable regulators\n");
1175ed8cc3b1SBjorn Andersson 		return ret;
1176ed8cc3b1SBjorn Andersson 	}
1177ed8cc3b1SBjorn Andersson 
1178ed8cc3b1SBjorn Andersson 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
1179ed8cc3b1SBjorn Andersson 	if (ret < 0)
1180ed8cc3b1SBjorn Andersson 		goto err_disable_regulators;
1181ed8cc3b1SBjorn Andersson 
1182ed8cc3b1SBjorn Andersson 	ret = reset_control_assert(res->pci_reset);
1183ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1184ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot deassert pci reset\n");
1185ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1186ed8cc3b1SBjorn Andersson 	}
1187ed8cc3b1SBjorn Andersson 
1188ed8cc3b1SBjorn Andersson 	usleep_range(1000, 1500);
1189ed8cc3b1SBjorn Andersson 
1190ed8cc3b1SBjorn Andersson 	ret = reset_control_deassert(res->pci_reset);
1191ed8cc3b1SBjorn Andersson 	if (ret < 0) {
1192ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot deassert pci reset\n");
1193ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1194ed8cc3b1SBjorn Andersson 	}
1195ed8cc3b1SBjorn Andersson 
1196ed8cc3b1SBjorn Andersson 	ret = clk_prepare_enable(res->pipe_clk);
1197ed8cc3b1SBjorn Andersson 	if (ret) {
1198ed8cc3b1SBjorn Andersson 		dev_err(dev, "cannot prepare/enable pipe clock\n");
1199ed8cc3b1SBjorn Andersson 		goto err_disable_clocks;
1200ed8cc3b1SBjorn Andersson 	}
1201ed8cc3b1SBjorn Andersson 
1202ed8cc3b1SBjorn Andersson 	/* configure PCIe to RC mode */
1203ed8cc3b1SBjorn Andersson 	writel(DEVICE_TYPE_RC, pcie->parf + PCIE20_PARF_DEVICE_TYPE);
1204ed8cc3b1SBjorn Andersson 
1205ed8cc3b1SBjorn Andersson 	/* enable PCIe clocks and resets */
1206ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
1207ed8cc3b1SBjorn Andersson 	val &= ~BIT(0);
1208ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
1209ed8cc3b1SBjorn Andersson 
1210ed8cc3b1SBjorn Andersson 	/* change DBI base address */
1211ed8cc3b1SBjorn Andersson 	writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
1212ed8cc3b1SBjorn Andersson 
1213ed8cc3b1SBjorn Andersson 	/* MAC PHY_POWERDOWN MUX DISABLE  */
1214ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
1215ed8cc3b1SBjorn Andersson 	val &= ~BIT(29);
1216ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
1217ed8cc3b1SBjorn Andersson 
1218ed8cc3b1SBjorn Andersson 	val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
1219ed8cc3b1SBjorn Andersson 	val |= BIT(4);
1220ed8cc3b1SBjorn Andersson 	writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
1221ed8cc3b1SBjorn Andersson 
1222ed8cc3b1SBjorn Andersson 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
1223ed8cc3b1SBjorn Andersson 		val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
1224ed8cc3b1SBjorn Andersson 		val |= BIT(31);
1225ed8cc3b1SBjorn Andersson 		writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
1226ed8cc3b1SBjorn Andersson 	}
1227ed8cc3b1SBjorn Andersson 
1228ed8cc3b1SBjorn Andersson 	return 0;
1229ed8cc3b1SBjorn Andersson err_disable_clocks:
1230ed8cc3b1SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
1231ed8cc3b1SBjorn Andersson err_disable_regulators:
1232ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1233ed8cc3b1SBjorn Andersson 
1234ed8cc3b1SBjorn Andersson 	return ret;
1235ed8cc3b1SBjorn Andersson }
1236ed8cc3b1SBjorn Andersson 
1237ed8cc3b1SBjorn Andersson static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
1238ed8cc3b1SBjorn Andersson {
1239ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1240ed8cc3b1SBjorn Andersson 
1241ed8cc3b1SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
1242ed8cc3b1SBjorn Andersson 	regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
1243ed8cc3b1SBjorn Andersson }
1244ed8cc3b1SBjorn Andersson 
1245ed8cc3b1SBjorn Andersson static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
1246ed8cc3b1SBjorn Andersson {
1247ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1248ed8cc3b1SBjorn Andersson 
1249ed8cc3b1SBjorn Andersson 	return clk_prepare_enable(res->pipe_clk);
1250ed8cc3b1SBjorn Andersson }
1251ed8cc3b1SBjorn Andersson 
1252ed8cc3b1SBjorn Andersson static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
1253ed8cc3b1SBjorn Andersson {
1254ed8cc3b1SBjorn Andersson 	struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
1255ed8cc3b1SBjorn Andersson 
1256ed8cc3b1SBjorn Andersson 	clk_disable_unprepare(res->pipe_clk);
1257ed8cc3b1SBjorn Andersson }
1258ed8cc3b1SBjorn Andersson 
12596e0832faSShawn Lin static int qcom_pcie_link_up(struct dw_pcie *pci)
12606e0832faSShawn Lin {
12617b87ddc0SRob Herring 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
12627b87ddc0SRob Herring 	u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
12636e0832faSShawn Lin 
12646e0832faSShawn Lin 	return !!(val & PCI_EXP_LNKSTA_DLLLA);
12656e0832faSShawn Lin }
12666e0832faSShawn Lin 
1267*4c939882SManivannan Sadhasivam static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
1268*4c939882SManivannan Sadhasivam {
1269*4c939882SManivannan Sadhasivam 	/* iommu map structure */
1270*4c939882SManivannan Sadhasivam 	struct {
1271*4c939882SManivannan Sadhasivam 		u32 bdf;
1272*4c939882SManivannan Sadhasivam 		u32 phandle;
1273*4c939882SManivannan Sadhasivam 		u32 smmu_sid;
1274*4c939882SManivannan Sadhasivam 		u32 smmu_sid_len;
1275*4c939882SManivannan Sadhasivam 	} *map;
1276*4c939882SManivannan Sadhasivam 	void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
1277*4c939882SManivannan Sadhasivam 	struct device *dev = pcie->pci->dev;
1278*4c939882SManivannan Sadhasivam 	u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
1279*4c939882SManivannan Sadhasivam 	int i, nr_map, size = 0;
1280*4c939882SManivannan Sadhasivam 	u32 smmu_sid_base;
1281*4c939882SManivannan Sadhasivam 
1282*4c939882SManivannan Sadhasivam 	of_get_property(dev->of_node, "iommu-map", &size);
1283*4c939882SManivannan Sadhasivam 	if (!size)
1284*4c939882SManivannan Sadhasivam 		return 0;
1285*4c939882SManivannan Sadhasivam 
1286*4c939882SManivannan Sadhasivam 	map = kzalloc(size, GFP_KERNEL);
1287*4c939882SManivannan Sadhasivam 	if (!map)
1288*4c939882SManivannan Sadhasivam 		return -ENOMEM;
1289*4c939882SManivannan Sadhasivam 
1290*4c939882SManivannan Sadhasivam 	of_property_read_u32_array(dev->of_node,
1291*4c939882SManivannan Sadhasivam 		"iommu-map", (u32 *)map, size / sizeof(u32));
1292*4c939882SManivannan Sadhasivam 
1293*4c939882SManivannan Sadhasivam 	nr_map = size / (sizeof(*map));
1294*4c939882SManivannan Sadhasivam 
1295*4c939882SManivannan Sadhasivam 	crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
1296*4c939882SManivannan Sadhasivam 
1297*4c939882SManivannan Sadhasivam 	/* Registers need to be zero out first */
1298*4c939882SManivannan Sadhasivam 	memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
1299*4c939882SManivannan Sadhasivam 
1300*4c939882SManivannan Sadhasivam 	/* Extract the SMMU SID base from the first entry of iommu-map */
1301*4c939882SManivannan Sadhasivam 	smmu_sid_base = map[0].smmu_sid;
1302*4c939882SManivannan Sadhasivam 
1303*4c939882SManivannan Sadhasivam 	/* Look for an available entry to hold the mapping */
1304*4c939882SManivannan Sadhasivam 	for (i = 0; i < nr_map; i++) {
1305*4c939882SManivannan Sadhasivam 		u16 bdf_be = cpu_to_be16(map[i].bdf);
1306*4c939882SManivannan Sadhasivam 		u32 val;
1307*4c939882SManivannan Sadhasivam 		u8 hash;
1308*4c939882SManivannan Sadhasivam 
1309*4c939882SManivannan Sadhasivam 		hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
1310*4c939882SManivannan Sadhasivam 			0);
1311*4c939882SManivannan Sadhasivam 
1312*4c939882SManivannan Sadhasivam 		val = readl(bdf_to_sid_base + hash * sizeof(u32));
1313*4c939882SManivannan Sadhasivam 
1314*4c939882SManivannan Sadhasivam 		/* If the register is already populated, look for next available entry */
1315*4c939882SManivannan Sadhasivam 		while (val) {
1316*4c939882SManivannan Sadhasivam 			u8 current_hash = hash++;
1317*4c939882SManivannan Sadhasivam 			u8 next_mask = 0xff;
1318*4c939882SManivannan Sadhasivam 
1319*4c939882SManivannan Sadhasivam 			/* If NEXT field is NULL then update it with next hash */
1320*4c939882SManivannan Sadhasivam 			if (!(val & next_mask)) {
1321*4c939882SManivannan Sadhasivam 				val |= (u32)hash;
1322*4c939882SManivannan Sadhasivam 				writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
1323*4c939882SManivannan Sadhasivam 			}
1324*4c939882SManivannan Sadhasivam 
1325*4c939882SManivannan Sadhasivam 			val = readl(bdf_to_sid_base + hash * sizeof(u32));
1326*4c939882SManivannan Sadhasivam 		}
1327*4c939882SManivannan Sadhasivam 
1328*4c939882SManivannan Sadhasivam 		/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
1329*4c939882SManivannan Sadhasivam 		val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
1330*4c939882SManivannan Sadhasivam 		writel(val, bdf_to_sid_base + hash * sizeof(u32));
1331*4c939882SManivannan Sadhasivam 	}
1332*4c939882SManivannan Sadhasivam 
1333*4c939882SManivannan Sadhasivam 	kfree(map);
1334*4c939882SManivannan Sadhasivam 
1335*4c939882SManivannan Sadhasivam 	return 0;
1336*4c939882SManivannan Sadhasivam }
1337*4c939882SManivannan Sadhasivam 
13386e0832faSShawn Lin static int qcom_pcie_host_init(struct pcie_port *pp)
13396e0832faSShawn Lin {
13406e0832faSShawn Lin 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
13416e0832faSShawn Lin 	struct qcom_pcie *pcie = to_qcom_pcie(pci);
13426e0832faSShawn Lin 	int ret;
13436e0832faSShawn Lin 
13446e0832faSShawn Lin 	qcom_ep_reset_assert(pcie);
13456e0832faSShawn Lin 
13466e0832faSShawn Lin 	ret = pcie->ops->init(pcie);
13476e0832faSShawn Lin 	if (ret)
13486e0832faSShawn Lin 		return ret;
13496e0832faSShawn Lin 
13506e0832faSShawn Lin 	ret = phy_power_on(pcie->phy);
13516e0832faSShawn Lin 	if (ret)
13526e0832faSShawn Lin 		goto err_deinit;
13536e0832faSShawn Lin 
13546e0832faSShawn Lin 	if (pcie->ops->post_init) {
13556e0832faSShawn Lin 		ret = pcie->ops->post_init(pcie);
13566e0832faSShawn Lin 		if (ret)
13576e0832faSShawn Lin 			goto err_disable_phy;
13586e0832faSShawn Lin 	}
13596e0832faSShawn Lin 
13606e0832faSShawn Lin 	qcom_ep_reset_deassert(pcie);
13616e0832faSShawn Lin 
1362*4c939882SManivannan Sadhasivam 	if (pcie->ops->config_sid) {
1363*4c939882SManivannan Sadhasivam 		ret = pcie->ops->config_sid(pcie);
1364*4c939882SManivannan Sadhasivam 		if (ret)
1365*4c939882SManivannan Sadhasivam 			goto err;
1366*4c939882SManivannan Sadhasivam 	}
1367*4c939882SManivannan Sadhasivam 
13686e0832faSShawn Lin 	return 0;
1369886a9c13SRob Herring 
1370*4c939882SManivannan Sadhasivam err:
1371*4c939882SManivannan Sadhasivam 	qcom_ep_reset_assert(pcie);
1372*4c939882SManivannan Sadhasivam 	if (pcie->ops->post_deinit)
1373*4c939882SManivannan Sadhasivam 		pcie->ops->post_deinit(pcie);
13746e0832faSShawn Lin err_disable_phy:
13756e0832faSShawn Lin 	phy_power_off(pcie->phy);
13766e0832faSShawn Lin err_deinit:
13776e0832faSShawn Lin 	pcie->ops->deinit(pcie);
13786e0832faSShawn Lin 
13796e0832faSShawn Lin 	return ret;
13806e0832faSShawn Lin }
13816e0832faSShawn Lin 
13826e0832faSShawn Lin static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
13836e0832faSShawn Lin 	.host_init = qcom_pcie_host_init,
13846e0832faSShawn Lin };
13856e0832faSShawn Lin 
13866e0832faSShawn Lin /* Qcom IP rev.: 2.1.0	Synopsys IP rev.: 4.01a */
13876e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_1_0 = {
13886e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_1_0,
13896e0832faSShawn Lin 	.init = qcom_pcie_init_2_1_0,
13906e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_1_0,
13916e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
13926e0832faSShawn Lin };
13936e0832faSShawn Lin 
13946e0832faSShawn Lin /* Qcom IP rev.: 1.0.0	Synopsys IP rev.: 4.11a */
13956e0832faSShawn Lin static const struct qcom_pcie_ops ops_1_0_0 = {
13966e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_1_0_0,
13976e0832faSShawn Lin 	.init = qcom_pcie_init_1_0_0,
13986e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_1_0_0,
13996e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
14006e0832faSShawn Lin };
14016e0832faSShawn Lin 
14026e0832faSShawn Lin /* Qcom IP rev.: 2.3.2	Synopsys IP rev.: 4.21a */
14036e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_2 = {
14046e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_2,
14056e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_2,
14066e0832faSShawn Lin 	.post_init = qcom_pcie_post_init_2_3_2,
14076e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_2,
14086e0832faSShawn Lin 	.post_deinit = qcom_pcie_post_deinit_2_3_2,
14096e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14106e0832faSShawn Lin };
14116e0832faSShawn Lin 
14126e0832faSShawn Lin /* Qcom IP rev.: 2.4.0	Synopsys IP rev.: 4.20a */
14136e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_4_0 = {
14146e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_4_0,
14156e0832faSShawn Lin 	.init = qcom_pcie_init_2_4_0,
14166e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_4_0,
14176e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14186e0832faSShawn Lin };
14196e0832faSShawn Lin 
14206e0832faSShawn Lin /* Qcom IP rev.: 2.3.3	Synopsys IP rev.: 4.30a */
14216e0832faSShawn Lin static const struct qcom_pcie_ops ops_2_3_3 = {
14226e0832faSShawn Lin 	.get_resources = qcom_pcie_get_resources_2_3_3,
14236e0832faSShawn Lin 	.init = qcom_pcie_init_2_3_3,
14246e0832faSShawn Lin 	.deinit = qcom_pcie_deinit_2_3_3,
14256e0832faSShawn Lin 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
14266e0832faSShawn Lin };
14276e0832faSShawn Lin 
1428ed8cc3b1SBjorn Andersson /* Qcom IP rev.: 2.7.0	Synopsys IP rev.: 4.30a */
1429ed8cc3b1SBjorn Andersson static const struct qcom_pcie_ops ops_2_7_0 = {
1430ed8cc3b1SBjorn Andersson 	.get_resources = qcom_pcie_get_resources_2_7_0,
1431ed8cc3b1SBjorn Andersson 	.init = qcom_pcie_init_2_7_0,
1432ed8cc3b1SBjorn Andersson 	.deinit = qcom_pcie_deinit_2_7_0,
1433ed8cc3b1SBjorn Andersson 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
1434ed8cc3b1SBjorn Andersson 	.post_init = qcom_pcie_post_init_2_7_0,
1435ed8cc3b1SBjorn Andersson 	.post_deinit = qcom_pcie_post_deinit_2_7_0,
1436ed8cc3b1SBjorn Andersson };
1437ed8cc3b1SBjorn Andersson 
1438e1dd639eSManivannan Sadhasivam /* Qcom IP rev.: 1.9.0 */
1439e1dd639eSManivannan Sadhasivam static const struct qcom_pcie_ops ops_1_9_0 = {
1440e1dd639eSManivannan Sadhasivam 	.get_resources = qcom_pcie_get_resources_2_7_0,
1441e1dd639eSManivannan Sadhasivam 	.init = qcom_pcie_init_2_7_0,
1442e1dd639eSManivannan Sadhasivam 	.deinit = qcom_pcie_deinit_2_7_0,
1443e1dd639eSManivannan Sadhasivam 	.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
1444e1dd639eSManivannan Sadhasivam 	.post_init = qcom_pcie_post_init_2_7_0,
1445e1dd639eSManivannan Sadhasivam 	.post_deinit = qcom_pcie_post_deinit_2_7_0,
1446*4c939882SManivannan Sadhasivam 	.config_sid = qcom_pcie_config_sid_sm8250,
1447e1dd639eSManivannan Sadhasivam };
1448e1dd639eSManivannan Sadhasivam 
14496e0832faSShawn Lin static const struct dw_pcie_ops dw_pcie_ops = {
14506e0832faSShawn Lin 	.link_up = qcom_pcie_link_up,
1451886a9c13SRob Herring 	.start_link = qcom_pcie_start_link,
14526e0832faSShawn Lin };
14536e0832faSShawn Lin 
14546e0832faSShawn Lin static int qcom_pcie_probe(struct platform_device *pdev)
14556e0832faSShawn Lin {
14566e0832faSShawn Lin 	struct device *dev = &pdev->dev;
14576e0832faSShawn Lin 	struct pcie_port *pp;
14586e0832faSShawn Lin 	struct dw_pcie *pci;
14596e0832faSShawn Lin 	struct qcom_pcie *pcie;
14606e0832faSShawn Lin 	int ret;
14616e0832faSShawn Lin 
14626e0832faSShawn Lin 	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
14636e0832faSShawn Lin 	if (!pcie)
14646e0832faSShawn Lin 		return -ENOMEM;
14656e0832faSShawn Lin 
14666e0832faSShawn Lin 	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
14676e0832faSShawn Lin 	if (!pci)
14686e0832faSShawn Lin 		return -ENOMEM;
14696e0832faSShawn Lin 
14706e0832faSShawn Lin 	pm_runtime_enable(dev);
14716e5da6f7SBjorn Andersson 	ret = pm_runtime_get_sync(dev);
1472cb52a402SDinghao Liu 	if (ret < 0)
1473cb52a402SDinghao Liu 		goto err_pm_runtime_put;
14746e5da6f7SBjorn Andersson 
14756e0832faSShawn Lin 	pci->dev = dev;
14766e0832faSShawn Lin 	pci->ops = &dw_pcie_ops;
14776e0832faSShawn Lin 	pp = &pci->pp;
14786e0832faSShawn Lin 
14796e0832faSShawn Lin 	pcie->pci = pci;
14806e0832faSShawn Lin 
14816e0832faSShawn Lin 	pcie->ops = of_device_get_match_data(dev);
14826e0832faSShawn Lin 
148302b485e3SBjorn Andersson 	pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
14846e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->reset)) {
14856e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->reset);
14866e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
14876e5da6f7SBjorn Andersson 	}
14886e0832faSShawn Lin 
1489936fa5cdSDejin Zheng 	pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
14906e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->parf)) {
14916e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->parf);
14926e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
14936e5da6f7SBjorn Andersson 	}
14946e0832faSShawn Lin 
1495936fa5cdSDejin Zheng 	pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
14966e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->elbi)) {
14976e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->elbi);
14986e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
14996e5da6f7SBjorn Andersson 	}
15006e0832faSShawn Lin 
15016e0832faSShawn Lin 	pcie->phy = devm_phy_optional_get(dev, "pciephy");
15026e5da6f7SBjorn Andersson 	if (IS_ERR(pcie->phy)) {
15036e5da6f7SBjorn Andersson 		ret = PTR_ERR(pcie->phy);
15046e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15056e5da6f7SBjorn Andersson 	}
15066e0832faSShawn Lin 
15076e0832faSShawn Lin 	ret = pcie->ops->get_resources(pcie);
15086e0832faSShawn Lin 	if (ret)
15096e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15106e0832faSShawn Lin 
15116e0832faSShawn Lin 	pp->ops = &qcom_pcie_dw_ops;
15126e0832faSShawn Lin 
15136e0832faSShawn Lin 	ret = phy_init(pcie->phy);
15146e0832faSShawn Lin 	if (ret) {
15156e0832faSShawn Lin 		pm_runtime_disable(&pdev->dev);
15166e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15176e0832faSShawn Lin 	}
15186e0832faSShawn Lin 
15196e0832faSShawn Lin 	platform_set_drvdata(pdev, pcie);
15206e0832faSShawn Lin 
15216e0832faSShawn Lin 	ret = dw_pcie_host_init(pp);
15226e0832faSShawn Lin 	if (ret) {
15236e0832faSShawn Lin 		dev_err(dev, "cannot initialize host\n");
15246e0832faSShawn Lin 		pm_runtime_disable(&pdev->dev);
15256e5da6f7SBjorn Andersson 		goto err_pm_runtime_put;
15266e0832faSShawn Lin 	}
15276e0832faSShawn Lin 
15286e0832faSShawn Lin 	return 0;
15296e5da6f7SBjorn Andersson 
15306e5da6f7SBjorn Andersson err_pm_runtime_put:
15316e5da6f7SBjorn Andersson 	pm_runtime_put(dev);
15326e5da6f7SBjorn Andersson 	pm_runtime_disable(dev);
15336e5da6f7SBjorn Andersson 
15346e5da6f7SBjorn Andersson 	return ret;
15356e0832faSShawn Lin }
15366e0832faSShawn Lin 
15376e0832faSShawn Lin static const struct of_device_id qcom_pcie_match[] = {
15386e0832faSShawn Lin 	{ .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
15396e0832faSShawn Lin 	{ .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
15408df093feSAnsuel Smith 	{ .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 },
15416e0832faSShawn Lin 	{ .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
15426e0832faSShawn Lin 	{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
15436e0832faSShawn Lin 	{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
15446e0832faSShawn Lin 	{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
154567021ae0SBjorn Andersson 	{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
1546ed8cc3b1SBjorn Andersson 	{ .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 },
1547e1dd639eSManivannan Sadhasivam 	{ .compatible = "qcom,pcie-sm8250", .data = &ops_1_9_0 },
15486e0832faSShawn Lin 	{ }
15496e0832faSShawn Lin };
15506e0832faSShawn Lin 
1551322f0343SMarc Gonzalez static void qcom_fixup_class(struct pci_dev *dev)
1552322f0343SMarc Gonzalez {
1553322f0343SMarc Gonzalez 	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
1554322f0343SMarc Gonzalez }
1555604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0101, qcom_fixup_class);
1556604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0104, qcom_fixup_class);
1557604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0106, qcom_fixup_class);
1558604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0107, qcom_fixup_class);
1559604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0302, qcom_fixup_class);
1560604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1000, qcom_fixup_class);
1561604f3956SBjorn Andersson DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1001, qcom_fixup_class);
1562322f0343SMarc Gonzalez 
15636e0832faSShawn Lin static struct platform_driver qcom_pcie_driver = {
15646e0832faSShawn Lin 	.probe = qcom_pcie_probe,
15656e0832faSShawn Lin 	.driver = {
15666e0832faSShawn Lin 		.name = "qcom-pcie",
15676e0832faSShawn Lin 		.suppress_bind_attrs = true,
15686e0832faSShawn Lin 		.of_match_table = qcom_pcie_match,
15696e0832faSShawn Lin 	},
15706e0832faSShawn Lin };
15716e0832faSShawn Lin builtin_platform_driver(qcom_pcie_driver);
1572