xref: /openbmc/linux/drivers/pci/controller/dwc/pcie-designware.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
16e0832faSShawn Lin // SPDX-License-Identifier: GPL-2.0
26e0832faSShawn Lin /*
36e0832faSShawn Lin  * Synopsys DesignWare PCIe host controller driver
46e0832faSShawn Lin  *
56e0832faSShawn Lin  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
67ecd4a81SAlexander A. Klimov  *		https://www.samsung.com
76e0832faSShawn Lin  *
86e0832faSShawn Lin  * Author: Jingoo Han <jg1.han@samsung.com>
96e0832faSShawn Lin  */
106e0832faSShawn Lin 
11edf408b9SSerge Semin #include <linux/align.h>
1289473aa9SSerge Semin #include <linux/bitops.h>
13ef69f852SSerge Semin #include <linux/clk.h>
146e0832faSShawn Lin #include <linux/delay.h>
15939fbcd5SSerge Semin #include <linux/dma/edma.h>
16ef69f852SSerge Semin #include <linux/gpio/consumer.h>
17ef8c5887SSerge Semin #include <linux/ioport.h>
186e0832faSShawn Lin #include <linux/of.h>
19c925cfafSRob Herring #include <linux/platform_device.h>
2089473aa9SSerge Semin #include <linux/sizes.h>
216e0832faSShawn Lin #include <linux/types.h>
226e0832faSShawn Lin 
23ed22aaaeSDilip Kota #include "../../pci.h"
246e0832faSShawn Lin #include "pcie-designware.h"
256e0832faSShawn Lin 
26ef69f852SSerge Semin static const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = {
27ef69f852SSerge Semin 	[DW_PCIE_DBI_CLK] = "dbi",
28ef69f852SSerge Semin 	[DW_PCIE_MSTR_CLK] = "mstr",
29ef69f852SSerge Semin 	[DW_PCIE_SLV_CLK] = "slv",
30ef69f852SSerge Semin };
31ef69f852SSerge Semin 
32ef69f852SSerge Semin static const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = {
33ef69f852SSerge Semin 	[DW_PCIE_PIPE_CLK] = "pipe",
34ef69f852SSerge Semin 	[DW_PCIE_CORE_CLK] = "core",
35ef69f852SSerge Semin 	[DW_PCIE_AUX_CLK] = "aux",
36ef69f852SSerge Semin 	[DW_PCIE_REF_CLK] = "ref",
37ef69f852SSerge Semin };
38ef69f852SSerge Semin 
39ef69f852SSerge Semin static const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = {
40ef69f852SSerge Semin 	[DW_PCIE_DBI_RST] = "dbi",
41ef69f852SSerge Semin 	[DW_PCIE_MSTR_RST] = "mstr",
42ef69f852SSerge Semin 	[DW_PCIE_SLV_RST] = "slv",
43ef69f852SSerge Semin };
44ef69f852SSerge Semin 
45ef69f852SSerge Semin static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = {
46ef69f852SSerge Semin 	[DW_PCIE_NON_STICKY_RST] = "non-sticky",
47ef69f852SSerge Semin 	[DW_PCIE_STICKY_RST] = "sticky",
48ef69f852SSerge Semin 	[DW_PCIE_CORE_RST] = "core",
49ef69f852SSerge Semin 	[DW_PCIE_PIPE_RST] = "pipe",
50ef69f852SSerge Semin 	[DW_PCIE_PHY_RST] = "phy",
51ef69f852SSerge Semin 	[DW_PCIE_HOT_RST] = "hot",
52ef69f852SSerge Semin 	[DW_PCIE_PWR_RST] = "pwr",
53ef69f852SSerge Semin };
54ef69f852SSerge Semin 
dw_pcie_get_clocks(struct dw_pcie * pci)55ef69f852SSerge Semin static int dw_pcie_get_clocks(struct dw_pcie *pci)
56ef69f852SSerge Semin {
57ef69f852SSerge Semin 	int i, ret;
58ef69f852SSerge Semin 
59ef69f852SSerge Semin 	for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++)
60ef69f852SSerge Semin 		pci->app_clks[i].id = dw_pcie_app_clks[i];
61ef69f852SSerge Semin 
62ef69f852SSerge Semin 	for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++)
63ef69f852SSerge Semin 		pci->core_clks[i].id = dw_pcie_core_clks[i];
64ef69f852SSerge Semin 
65ef69f852SSerge Semin 	ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS,
66ef69f852SSerge Semin 					 pci->app_clks);
67ef69f852SSerge Semin 	if (ret)
68ef69f852SSerge Semin 		return ret;
69ef69f852SSerge Semin 
70ef69f852SSerge Semin 	return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS,
71ef69f852SSerge Semin 					  pci->core_clks);
72ef69f852SSerge Semin }
73ef69f852SSerge Semin 
dw_pcie_get_resets(struct dw_pcie * pci)74ef69f852SSerge Semin static int dw_pcie_get_resets(struct dw_pcie *pci)
75ef69f852SSerge Semin {
76ef69f852SSerge Semin 	int i, ret;
77ef69f852SSerge Semin 
78ef69f852SSerge Semin 	for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++)
79ef69f852SSerge Semin 		pci->app_rsts[i].id = dw_pcie_app_rsts[i];
80ef69f852SSerge Semin 
81ef69f852SSerge Semin 	for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++)
82ef69f852SSerge Semin 		pci->core_rsts[i].id = dw_pcie_core_rsts[i];
83ef69f852SSerge Semin 
84ef69f852SSerge Semin 	ret = devm_reset_control_bulk_get_optional_shared(pci->dev,
85ef69f852SSerge Semin 							  DW_PCIE_NUM_APP_RSTS,
86ef69f852SSerge Semin 							  pci->app_rsts);
87ef69f852SSerge Semin 	if (ret)
88ef69f852SSerge Semin 		return ret;
89ef69f852SSerge Semin 
90ef69f852SSerge Semin 	ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev,
91ef69f852SSerge Semin 							     DW_PCIE_NUM_CORE_RSTS,
92ef69f852SSerge Semin 							     pci->core_rsts);
93ef69f852SSerge Semin 	if (ret)
94ef69f852SSerge Semin 		return ret;
95ef69f852SSerge Semin 
96ef69f852SSerge Semin 	pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH);
97ef69f852SSerge Semin 	if (IS_ERR(pci->pe_rst))
98ef69f852SSerge Semin 		return PTR_ERR(pci->pe_rst);
99ef69f852SSerge Semin 
100ef69f852SSerge Semin 	return 0;
101ef69f852SSerge Semin }
102ef69f852SSerge Semin 
dw_pcie_get_resources(struct dw_pcie * pci)103ef8c5887SSerge Semin int dw_pcie_get_resources(struct dw_pcie *pci)
104ef8c5887SSerge Semin {
105ef8c5887SSerge Semin 	struct platform_device *pdev = to_platform_device(pci->dev);
106ef8c5887SSerge Semin 	struct device_node *np = dev_of_node(pci->dev);
107ef8c5887SSerge Semin 	struct resource *res;
108ef69f852SSerge Semin 	int ret;
109ef8c5887SSerge Semin 
110ef8c5887SSerge Semin 	if (!pci->dbi_base) {
111ef8c5887SSerge Semin 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
112ef8c5887SSerge Semin 		pci->dbi_base = devm_pci_remap_cfg_resource(pci->dev, res);
113ef8c5887SSerge Semin 		if (IS_ERR(pci->dbi_base))
114ef8c5887SSerge Semin 			return PTR_ERR(pci->dbi_base);
115ef8c5887SSerge Semin 	}
116ef8c5887SSerge Semin 
117ef8c5887SSerge Semin 	/* DBI2 is mainly useful for the endpoint controller */
118ef8c5887SSerge Semin 	if (!pci->dbi_base2) {
119ef8c5887SSerge Semin 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
120ef8c5887SSerge Semin 		if (res) {
121ef8c5887SSerge Semin 			pci->dbi_base2 = devm_pci_remap_cfg_resource(pci->dev, res);
122ef8c5887SSerge Semin 			if (IS_ERR(pci->dbi_base2))
123ef8c5887SSerge Semin 				return PTR_ERR(pci->dbi_base2);
124ef8c5887SSerge Semin 		} else {
125ef8c5887SSerge Semin 			pci->dbi_base2 = pci->dbi_base + SZ_4K;
126ef8c5887SSerge Semin 		}
127ef8c5887SSerge Semin 	}
128ef8c5887SSerge Semin 
129ef8c5887SSerge Semin 	/* For non-unrolled iATU/eDMA platforms this range will be ignored */
130ef8c5887SSerge Semin 	if (!pci->atu_base) {
131ef8c5887SSerge Semin 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
132ef8c5887SSerge Semin 		if (res) {
133ef8c5887SSerge Semin 			pci->atu_size = resource_size(res);
134ef8c5887SSerge Semin 			pci->atu_base = devm_ioremap_resource(pci->dev, res);
135ef8c5887SSerge Semin 			if (IS_ERR(pci->atu_base))
136ef8c5887SSerge Semin 				return PTR_ERR(pci->atu_base);
137ef8c5887SSerge Semin 		} else {
138ef8c5887SSerge Semin 			pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
139ef8c5887SSerge Semin 		}
140ef8c5887SSerge Semin 	}
141ef8c5887SSerge Semin 
142ef8c5887SSerge Semin 	/* Set a default value suitable for at most 8 in and 8 out windows */
143ef8c5887SSerge Semin 	if (!pci->atu_size)
144ef8c5887SSerge Semin 		pci->atu_size = SZ_4K;
145ef8c5887SSerge Semin 
146939fbcd5SSerge Semin 	/* eDMA region can be mapped to a custom base address */
147939fbcd5SSerge Semin 	if (!pci->edma.reg_base) {
148939fbcd5SSerge Semin 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
149939fbcd5SSerge Semin 		if (res) {
150939fbcd5SSerge Semin 			pci->edma.reg_base = devm_ioremap_resource(pci->dev, res);
151939fbcd5SSerge Semin 			if (IS_ERR(pci->edma.reg_base))
152939fbcd5SSerge Semin 				return PTR_ERR(pci->edma.reg_base);
153939fbcd5SSerge Semin 		} else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) {
154939fbcd5SSerge Semin 			pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET;
155939fbcd5SSerge Semin 		}
156939fbcd5SSerge Semin 	}
157939fbcd5SSerge Semin 
158ef69f852SSerge Semin 	/* LLDD is supposed to manually switch the clocks and resets state */
159ef69f852SSerge Semin 	if (dw_pcie_cap_is(pci, REQ_RES)) {
160ef69f852SSerge Semin 		ret = dw_pcie_get_clocks(pci);
161ef69f852SSerge Semin 		if (ret)
162ef69f852SSerge Semin 			return ret;
163ef69f852SSerge Semin 
164ef69f852SSerge Semin 		ret = dw_pcie_get_resets(pci);
165ef69f852SSerge Semin 		if (ret)
166ef69f852SSerge Semin 			return ret;
167ef69f852SSerge Semin 	}
168ef69f852SSerge Semin 
169ef8c5887SSerge Semin 	if (pci->link_gen < 1)
170ef8c5887SSerge Semin 		pci->link_gen = of_pci_get_max_link_speed(np);
171ef8c5887SSerge Semin 
172ef8c5887SSerge Semin 	of_property_read_u32(np, "num-lanes", &pci->num_lanes);
173ef8c5887SSerge Semin 
174ef8c5887SSerge Semin 	if (of_property_read_bool(np, "snps,enable-cdm-check"))
175ef8c5887SSerge Semin 		dw_pcie_cap_set(pci, CDM_CHECK);
176ef8c5887SSerge Semin 
177ef8c5887SSerge Semin 	return 0;
178ef8c5887SSerge Semin }
179ef8c5887SSerge Semin 
dw_pcie_version_detect(struct dw_pcie * pci)18013e9d390SSerge Semin void dw_pcie_version_detect(struct dw_pcie *pci)
18113e9d390SSerge Semin {
18213e9d390SSerge Semin 	u32 ver;
18313e9d390SSerge Semin 
18413e9d390SSerge Semin 	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
18513e9d390SSerge Semin 	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
18613e9d390SSerge Semin 	if (!ver)
18713e9d390SSerge Semin 		return;
18813e9d390SSerge Semin 
18913e9d390SSerge Semin 	if (pci->version && pci->version != ver)
19013e9d390SSerge Semin 		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
19113e9d390SSerge Semin 			 pci->version, ver);
19213e9d390SSerge Semin 	else
19313e9d390SSerge Semin 		pci->version = ver;
19413e9d390SSerge Semin 
19513e9d390SSerge Semin 	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_TYPE);
19613e9d390SSerge Semin 
19713e9d390SSerge Semin 	if (pci->type && pci->type != ver)
19813e9d390SSerge Semin 		dev_warn(pci->dev, "Types don't match (%08x != %08x)\n",
19913e9d390SSerge Semin 			 pci->type, ver);
20013e9d390SSerge Semin 	else
20113e9d390SSerge Semin 		pci->type = ver;
20213e9d390SSerge Semin }
20313e9d390SSerge Semin 
2047a6854f6SVidya Sagar /*
2057a6854f6SVidya Sagar  * These interfaces resemble the pci_find_*capability() interfaces, but these
2067a6854f6SVidya Sagar  * are for configuring host controllers, which are bridges *to* PCI devices but
2077a6854f6SVidya Sagar  * are not PCI devices themselves.
2087a6854f6SVidya Sagar  */
__dw_pcie_find_next_cap(struct dw_pcie * pci,u8 cap_ptr,u8 cap)2097a6854f6SVidya Sagar static u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
2107a6854f6SVidya Sagar 				  u8 cap)
2117a6854f6SVidya Sagar {
2127a6854f6SVidya Sagar 	u8 cap_id, next_cap_ptr;
2137a6854f6SVidya Sagar 	u16 reg;
2147a6854f6SVidya Sagar 
2157a6854f6SVidya Sagar 	if (!cap_ptr)
2167a6854f6SVidya Sagar 		return 0;
2177a6854f6SVidya Sagar 
2187a6854f6SVidya Sagar 	reg = dw_pcie_readw_dbi(pci, cap_ptr);
2197a6854f6SVidya Sagar 	cap_id = (reg & 0x00ff);
2207a6854f6SVidya Sagar 
2217a6854f6SVidya Sagar 	if (cap_id > PCI_CAP_ID_MAX)
2227a6854f6SVidya Sagar 		return 0;
2237a6854f6SVidya Sagar 
2247a6854f6SVidya Sagar 	if (cap_id == cap)
2257a6854f6SVidya Sagar 		return cap_ptr;
2267a6854f6SVidya Sagar 
2277a6854f6SVidya Sagar 	next_cap_ptr = (reg & 0xff00) >> 8;
2287a6854f6SVidya Sagar 	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
2297a6854f6SVidya Sagar }
2307a6854f6SVidya Sagar 
dw_pcie_find_capability(struct dw_pcie * pci,u8 cap)2317a6854f6SVidya Sagar u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
2327a6854f6SVidya Sagar {
2337a6854f6SVidya Sagar 	u8 next_cap_ptr;
2347a6854f6SVidya Sagar 	u16 reg;
2357a6854f6SVidya Sagar 
2367a6854f6SVidya Sagar 	reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
2377a6854f6SVidya Sagar 	next_cap_ptr = (reg & 0x00ff);
2387a6854f6SVidya Sagar 
2397a6854f6SVidya Sagar 	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
2407a6854f6SVidya Sagar }
2417a6854f6SVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
2427a6854f6SVidya Sagar 
dw_pcie_find_next_ext_capability(struct dw_pcie * pci,u16 start,u8 cap)2435b0841faSVidya Sagar static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
2445b0841faSVidya Sagar 					    u8 cap)
2455b0841faSVidya Sagar {
2465b0841faSVidya Sagar 	u32 header;
2475b0841faSVidya Sagar 	int ttl;
2485b0841faSVidya Sagar 	int pos = PCI_CFG_SPACE_SIZE;
2495b0841faSVidya Sagar 
2505b0841faSVidya Sagar 	/* minimum 8 bytes per capability */
2515b0841faSVidya Sagar 	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
2525b0841faSVidya Sagar 
2535b0841faSVidya Sagar 	if (start)
2545b0841faSVidya Sagar 		pos = start;
2555b0841faSVidya Sagar 
2565b0841faSVidya Sagar 	header = dw_pcie_readl_dbi(pci, pos);
2575b0841faSVidya Sagar 	/*
2585b0841faSVidya Sagar 	 * If we have no capabilities, this is indicated by cap ID,
2595b0841faSVidya Sagar 	 * cap version and next pointer all being 0.
2605b0841faSVidya Sagar 	 */
2615b0841faSVidya Sagar 	if (header == 0)
2625b0841faSVidya Sagar 		return 0;
2635b0841faSVidya Sagar 
2645b0841faSVidya Sagar 	while (ttl-- > 0) {
2655b0841faSVidya Sagar 		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
2665b0841faSVidya Sagar 			return pos;
2675b0841faSVidya Sagar 
2685b0841faSVidya Sagar 		pos = PCI_EXT_CAP_NEXT(header);
2695b0841faSVidya Sagar 		if (pos < PCI_CFG_SPACE_SIZE)
2705b0841faSVidya Sagar 			break;
2715b0841faSVidya Sagar 
2725b0841faSVidya Sagar 		header = dw_pcie_readl_dbi(pci, pos);
2735b0841faSVidya Sagar 	}
2745b0841faSVidya Sagar 
2755b0841faSVidya Sagar 	return 0;
2765b0841faSVidya Sagar }
2775b0841faSVidya Sagar 
dw_pcie_find_ext_capability(struct dw_pcie * pci,u8 cap)2785b0841faSVidya Sagar u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
2795b0841faSVidya Sagar {
2805b0841faSVidya Sagar 	return dw_pcie_find_next_ext_capability(pci, 0, cap);
2815b0841faSVidya Sagar }
2825b0841faSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
2835b0841faSVidya Sagar 
dw_pcie_read(void __iomem * addr,int size,u32 * val)2846e0832faSShawn Lin int dw_pcie_read(void __iomem *addr, int size, u32 *val)
2856e0832faSShawn Lin {
2864f8bbd2fSAndrey Smirnov 	if (!IS_ALIGNED((uintptr_t)addr, size)) {
2876e0832faSShawn Lin 		*val = 0;
2886e0832faSShawn Lin 		return PCIBIOS_BAD_REGISTER_NUMBER;
2896e0832faSShawn Lin 	}
2906e0832faSShawn Lin 
2916e0832faSShawn Lin 	if (size == 4) {
2926e0832faSShawn Lin 		*val = readl(addr);
2936e0832faSShawn Lin 	} else if (size == 2) {
2946e0832faSShawn Lin 		*val = readw(addr);
2956e0832faSShawn Lin 	} else if (size == 1) {
2966e0832faSShawn Lin 		*val = readb(addr);
2976e0832faSShawn Lin 	} else {
2986e0832faSShawn Lin 		*val = 0;
2996e0832faSShawn Lin 		return PCIBIOS_BAD_REGISTER_NUMBER;
3006e0832faSShawn Lin 	}
3016e0832faSShawn Lin 
3026e0832faSShawn Lin 	return PCIBIOS_SUCCESSFUL;
3036e0832faSShawn Lin }
304ca98329dSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_read);
3056e0832faSShawn Lin 
dw_pcie_write(void __iomem * addr,int size,u32 val)3066e0832faSShawn Lin int dw_pcie_write(void __iomem *addr, int size, u32 val)
3076e0832faSShawn Lin {
3084f8bbd2fSAndrey Smirnov 	if (!IS_ALIGNED((uintptr_t)addr, size))
3096e0832faSShawn Lin 		return PCIBIOS_BAD_REGISTER_NUMBER;
3106e0832faSShawn Lin 
3116e0832faSShawn Lin 	if (size == 4)
3126e0832faSShawn Lin 		writel(val, addr);
3136e0832faSShawn Lin 	else if (size == 2)
3146e0832faSShawn Lin 		writew(val, addr);
3156e0832faSShawn Lin 	else if (size == 1)
3166e0832faSShawn Lin 		writeb(val, addr);
3176e0832faSShawn Lin 	else
3186e0832faSShawn Lin 		return PCIBIOS_BAD_REGISTER_NUMBER;
3196e0832faSShawn Lin 
3206e0832faSShawn Lin 	return PCIBIOS_SUCCESSFUL;
3216e0832faSShawn Lin }
322ca98329dSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_write);
3236e0832faSShawn Lin 
dw_pcie_read_dbi(struct dw_pcie * pci,u32 reg,size_t size)3247bc082d7SVidya Sagar u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
3256e0832faSShawn Lin {
3266e0832faSShawn Lin 	int ret;
3276e0832faSShawn Lin 	u32 val;
3286e0832faSShawn Lin 
329a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->read_dbi)
3307bc082d7SVidya Sagar 		return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
3316e0832faSShawn Lin 
3327bc082d7SVidya Sagar 	ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
3336e0832faSShawn Lin 	if (ret)
3346e0832faSShawn Lin 		dev_err(pci->dev, "Read DBI address failed\n");
3356e0832faSShawn Lin 
3366e0832faSShawn Lin 	return val;
3376e0832faSShawn Lin }
338ca98329dSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_read_dbi);
3396e0832faSShawn Lin 
dw_pcie_write_dbi(struct dw_pcie * pci,u32 reg,size_t size,u32 val)3407bc082d7SVidya Sagar void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
3416e0832faSShawn Lin {
3426e0832faSShawn Lin 	int ret;
3436e0832faSShawn Lin 
344a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->write_dbi) {
3457bc082d7SVidya Sagar 		pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
3466e0832faSShawn Lin 		return;
3476e0832faSShawn Lin 	}
3486e0832faSShawn Lin 
3497bc082d7SVidya Sagar 	ret = dw_pcie_write(pci->dbi_base + reg, size, val);
3506e0832faSShawn Lin 	if (ret)
3516e0832faSShawn Lin 		dev_err(pci->dev, "Write DBI address failed\n");
3526e0832faSShawn Lin }
353ca98329dSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
3546e0832faSShawn Lin 
dw_pcie_write_dbi2(struct dw_pcie * pci,u32 reg,size_t size,u32 val)3557bc082d7SVidya Sagar void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
356ddf567e3SKishon Vijay Abraham I {
357ddf567e3SKishon Vijay Abraham I 	int ret;
358ddf567e3SKishon Vijay Abraham I 
359a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->write_dbi2) {
3607bc082d7SVidya Sagar 		pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
361ddf567e3SKishon Vijay Abraham I 		return;
362ddf567e3SKishon Vijay Abraham I 	}
363ddf567e3SKishon Vijay Abraham I 
3647bc082d7SVidya Sagar 	ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
365ddf567e3SKishon Vijay Abraham I 	if (ret)
366ddf567e3SKishon Vijay Abraham I 		dev_err(pci->dev, "write DBI address failed\n");
367ddf567e3SKishon Vijay Abraham I }
368ddf567e3SKishon Vijay Abraham I 
dw_pcie_select_atu(struct dw_pcie * pci,u32 dir,u32 index)3695a163f59SSerge Semin static inline void __iomem *dw_pcie_select_atu(struct dw_pcie *pci, u32 dir,
3705a163f59SSerge Semin 					       u32 index)
3717bc082d7SVidya Sagar {
3727f9e982dSSerge Semin 	if (dw_pcie_cap_is(pci, IATU_UNROLL))
3735a163f59SSerge Semin 		return pci->atu_base + PCIE_ATU_UNROLL_BASE(dir, index);
3745a163f59SSerge Semin 
3755a163f59SSerge Semin 	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | index);
3765a163f59SSerge Semin 	return pci->atu_base;
3775a163f59SSerge Semin }
3785a163f59SSerge Semin 
dw_pcie_readl_atu(struct dw_pcie * pci,u32 dir,u32 index,u32 reg)3795a163f59SSerge Semin static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 dir, u32 index, u32 reg)
3805a163f59SSerge Semin {
3815a163f59SSerge Semin 	void __iomem *base;
3827bc082d7SVidya Sagar 	int ret;
3837bc082d7SVidya Sagar 	u32 val;
3847bc082d7SVidya Sagar 
3855a163f59SSerge Semin 	base = dw_pcie_select_atu(pci, dir, index);
3867bc082d7SVidya Sagar 
3875a163f59SSerge Semin 	if (pci->ops && pci->ops->read_dbi)
3885a163f59SSerge Semin 		return pci->ops->read_dbi(pci, base, reg, 4);
3895a163f59SSerge Semin 
3905a163f59SSerge Semin 	ret = dw_pcie_read(base + reg, 4, &val);
3917bc082d7SVidya Sagar 	if (ret)
3927bc082d7SVidya Sagar 		dev_err(pci->dev, "Read ATU address failed\n");
3937bc082d7SVidya Sagar 
3947bc082d7SVidya Sagar 	return val;
3957bc082d7SVidya Sagar }
3967bc082d7SVidya Sagar 
dw_pcie_writel_atu(struct dw_pcie * pci,u32 dir,u32 index,u32 reg,u32 val)3975a163f59SSerge Semin static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 dir, u32 index,
3985a163f59SSerge Semin 			       u32 reg, u32 val)
3997bc082d7SVidya Sagar {
4005a163f59SSerge Semin 	void __iomem *base;
4017bc082d7SVidya Sagar 	int ret;
4027bc082d7SVidya Sagar 
4035a163f59SSerge Semin 	base = dw_pcie_select_atu(pci, dir, index);
4045a163f59SSerge Semin 
405a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->write_dbi) {
4065a163f59SSerge Semin 		pci->ops->write_dbi(pci, base, reg, 4, val);
4077bc082d7SVidya Sagar 		return;
4087bc082d7SVidya Sagar 	}
4097bc082d7SVidya Sagar 
4105a163f59SSerge Semin 	ret = dw_pcie_write(base + reg, 4, val);
4117bc082d7SVidya Sagar 	if (ret)
4127bc082d7SVidya Sagar 		dev_err(pci->dev, "Write ATU address failed\n");
4137bc082d7SVidya Sagar }
4147bc082d7SVidya Sagar 
dw_pcie_readl_atu_ob(struct dw_pcie * pci,u32 index,u32 reg)4155a163f59SSerge Semin static inline u32 dw_pcie_readl_atu_ob(struct dw_pcie *pci, u32 index, u32 reg)
4166e0832faSShawn Lin {
4175a163f59SSerge Semin 	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_OB, index, reg);
4186e0832faSShawn Lin }
4196e0832faSShawn Lin 
dw_pcie_writel_atu_ob(struct dw_pcie * pci,u32 index,u32 reg,u32 val)4205a163f59SSerge Semin static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg,
4216e0832faSShawn Lin 					 u32 val)
4226e0832faSShawn Lin {
4235a163f59SSerge Semin 	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_OB, index, reg, val);
4246e0832faSShawn Lin }
4256e0832faSShawn Lin 
dw_pcie_enable_ecrc(u32 val)4266104033bSVidya Sagar static inline u32 dw_pcie_enable_ecrc(u32 val)
4276104033bSVidya Sagar {
4286104033bSVidya Sagar 	/*
4296104033bSVidya Sagar 	 * DesignWare core version 4.90A has a design issue where the 'TD'
4306104033bSVidya Sagar 	 * bit in the Control register-1 of the ATU outbound region acts
4316104033bSVidya Sagar 	 * like an override for the ECRC setting, i.e., the presence of TLP
4326104033bSVidya Sagar 	 * Digest (ECRC) in the outgoing TLPs is solely determined by this
4336104033bSVidya Sagar 	 * bit. This is contrary to the PCIe spec which says that the
4346104033bSVidya Sagar 	 * enablement of the ECRC is solely determined by the AER
4356104033bSVidya Sagar 	 * registers.
4366104033bSVidya Sagar 	 *
4376104033bSVidya Sagar 	 * Because of this, even when the ECRC is enabled through AER
4386104033bSVidya Sagar 	 * registers, the transactions going through ATU won't have TLP
4396104033bSVidya Sagar 	 * Digest as there is no way the PCI core AER code could program
4406104033bSVidya Sagar 	 * the TD bit which is specific to the DesignWare core.
4416104033bSVidya Sagar 	 *
4426104033bSVidya Sagar 	 * The best way to handle this scenario is to program the TD bit
4436104033bSVidya Sagar 	 * always. It affects only the traffic from root port to downstream
4446104033bSVidya Sagar 	 * devices.
4456104033bSVidya Sagar 	 *
4466104033bSVidya Sagar 	 * At this point,
4476104033bSVidya Sagar 	 * When ECRC is enabled in AER registers, everything works normally
4486104033bSVidya Sagar 	 * When ECRC is NOT enabled in AER registers, then,
4496104033bSVidya Sagar 	 * on Root Port:- TLP Digest (DWord size) gets appended to each packet
4506104033bSVidya Sagar 	 *                even through it is not required. Since downstream
4516104033bSVidya Sagar 	 *                TLPs are mostly for configuration accesses and BAR
4526104033bSVidya Sagar 	 *                accesses, they are not in critical path and won't
4536104033bSVidya Sagar 	 *                have much negative effect on the performance.
4546104033bSVidya Sagar 	 * on End Point:- TLP Digest is received for some/all the packets coming
4556104033bSVidya Sagar 	 *                from the root port. TLP Digest is ignored because,
4566104033bSVidya Sagar 	 *                as per the PCIe Spec r5.0 v1.0 section 2.2.3
4576104033bSVidya Sagar 	 *                "TLP Digest Rules", when an endpoint receives TLP
4586104033bSVidya Sagar 	 *                Digest when its ECRC check functionality is disabled
4596104033bSVidya Sagar 	 *                in AER registers, received TLP Digest is just ignored.
4606104033bSVidya Sagar 	 * Since there is no issue or error reported either side, best way to
4616104033bSVidya Sagar 	 * handle the scenario is to program TD bit by default.
4626104033bSVidya Sagar 	 */
4636104033bSVidya Sagar 
4646104033bSVidya Sagar 	return val | PCIE_ATU_TD;
4656104033bSVidya Sagar }
4666104033bSVidya Sagar 
__dw_pcie_prog_outbound_atu(struct dw_pcie * pci,u8 func_no,int index,int type,u64 cpu_addr,u64 pci_addr,u64 size)467edf408b9SSerge Semin static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
46824ede430SXiaowei Bao 				       int index, int type, u64 cpu_addr,
46974081de4SVidya Sagar 				       u64 pci_addr, u64 size)
4706e0832faSShawn Lin {
4716e0832faSShawn Lin 	u32 retries, val;
472777e7c3aSSerge Semin 	u64 limit_addr;
4736e0832faSShawn Lin 
474a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->cpu_addr_fixup)
4756e0832faSShawn Lin 		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
4766e0832faSShawn Lin 
477777e7c3aSSerge Semin 	limit_addr = cpu_addr + size - 1;
478777e7c3aSSerge Semin 
479edf408b9SSerge Semin 	if ((limit_addr & ~pci->region_limit) != (cpu_addr & ~pci->region_limit) ||
480edf408b9SSerge Semin 	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
481edf408b9SSerge Semin 	    !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
482edf408b9SSerge Semin 		return -EINVAL;
483edf408b9SSerge Semin 	}
484edf408b9SSerge Semin 
4855a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
4866e0832faSShawn Lin 			      lower_32_bits(cpu_addr));
4875a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
4886e0832faSShawn Lin 			      upper_32_bits(cpu_addr));
4895a163f59SSerge Semin 
4905a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LIMIT,
491777e7c3aSSerge Semin 			      lower_32_bits(limit_addr));
4920b0a780dSSerge Semin 	if (dw_pcie_ver_is_ge(pci, 460A))
4935a163f59SSerge Semin 		dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_LIMIT,
494777e7c3aSSerge Semin 				      upper_32_bits(limit_addr));
4955a163f59SSerge Semin 
4965a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_TARGET,
4976e0832faSShawn Lin 			      lower_32_bits(pci_addr));
4985a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_TARGET,
4996e0832faSShawn Lin 			      upper_32_bits(pci_addr));
5005a163f59SSerge Semin 
5016104033bSVidya Sagar 	val = type | PCIE_ATU_FUNC_NUM(func_no);
502777e7c3aSSerge Semin 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
5030b0a780dSSerge Semin 	    dw_pcie_ver_is_ge(pci, 460A))
504777e7c3aSSerge Semin 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
5050b0a780dSSerge Semin 	if (dw_pcie_ver_is(pci, 490A))
5066104033bSVidya Sagar 		val = dw_pcie_enable_ecrc(val);
5075a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val);
5085a163f59SSerge Semin 
5095a163f59SSerge Semin 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
5106e0832faSShawn Lin 
5116e0832faSShawn Lin 	/*
5126e0832faSShawn Lin 	 * Make sure ATU enable takes effect before any subsequent config
5136e0832faSShawn Lin 	 * and I/O accesses.
5146e0832faSShawn Lin 	 */
5156e0832faSShawn Lin 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
5165a163f59SSerge Semin 		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
5176e0832faSShawn Lin 		if (val & PCIE_ATU_ENABLE)
518edf408b9SSerge Semin 			return 0;
5196e0832faSShawn Lin 
5209024143eSJisheng Zhang 		mdelay(LINK_WAIT_IATU);
5216e0832faSShawn Lin 	}
5225a163f59SSerge Semin 
5236e0832faSShawn Lin 	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
524edf408b9SSerge Semin 
525edf408b9SSerge Semin 	return -ETIMEDOUT;
5266e0832faSShawn Lin }
5276e0832faSShawn Lin 
dw_pcie_prog_outbound_atu(struct dw_pcie * pci,int index,int type,u64 cpu_addr,u64 pci_addr,u64 size)528edf408b9SSerge Semin int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
52974081de4SVidya Sagar 			      u64 cpu_addr, u64 pci_addr, u64 size)
53024ede430SXiaowei Bao {
531edf408b9SSerge Semin 	return __dw_pcie_prog_outbound_atu(pci, 0, index, type,
53224ede430SXiaowei Bao 					   cpu_addr, pci_addr, size);
53324ede430SXiaowei Bao }
53424ede430SXiaowei Bao 
dw_pcie_prog_ep_outbound_atu(struct dw_pcie * pci,u8 func_no,int index,int type,u64 cpu_addr,u64 pci_addr,u64 size)535edf408b9SSerge Semin int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
53624ede430SXiaowei Bao 				 int type, u64 cpu_addr, u64 pci_addr,
5373856e1c5SShradha Todi 				 u64 size)
53824ede430SXiaowei Bao {
539edf408b9SSerge Semin 	return __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
54024ede430SXiaowei Bao 					   cpu_addr, pci_addr, size);
54124ede430SXiaowei Bao }
54224ede430SXiaowei Bao 
dw_pcie_readl_atu_ib(struct dw_pcie * pci,u32 index,u32 reg)5435a163f59SSerge Semin static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg)
5446e0832faSShawn Lin {
5455a163f59SSerge Semin 	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg);
5466e0832faSShawn Lin }
5476e0832faSShawn Lin 
dw_pcie_writel_atu_ib(struct dw_pcie * pci,u32 index,u32 reg,u32 val)5485a163f59SSerge Semin static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
5496e0832faSShawn Lin 					 u32 val)
5506e0832faSShawn Lin {
5515a163f59SSerge Semin 	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
5526e0832faSShawn Lin }
5536e0832faSShawn Lin 
dw_pcie_prog_inbound_atu(struct dw_pcie * pci,int index,int type,u64 cpu_addr,u64 pci_addr,u64 size)5548522e17dSSerge Semin int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
5558522e17dSSerge Semin 			     u64 cpu_addr, u64 pci_addr, u64 size)
5568522e17dSSerge Semin {
5578522e17dSSerge Semin 	u64 limit_addr = pci_addr + size - 1;
5588522e17dSSerge Semin 	u32 retries, val;
5598522e17dSSerge Semin 
5608522e17dSSerge Semin 	if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
5618522e17dSSerge Semin 	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
5628522e17dSSerge Semin 	    !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
5638522e17dSSerge Semin 		return -EINVAL;
5648522e17dSSerge Semin 	}
5658522e17dSSerge Semin 
5668522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
5678522e17dSSerge Semin 			      lower_32_bits(pci_addr));
5688522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE,
5698522e17dSSerge Semin 			      upper_32_bits(pci_addr));
5708522e17dSSerge Semin 
5718522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT,
5728522e17dSSerge Semin 			      lower_32_bits(limit_addr));
5738522e17dSSerge Semin 	if (dw_pcie_ver_is_ge(pci, 460A))
5748522e17dSSerge Semin 		dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT,
5758522e17dSSerge Semin 				      upper_32_bits(limit_addr));
5768522e17dSSerge Semin 
5778522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
5788522e17dSSerge Semin 			      lower_32_bits(cpu_addr));
5798522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
5808522e17dSSerge Semin 			      upper_32_bits(cpu_addr));
5818522e17dSSerge Semin 
5828522e17dSSerge Semin 	val = type;
5838522e17dSSerge Semin 	if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) &&
5848522e17dSSerge Semin 	    dw_pcie_ver_is_ge(pci, 460A))
5858522e17dSSerge Semin 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
5868522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val);
5878522e17dSSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
5888522e17dSSerge Semin 
5898522e17dSSerge Semin 	/*
5908522e17dSSerge Semin 	 * Make sure ATU enable takes effect before any subsequent config
5918522e17dSSerge Semin 	 * and I/O accesses.
5928522e17dSSerge Semin 	 */
5938522e17dSSerge Semin 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
5948522e17dSSerge Semin 		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
5958522e17dSSerge Semin 		if (val & PCIE_ATU_ENABLE)
5968522e17dSSerge Semin 			return 0;
5978522e17dSSerge Semin 
5988522e17dSSerge Semin 		mdelay(LINK_WAIT_IATU);
5998522e17dSSerge Semin 	}
6008522e17dSSerge Semin 
6018522e17dSSerge Semin 	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
6028522e17dSSerge Semin 
6038522e17dSSerge Semin 	return -ETIMEDOUT;
6048522e17dSSerge Semin }
6058522e17dSSerge Semin 
dw_pcie_prog_ep_inbound_atu(struct dw_pcie * pci,u8 func_no,int index,int type,u64 cpu_addr,u8 bar)6068522e17dSSerge Semin int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
6074859db9bSSerge Semin 				int type, u64 cpu_addr, u8 bar)
6086e0832faSShawn Lin {
6096e0832faSShawn Lin 	u32 retries, val;
6106e0832faSShawn Lin 
611edf408b9SSerge Semin 	if (!IS_ALIGNED(cpu_addr, pci->region_align))
612edf408b9SSerge Semin 		return -EINVAL;
613edf408b9SSerge Semin 
6145a163f59SSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
6155a163f59SSerge Semin 			      lower_32_bits(cpu_addr));
6165a163f59SSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
6175a163f59SSerge Semin 			      upper_32_bits(cpu_addr));
6186e0832faSShawn Lin 
6195a163f59SSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
62024ede430SXiaowei Bao 			      PCIE_ATU_FUNC_NUM(func_no));
6215a163f59SSerge Semin 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
6225a163f59SSerge Semin 			      PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
62324ede430SXiaowei Bao 			      PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
6246e0832faSShawn Lin 
6256e0832faSShawn Lin 	/*
6266e0832faSShawn Lin 	 * Make sure ATU enable takes effect before any subsequent config
6276e0832faSShawn Lin 	 * and I/O accesses.
6286e0832faSShawn Lin 	 */
6296e0832faSShawn Lin 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
6305a163f59SSerge Semin 		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
6316e0832faSShawn Lin 		if (val & PCIE_ATU_ENABLE)
6326e0832faSShawn Lin 			return 0;
6336e0832faSShawn Lin 
6349024143eSJisheng Zhang 		mdelay(LINK_WAIT_IATU);
6356e0832faSShawn Lin 	}
6365a163f59SSerge Semin 
6376e0832faSShawn Lin 	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
6386e0832faSShawn Lin 
6395a163f59SSerge Semin 	return -ETIMEDOUT;
6406e0832faSShawn Lin }
6416e0832faSShawn Lin 
dw_pcie_disable_atu(struct dw_pcie * pci,u32 dir,int index)64238fe2723SSerge Semin void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
6436e0832faSShawn Lin {
6445a163f59SSerge Semin 	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
645d1cf738fSSerge Semin }
6466e0832faSShawn Lin 
dw_pcie_wait_for_link(struct dw_pcie * pci)647da56a1bfSAjay Agarwal int dw_pcie_wait_for_link(struct dw_pcie *pci)
648da56a1bfSAjay Agarwal {
649c5097b98SJohan Hovold 	u32 offset, val;
6506e0832faSShawn Lin 	int retries;
6516e0832faSShawn Lin 
6526e0832faSShawn Lin 	/* Check if the link is up or not */
6536e0832faSShawn Lin 	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
65414c4ad12SSerge Semin 		if (dw_pcie_link_up(pci))
65514c4ad12SSerge Semin 			break;
65614c4ad12SSerge Semin 
6576e0832faSShawn Lin 		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
6586e0832faSShawn Lin 	}
6596e0832faSShawn Lin 
66014c4ad12SSerge Semin 	if (retries >= LINK_WAIT_MAX_RETRIES) {
6618405d8f0SVidya Sagar 		dev_info(pci->dev, "Phy link never came up\n");
6626e0832faSShawn Lin 		return -ETIMEDOUT;
6636e0832faSShawn Lin 	}
66414c4ad12SSerge Semin 
665c5097b98SJohan Hovold 	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
666c5097b98SJohan Hovold 	val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
667c5097b98SJohan Hovold 
668c5097b98SJohan Hovold 	dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
669c5097b98SJohan Hovold 		 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
670c5097b98SJohan Hovold 		 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
67114c4ad12SSerge Semin 
67214c4ad12SSerge Semin 	return 0;
67314c4ad12SSerge Semin }
674feee519aSVidya Sagar EXPORT_SYMBOL_GPL(dw_pcie_wait_for_link);
6756e0832faSShawn Lin 
dw_pcie_link_up(struct dw_pcie * pci)6766e0832faSShawn Lin int dw_pcie_link_up(struct dw_pcie *pci)
6776e0832faSShawn Lin {
6786e0832faSShawn Lin 	u32 val;
6796e0832faSShawn Lin 
680a2f882d8SJisheng Zhang 	if (pci->ops && pci->ops->link_up)
6816e0832faSShawn Lin 		return pci->ops->link_up(pci);
6826e0832faSShawn Lin 
6833869e9a3SSerge Semin 	val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1);
68460ef4b07SAndrey Smirnov 	return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
68560ef4b07SAndrey Smirnov 		(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
6866e0832faSShawn Lin }
6873a7fb867SLuca Ceresoli EXPORT_SYMBOL_GPL(dw_pcie_link_up);
6886e0832faSShawn Lin 
dw_pcie_upconfig_setup(struct dw_pcie * pci)689ed22aaaeSDilip Kota void dw_pcie_upconfig_setup(struct dw_pcie *pci)
690ed22aaaeSDilip Kota {
691ed22aaaeSDilip Kota 	u32 val;
692ed22aaaeSDilip Kota 
693ed22aaaeSDilip Kota 	val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL);
694ed22aaaeSDilip Kota 	val |= PORT_MLTI_UPCFG_SUPPORT;
695ed22aaaeSDilip Kota 	dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val);
696ed22aaaeSDilip Kota }
697ed22aaaeSDilip Kota EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
698ed22aaaeSDilip Kota 
dw_pcie_link_set_max_speed(struct dw_pcie * pci,u32 link_gen)69939bc5006SRob Herring static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
700ed22aaaeSDilip Kota {
70139bc5006SRob Herring 	u32 cap, ctrl2, link_speed;
702ed22aaaeSDilip Kota 	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
703ed22aaaeSDilip Kota 
70439bc5006SRob Herring 	cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
70539bc5006SRob Herring 	ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
70639bc5006SRob Herring 	ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
707ed22aaaeSDilip Kota 
708ed22aaaeSDilip Kota 	switch (pcie_link_speed[link_gen]) {
709ed22aaaeSDilip Kota 	case PCIE_SPEED_2_5GT:
71039bc5006SRob Herring 		link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
711ed22aaaeSDilip Kota 		break;
712ed22aaaeSDilip Kota 	case PCIE_SPEED_5_0GT:
71339bc5006SRob Herring 		link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
714ed22aaaeSDilip Kota 		break;
715ed22aaaeSDilip Kota 	case PCIE_SPEED_8_0GT:
71639bc5006SRob Herring 		link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
717ed22aaaeSDilip Kota 		break;
718ed22aaaeSDilip Kota 	case PCIE_SPEED_16_0GT:
71939bc5006SRob Herring 		link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
720ed22aaaeSDilip Kota 		break;
721ed22aaaeSDilip Kota 	default:
722ed22aaaeSDilip Kota 		/* Use hardware capability */
72339bc5006SRob Herring 		link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
72439bc5006SRob Herring 		ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
725ed22aaaeSDilip Kota 		break;
726ed22aaaeSDilip Kota 	}
727ed22aaaeSDilip Kota 
72839bc5006SRob Herring 	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
72939bc5006SRob Herring 
73039bc5006SRob Herring 	cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
73139bc5006SRob Herring 	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
73239bc5006SRob Herring 
733ed22aaaeSDilip Kota }
734ed22aaaeSDilip Kota 
dw_pcie_link_set_max_link_width(struct dw_pcie * pci,u32 num_lanes)735e8bde5ebSYoshihiro Shimoda static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
736e8bde5ebSYoshihiro Shimoda {
737*f3dda1cfSYoshihiro Shimoda 	u32 lnkcap, lwsc, plc;
738*f3dda1cfSYoshihiro Shimoda 	u8 cap;
739e8bde5ebSYoshihiro Shimoda 
740e8bde5ebSYoshihiro Shimoda 	if (!num_lanes)
741e8bde5ebSYoshihiro Shimoda 		return;
742e8bde5ebSYoshihiro Shimoda 
743e8bde5ebSYoshihiro Shimoda 	/* Set the number of lanes */
744e8bde5ebSYoshihiro Shimoda 	plc = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
745e8bde5ebSYoshihiro Shimoda 	plc &= ~PORT_LINK_FAST_LINK_MODE;
746e8bde5ebSYoshihiro Shimoda 	plc &= ~PORT_LINK_MODE_MASK;
747e8bde5ebSYoshihiro Shimoda 
748e8bde5ebSYoshihiro Shimoda 	/* Set link width speed control register */
749e8bde5ebSYoshihiro Shimoda 	lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
750e8bde5ebSYoshihiro Shimoda 	lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
751e8bde5ebSYoshihiro Shimoda 	switch (num_lanes) {
752e8bde5ebSYoshihiro Shimoda 	case 1:
753e8bde5ebSYoshihiro Shimoda 		plc |= PORT_LINK_MODE_1_LANES;
754e8bde5ebSYoshihiro Shimoda 		lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
755e8bde5ebSYoshihiro Shimoda 		break;
756e8bde5ebSYoshihiro Shimoda 	case 2:
757e8bde5ebSYoshihiro Shimoda 		plc |= PORT_LINK_MODE_2_LANES;
758e8bde5ebSYoshihiro Shimoda 		lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES;
759e8bde5ebSYoshihiro Shimoda 		break;
760e8bde5ebSYoshihiro Shimoda 	case 4:
761e8bde5ebSYoshihiro Shimoda 		plc |= PORT_LINK_MODE_4_LANES;
762e8bde5ebSYoshihiro Shimoda 		lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES;
763e8bde5ebSYoshihiro Shimoda 		break;
764e8bde5ebSYoshihiro Shimoda 	case 8:
765e8bde5ebSYoshihiro Shimoda 		plc |= PORT_LINK_MODE_8_LANES;
766e8bde5ebSYoshihiro Shimoda 		lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES;
767e8bde5ebSYoshihiro Shimoda 		break;
768e8bde5ebSYoshihiro Shimoda 	default:
769e8bde5ebSYoshihiro Shimoda 		dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
770e8bde5ebSYoshihiro Shimoda 		return;
771e8bde5ebSYoshihiro Shimoda 	}
772e8bde5ebSYoshihiro Shimoda 	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
773e8bde5ebSYoshihiro Shimoda 	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
774*f3dda1cfSYoshihiro Shimoda 
775*f3dda1cfSYoshihiro Shimoda 	cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
776*f3dda1cfSYoshihiro Shimoda 	lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
777*f3dda1cfSYoshihiro Shimoda 	lnkcap &= ~PCI_EXP_LNKCAP_MLW;
778*f3dda1cfSYoshihiro Shimoda 	lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
779*f3dda1cfSYoshihiro Shimoda 	dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
780e8bde5ebSYoshihiro Shimoda }
781e8bde5ebSYoshihiro Shimoda 
dw_pcie_iatu_detect(struct dw_pcie * pci)7829f67ecddSSerge Semin void dw_pcie_iatu_detect(struct dw_pcie *pci)
783281f1f99SRob Herring {
7845a163f59SSerge Semin 	int max_region, ob, ib;
78589473aa9SSerge Semin 	u32 val, min, dir;
78689473aa9SSerge Semin 	u64 max;
787281f1f99SRob Herring 
7889f67ecddSSerge Semin 	val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
7899f67ecddSSerge Semin 	if (val == 0xFFFFFFFF) {
7909f67ecddSSerge Semin 		dw_pcie_cap_set(pci, IATU_UNROLL);
7919f67ecddSSerge Semin 
7925a163f59SSerge Semin 		max_region = min((int)pci->atu_size / 512, 256);
7935a163f59SSerge Semin 	} else {
7949f67ecddSSerge Semin 		pci->atu_base = pci->dbi_base + PCIE_ATU_VIEWPORT_BASE;
7959f67ecddSSerge Semin 		pci->atu_size = PCIE_ATU_VIEWPORT_SIZE;
7969f67ecddSSerge Semin 
797281f1f99SRob Herring 		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
798281f1f99SRob Herring 		max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
7995a163f59SSerge Semin 	}
800281f1f99SRob Herring 
8015a163f59SSerge Semin 	for (ob = 0; ob < max_region; ob++) {
8025a163f59SSerge Semin 		dw_pcie_writel_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET, 0x11110000);
8035a163f59SSerge Semin 		val = dw_pcie_readl_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET);
8045a163f59SSerge Semin 		if (val != 0x11110000)
805281f1f99SRob Herring 			break;
806281f1f99SRob Herring 	}
807281f1f99SRob Herring 
8085a163f59SSerge Semin 	for (ib = 0; ib < max_region; ib++) {
8095a163f59SSerge Semin 		dw_pcie_writel_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET, 0x11110000);
8105a163f59SSerge Semin 		val = dw_pcie_readl_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET);
8115a163f59SSerge Semin 		if (val != 0x11110000)
812281f1f99SRob Herring 			break;
813281f1f99SRob Herring 	}
814281f1f99SRob Herring 
81589473aa9SSerge Semin 	if (ob) {
81689473aa9SSerge Semin 		dir = PCIE_ATU_REGION_DIR_OB;
81789473aa9SSerge Semin 	} else if (ib) {
81889473aa9SSerge Semin 		dir = PCIE_ATU_REGION_DIR_IB;
81989473aa9SSerge Semin 	} else {
82089473aa9SSerge Semin 		dev_err(pci->dev, "No iATU regions found\n");
82189473aa9SSerge Semin 		return;
82289473aa9SSerge Semin 	}
82389473aa9SSerge Semin 
82489473aa9SSerge Semin 	dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_LIMIT, 0x0);
82589473aa9SSerge Semin 	min = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_LIMIT);
82689473aa9SSerge Semin 
82789473aa9SSerge Semin 	if (dw_pcie_ver_is_ge(pci, 460A)) {
82889473aa9SSerge Semin 		dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT, 0xFFFFFFFF);
82989473aa9SSerge Semin 		max = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT);
83089473aa9SSerge Semin 	} else {
83189473aa9SSerge Semin 		max = 0;
83289473aa9SSerge Semin 	}
83389473aa9SSerge Semin 
834281f1f99SRob Herring 	pci->num_ob_windows = ob;
83589473aa9SSerge Semin 	pci->num_ib_windows = ib;
83689473aa9SSerge Semin 	pci->region_align = 1 << fls(min);
83789473aa9SSerge Semin 	pci->region_limit = (max << 32) | (SZ_4G - 1);
838281f1f99SRob Herring 
8399f67ecddSSerge Semin 	dev_info(pci->dev, "iATU: unroll %s, %u ob, %u ib, align %uK, limit %lluG\n",
8409f67ecddSSerge Semin 		 dw_pcie_cap_is(pci, IATU_UNROLL) ? "T" : "F",
84189473aa9SSerge Semin 		 pci->num_ob_windows, pci->num_ib_windows,
84289473aa9SSerge Semin 		 pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
8438bcca265SHou Zhiqiang }
8448bcca265SHou Zhiqiang 
dw_pcie_readl_dma(struct dw_pcie * pci,u32 reg)845939fbcd5SSerge Semin static u32 dw_pcie_readl_dma(struct dw_pcie *pci, u32 reg)
846939fbcd5SSerge Semin {
847939fbcd5SSerge Semin 	u32 val = 0;
848939fbcd5SSerge Semin 	int ret;
849939fbcd5SSerge Semin 
850939fbcd5SSerge Semin 	if (pci->ops && pci->ops->read_dbi)
851939fbcd5SSerge Semin 		return pci->ops->read_dbi(pci, pci->edma.reg_base, reg, 4);
852939fbcd5SSerge Semin 
853939fbcd5SSerge Semin 	ret = dw_pcie_read(pci->edma.reg_base + reg, 4, &val);
854939fbcd5SSerge Semin 	if (ret)
855939fbcd5SSerge Semin 		dev_err(pci->dev, "Read DMA address failed\n");
856939fbcd5SSerge Semin 
857939fbcd5SSerge Semin 	return val;
858939fbcd5SSerge Semin }
859939fbcd5SSerge Semin 
dw_pcie_edma_irq_vector(struct device * dev,unsigned int nr)860939fbcd5SSerge Semin static int dw_pcie_edma_irq_vector(struct device *dev, unsigned int nr)
861939fbcd5SSerge Semin {
862939fbcd5SSerge Semin 	struct platform_device *pdev = to_platform_device(dev);
863939fbcd5SSerge Semin 	char name[6];
864939fbcd5SSerge Semin 	int ret;
865939fbcd5SSerge Semin 
866939fbcd5SSerge Semin 	if (nr >= EDMA_MAX_WR_CH + EDMA_MAX_RD_CH)
867939fbcd5SSerge Semin 		return -EINVAL;
868939fbcd5SSerge Semin 
869939fbcd5SSerge Semin 	ret = platform_get_irq_byname_optional(pdev, "dma");
870939fbcd5SSerge Semin 	if (ret > 0)
871939fbcd5SSerge Semin 		return ret;
872939fbcd5SSerge Semin 
873939fbcd5SSerge Semin 	snprintf(name, sizeof(name), "dma%u", nr);
874939fbcd5SSerge Semin 
875939fbcd5SSerge Semin 	return platform_get_irq_byname_optional(pdev, name);
876939fbcd5SSerge Semin }
877939fbcd5SSerge Semin 
87848751755SCai Huoqing static struct dw_edma_plat_ops dw_pcie_edma_ops = {
879939fbcd5SSerge Semin 	.irq_vector = dw_pcie_edma_irq_vector,
880939fbcd5SSerge Semin };
881939fbcd5SSerge Semin 
dw_pcie_edma_find_chip(struct dw_pcie * pci)882939fbcd5SSerge Semin static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
883939fbcd5SSerge Semin {
884939fbcd5SSerge Semin 	u32 val;
885939fbcd5SSerge Semin 
886939fbcd5SSerge Semin 	/*
887939fbcd5SSerge Semin 	 * Indirect eDMA CSRs access has been completely removed since v5.40a
888939fbcd5SSerge Semin 	 * thus no space is now reserved for the eDMA channels viewport and
889939fbcd5SSerge Semin 	 * former DMA CTRL register is no longer fixed to FFs.
890939fbcd5SSerge Semin 	 */
891939fbcd5SSerge Semin 	if (dw_pcie_ver_is_ge(pci, 540A))
892939fbcd5SSerge Semin 		val = 0xFFFFFFFF;
893939fbcd5SSerge Semin 	else
894939fbcd5SSerge Semin 		val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
895939fbcd5SSerge Semin 
896939fbcd5SSerge Semin 	if (val == 0xFFFFFFFF && pci->edma.reg_base) {
897939fbcd5SSerge Semin 		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
898939fbcd5SSerge Semin 
899939fbcd5SSerge Semin 		val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
900939fbcd5SSerge Semin 	} else if (val != 0xFFFFFFFF) {
901939fbcd5SSerge Semin 		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
902939fbcd5SSerge Semin 
903939fbcd5SSerge Semin 		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
904939fbcd5SSerge Semin 	} else {
905939fbcd5SSerge Semin 		return -ENODEV;
906939fbcd5SSerge Semin 	}
907939fbcd5SSerge Semin 
908939fbcd5SSerge Semin 	pci->edma.dev = pci->dev;
909939fbcd5SSerge Semin 
910939fbcd5SSerge Semin 	if (!pci->edma.ops)
911939fbcd5SSerge Semin 		pci->edma.ops = &dw_pcie_edma_ops;
912939fbcd5SSerge Semin 
913939fbcd5SSerge Semin 	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
914939fbcd5SSerge Semin 
915939fbcd5SSerge Semin 	pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val);
916939fbcd5SSerge Semin 	pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val);
917939fbcd5SSerge Semin 
918939fbcd5SSerge Semin 	/* Sanity check the channels count if the mapping was incorrect */
919939fbcd5SSerge Semin 	if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH ||
920939fbcd5SSerge Semin 	    !pci->edma.ll_rd_cnt || pci->edma.ll_rd_cnt > EDMA_MAX_RD_CH)
921939fbcd5SSerge Semin 		return -EINVAL;
922939fbcd5SSerge Semin 
923939fbcd5SSerge Semin 	return 0;
924939fbcd5SSerge Semin }
925939fbcd5SSerge Semin 
dw_pcie_edma_irq_verify(struct dw_pcie * pci)926939fbcd5SSerge Semin static int dw_pcie_edma_irq_verify(struct dw_pcie *pci)
927939fbcd5SSerge Semin {
928939fbcd5SSerge Semin 	struct platform_device *pdev = to_platform_device(pci->dev);
929939fbcd5SSerge Semin 	u16 ch_cnt = pci->edma.ll_wr_cnt + pci->edma.ll_rd_cnt;
930939fbcd5SSerge Semin 	char name[6];
931939fbcd5SSerge Semin 	int ret;
932939fbcd5SSerge Semin 
933939fbcd5SSerge Semin 	if (pci->edma.nr_irqs == 1)
934939fbcd5SSerge Semin 		return 0;
935939fbcd5SSerge Semin 	else if (pci->edma.nr_irqs > 1)
936939fbcd5SSerge Semin 		return pci->edma.nr_irqs != ch_cnt ? -EINVAL : 0;
937939fbcd5SSerge Semin 
938939fbcd5SSerge Semin 	ret = platform_get_irq_byname_optional(pdev, "dma");
939939fbcd5SSerge Semin 	if (ret > 0) {
940939fbcd5SSerge Semin 		pci->edma.nr_irqs = 1;
941939fbcd5SSerge Semin 		return 0;
942939fbcd5SSerge Semin 	}
943939fbcd5SSerge Semin 
944939fbcd5SSerge Semin 	for (; pci->edma.nr_irqs < ch_cnt; pci->edma.nr_irqs++) {
945939fbcd5SSerge Semin 		snprintf(name, sizeof(name), "dma%d", pci->edma.nr_irqs);
946939fbcd5SSerge Semin 
947939fbcd5SSerge Semin 		ret = platform_get_irq_byname_optional(pdev, name);
948939fbcd5SSerge Semin 		if (ret <= 0)
949939fbcd5SSerge Semin 			return -EINVAL;
950939fbcd5SSerge Semin 	}
951939fbcd5SSerge Semin 
952939fbcd5SSerge Semin 	return 0;
953939fbcd5SSerge Semin }
954939fbcd5SSerge Semin 
dw_pcie_edma_ll_alloc(struct dw_pcie * pci)955939fbcd5SSerge Semin static int dw_pcie_edma_ll_alloc(struct dw_pcie *pci)
956939fbcd5SSerge Semin {
957939fbcd5SSerge Semin 	struct dw_edma_region *ll;
958939fbcd5SSerge Semin 	dma_addr_t paddr;
959939fbcd5SSerge Semin 	int i;
960939fbcd5SSerge Semin 
961939fbcd5SSerge Semin 	for (i = 0; i < pci->edma.ll_wr_cnt; i++) {
962939fbcd5SSerge Semin 		ll = &pci->edma.ll_region_wr[i];
963939fbcd5SSerge Semin 		ll->sz = DMA_LLP_MEM_SIZE;
964939fbcd5SSerge Semin 		ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
965939fbcd5SSerge Semin 						    &paddr, GFP_KERNEL);
966939fbcd5SSerge Semin 		if (!ll->vaddr.mem)
967939fbcd5SSerge Semin 			return -ENOMEM;
968939fbcd5SSerge Semin 
969939fbcd5SSerge Semin 		ll->paddr = paddr;
970939fbcd5SSerge Semin 	}
971939fbcd5SSerge Semin 
972939fbcd5SSerge Semin 	for (i = 0; i < pci->edma.ll_rd_cnt; i++) {
973939fbcd5SSerge Semin 		ll = &pci->edma.ll_region_rd[i];
974939fbcd5SSerge Semin 		ll->sz = DMA_LLP_MEM_SIZE;
975939fbcd5SSerge Semin 		ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
976939fbcd5SSerge Semin 						    &paddr, GFP_KERNEL);
977939fbcd5SSerge Semin 		if (!ll->vaddr.mem)
978939fbcd5SSerge Semin 			return -ENOMEM;
979939fbcd5SSerge Semin 
980939fbcd5SSerge Semin 		ll->paddr = paddr;
981939fbcd5SSerge Semin 	}
982939fbcd5SSerge Semin 
983939fbcd5SSerge Semin 	return 0;
984939fbcd5SSerge Semin }
985939fbcd5SSerge Semin 
dw_pcie_edma_detect(struct dw_pcie * pci)986939fbcd5SSerge Semin int dw_pcie_edma_detect(struct dw_pcie *pci)
987939fbcd5SSerge Semin {
988939fbcd5SSerge Semin 	int ret;
989939fbcd5SSerge Semin 
990939fbcd5SSerge Semin 	/* Don't fail if no eDMA was found (for the backward compatibility) */
991939fbcd5SSerge Semin 	ret = dw_pcie_edma_find_chip(pci);
992939fbcd5SSerge Semin 	if (ret)
993939fbcd5SSerge Semin 		return 0;
994939fbcd5SSerge Semin 
995939fbcd5SSerge Semin 	/* Don't fail on the IRQs verification (for the backward compatibility) */
996939fbcd5SSerge Semin 	ret = dw_pcie_edma_irq_verify(pci);
997939fbcd5SSerge Semin 	if (ret) {
998939fbcd5SSerge Semin 		dev_err(pci->dev, "Invalid eDMA IRQs found\n");
999939fbcd5SSerge Semin 		return 0;
1000939fbcd5SSerge Semin 	}
1001939fbcd5SSerge Semin 
1002939fbcd5SSerge Semin 	ret = dw_pcie_edma_ll_alloc(pci);
1003939fbcd5SSerge Semin 	if (ret) {
1004939fbcd5SSerge Semin 		dev_err(pci->dev, "Couldn't allocate LLP memory\n");
1005939fbcd5SSerge Semin 		return ret;
1006939fbcd5SSerge Semin 	}
1007939fbcd5SSerge Semin 
1008939fbcd5SSerge Semin 	/* Don't fail if the DW eDMA driver can't find the device */
1009939fbcd5SSerge Semin 	ret = dw_edma_probe(&pci->edma);
1010939fbcd5SSerge Semin 	if (ret && ret != -ENODEV) {
1011939fbcd5SSerge Semin 		dev_err(pci->dev, "Couldn't register eDMA device\n");
1012939fbcd5SSerge Semin 		return ret;
1013939fbcd5SSerge Semin 	}
1014939fbcd5SSerge Semin 
1015939fbcd5SSerge Semin 	dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
1016939fbcd5SSerge Semin 		 pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
1017939fbcd5SSerge Semin 		 pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
1018939fbcd5SSerge Semin 
1019939fbcd5SSerge Semin 	return 0;
1020939fbcd5SSerge Semin }
1021939fbcd5SSerge Semin 
dw_pcie_edma_remove(struct dw_pcie * pci)1022939fbcd5SSerge Semin void dw_pcie_edma_remove(struct dw_pcie *pci)
1023939fbcd5SSerge Semin {
1024939fbcd5SSerge Semin 	dw_edma_remove(&pci->edma);
1025939fbcd5SSerge Semin }
1026939fbcd5SSerge Semin 
dw_pcie_setup(struct dw_pcie * pci)10278bcca265SHou Zhiqiang void dw_pcie_setup(struct dw_pcie *pci)
10288bcca265SHou Zhiqiang {
10298bcca265SHou Zhiqiang 	u32 val;
1030281f1f99SRob Herring 
103139bc5006SRob Herring 	if (pci->link_gen > 0)
103239bc5006SRob Herring 		dw_pcie_link_set_max_speed(pci, pci->link_gen);
103339bc5006SRob Herring 
1034aeaa0bfeSRob Herring 	/* Configure Gen1 N_FTS */
1035aeaa0bfeSRob Herring 	if (pci->n_fts[0]) {
1036aeaa0bfeSRob Herring 		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
1037aeaa0bfeSRob Herring 		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
1038aeaa0bfeSRob Herring 		val |= PORT_AFR_N_FTS(pci->n_fts[0]);
1039aeaa0bfeSRob Herring 		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
1040aeaa0bfeSRob Herring 		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
1041aeaa0bfeSRob Herring 	}
1042aeaa0bfeSRob Herring 
1043aeaa0bfeSRob Herring 	/* Configure Gen2+ N_FTS */
1044aeaa0bfeSRob Herring 	if (pci->n_fts[1]) {
1045aeaa0bfeSRob Herring 		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
1046aeaa0bfeSRob Herring 		val &= ~PORT_LOGIC_N_FTS_MASK;
104766110361SVidya Sagar 		val |= pci->n_fts[1];
1048aeaa0bfeSRob Herring 		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
1049aeaa0bfeSRob Herring 	}
1050aeaa0bfeSRob Herring 
1051ef8c5887SSerge Semin 	if (dw_pcie_cap_is(pci, CDM_CHECK)) {
1052ec7b952fSSerge Semin 		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
1053ec7b952fSSerge Semin 		val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
1054ec7b952fSSerge Semin 		       PCIE_PL_CHK_REG_CHK_REG_START;
1055ec7b952fSSerge Semin 		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
1056ec7b952fSSerge Semin 	}
1057ec7b952fSSerge Semin 
1058cdce6709SYoshihiro Shimoda 	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
1059cdce6709SYoshihiro Shimoda 	val &= ~PORT_LINK_FAST_LINK_MODE;
1060cdce6709SYoshihiro Shimoda 	val |= PORT_LINK_DLL_LINK_EN;
1061cdce6709SYoshihiro Shimoda 	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
1062cdce6709SYoshihiro Shimoda 
1063e8bde5ebSYoshihiro Shimoda 	dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
10646e0832faSShawn Lin }
1065