162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Synopsys DesignWare PCIe host controller driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd.
662306a36Sopenharmony_ci *		https://www.samsung.com
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Jingoo Han <jg1.han@samsung.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/align.h>
1262306a36Sopenharmony_ci#include <linux/bitops.h>
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dma/edma.h>
1662306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1762306a36Sopenharmony_ci#include <linux/ioport.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/sizes.h>
2162306a36Sopenharmony_ci#include <linux/types.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "../../pci.h"
2462306a36Sopenharmony_ci#include "pcie-designware.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = {
2762306a36Sopenharmony_ci	[DW_PCIE_DBI_CLK] = "dbi",
2862306a36Sopenharmony_ci	[DW_PCIE_MSTR_CLK] = "mstr",
2962306a36Sopenharmony_ci	[DW_PCIE_SLV_CLK] = "slv",
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = {
3362306a36Sopenharmony_ci	[DW_PCIE_PIPE_CLK] = "pipe",
3462306a36Sopenharmony_ci	[DW_PCIE_CORE_CLK] = "core",
3562306a36Sopenharmony_ci	[DW_PCIE_AUX_CLK] = "aux",
3662306a36Sopenharmony_ci	[DW_PCIE_REF_CLK] = "ref",
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = {
4062306a36Sopenharmony_ci	[DW_PCIE_DBI_RST] = "dbi",
4162306a36Sopenharmony_ci	[DW_PCIE_MSTR_RST] = "mstr",
4262306a36Sopenharmony_ci	[DW_PCIE_SLV_RST] = "slv",
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = {
4662306a36Sopenharmony_ci	[DW_PCIE_NON_STICKY_RST] = "non-sticky",
4762306a36Sopenharmony_ci	[DW_PCIE_STICKY_RST] = "sticky",
4862306a36Sopenharmony_ci	[DW_PCIE_CORE_RST] = "core",
4962306a36Sopenharmony_ci	[DW_PCIE_PIPE_RST] = "pipe",
5062306a36Sopenharmony_ci	[DW_PCIE_PHY_RST] = "phy",
5162306a36Sopenharmony_ci	[DW_PCIE_HOT_RST] = "hot",
5262306a36Sopenharmony_ci	[DW_PCIE_PWR_RST] = "pwr",
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int dw_pcie_get_clocks(struct dw_pcie *pci)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int i, ret;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++)
6062306a36Sopenharmony_ci		pci->app_clks[i].id = dw_pcie_app_clks[i];
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++)
6362306a36Sopenharmony_ci		pci->core_clks[i].id = dw_pcie_core_clks[i];
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS,
6662306a36Sopenharmony_ci					 pci->app_clks);
6762306a36Sopenharmony_ci	if (ret)
6862306a36Sopenharmony_ci		return ret;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS,
7162306a36Sopenharmony_ci					  pci->core_clks);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int dw_pcie_get_resets(struct dw_pcie *pci)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	int i, ret;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++)
7962306a36Sopenharmony_ci		pci->app_rsts[i].id = dw_pcie_app_rsts[i];
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++)
8262306a36Sopenharmony_ci		pci->core_rsts[i].id = dw_pcie_core_rsts[i];
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ret = devm_reset_control_bulk_get_optional_shared(pci->dev,
8562306a36Sopenharmony_ci							  DW_PCIE_NUM_APP_RSTS,
8662306a36Sopenharmony_ci							  pci->app_rsts);
8762306a36Sopenharmony_ci	if (ret)
8862306a36Sopenharmony_ci		return ret;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev,
9162306a36Sopenharmony_ci							     DW_PCIE_NUM_CORE_RSTS,
9262306a36Sopenharmony_ci							     pci->core_rsts);
9362306a36Sopenharmony_ci	if (ret)
9462306a36Sopenharmony_ci		return ret;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH);
9762306a36Sopenharmony_ci	if (IS_ERR(pci->pe_rst))
9862306a36Sopenharmony_ci		return PTR_ERR(pci->pe_rst);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciint dw_pcie_get_resources(struct dw_pcie *pci)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(pci->dev);
10662306a36Sopenharmony_ci	struct device_node *np = dev_of_node(pci->dev);
10762306a36Sopenharmony_ci	struct resource *res;
10862306a36Sopenharmony_ci	int ret;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!pci->dbi_base) {
11162306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
11262306a36Sopenharmony_ci		pci->dbi_base = devm_pci_remap_cfg_resource(pci->dev, res);
11362306a36Sopenharmony_ci		if (IS_ERR(pci->dbi_base))
11462306a36Sopenharmony_ci			return PTR_ERR(pci->dbi_base);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* DBI2 is mainly useful for the endpoint controller */
11862306a36Sopenharmony_ci	if (!pci->dbi_base2) {
11962306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
12062306a36Sopenharmony_ci		if (res) {
12162306a36Sopenharmony_ci			pci->dbi_base2 = devm_pci_remap_cfg_resource(pci->dev, res);
12262306a36Sopenharmony_ci			if (IS_ERR(pci->dbi_base2))
12362306a36Sopenharmony_ci				return PTR_ERR(pci->dbi_base2);
12462306a36Sopenharmony_ci		} else {
12562306a36Sopenharmony_ci			pci->dbi_base2 = pci->dbi_base + SZ_4K;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* For non-unrolled iATU/eDMA platforms this range will be ignored */
13062306a36Sopenharmony_ci	if (!pci->atu_base) {
13162306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
13262306a36Sopenharmony_ci		if (res) {
13362306a36Sopenharmony_ci			pci->atu_size = resource_size(res);
13462306a36Sopenharmony_ci			pci->atu_base = devm_ioremap_resource(pci->dev, res);
13562306a36Sopenharmony_ci			if (IS_ERR(pci->atu_base))
13662306a36Sopenharmony_ci				return PTR_ERR(pci->atu_base);
13762306a36Sopenharmony_ci		} else {
13862306a36Sopenharmony_ci			pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Set a default value suitable for at most 8 in and 8 out windows */
14362306a36Sopenharmony_ci	if (!pci->atu_size)
14462306a36Sopenharmony_ci		pci->atu_size = SZ_4K;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* eDMA region can be mapped to a custom base address */
14762306a36Sopenharmony_ci	if (!pci->edma.reg_base) {
14862306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
14962306a36Sopenharmony_ci		if (res) {
15062306a36Sopenharmony_ci			pci->edma.reg_base = devm_ioremap_resource(pci->dev, res);
15162306a36Sopenharmony_ci			if (IS_ERR(pci->edma.reg_base))
15262306a36Sopenharmony_ci				return PTR_ERR(pci->edma.reg_base);
15362306a36Sopenharmony_ci		} else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) {
15462306a36Sopenharmony_ci			pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET;
15562306a36Sopenharmony_ci		}
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* LLDD is supposed to manually switch the clocks and resets state */
15962306a36Sopenharmony_ci	if (dw_pcie_cap_is(pci, REQ_RES)) {
16062306a36Sopenharmony_ci		ret = dw_pcie_get_clocks(pci);
16162306a36Sopenharmony_ci		if (ret)
16262306a36Sopenharmony_ci			return ret;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		ret = dw_pcie_get_resets(pci);
16562306a36Sopenharmony_ci		if (ret)
16662306a36Sopenharmony_ci			return ret;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (pci->link_gen < 1)
17062306a36Sopenharmony_ci		pci->link_gen = of_pci_get_max_link_speed(np);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	of_property_read_u32(np, "num-lanes", &pci->num_lanes);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (of_property_read_bool(np, "snps,enable-cdm-check"))
17562306a36Sopenharmony_ci		dw_pcie_cap_set(pci, CDM_CHECK);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return 0;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_civoid dw_pcie_version_detect(struct dw_pcie *pci)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	u32 ver;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
18562306a36Sopenharmony_ci	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
18662306a36Sopenharmony_ci	if (!ver)
18762306a36Sopenharmony_ci		return;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (pci->version && pci->version != ver)
19062306a36Sopenharmony_ci		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
19162306a36Sopenharmony_ci			 pci->version, ver);
19262306a36Sopenharmony_ci	else
19362306a36Sopenharmony_ci		pci->version = ver;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_TYPE);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (pci->type && pci->type != ver)
19862306a36Sopenharmony_ci		dev_warn(pci->dev, "Types don't match (%08x != %08x)\n",
19962306a36Sopenharmony_ci			 pci->type, ver);
20062306a36Sopenharmony_ci	else
20162306a36Sopenharmony_ci		pci->type = ver;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/*
20562306a36Sopenharmony_ci * These interfaces resemble the pci_find_*capability() interfaces, but these
20662306a36Sopenharmony_ci * are for configuring host controllers, which are bridges *to* PCI devices but
20762306a36Sopenharmony_ci * are not PCI devices themselves.
20862306a36Sopenharmony_ci */
20962306a36Sopenharmony_cistatic u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
21062306a36Sopenharmony_ci				  u8 cap)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	u8 cap_id, next_cap_ptr;
21362306a36Sopenharmony_ci	u16 reg;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (!cap_ptr)
21662306a36Sopenharmony_ci		return 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	reg = dw_pcie_readw_dbi(pci, cap_ptr);
21962306a36Sopenharmony_ci	cap_id = (reg & 0x00ff);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (cap_id > PCI_CAP_ID_MAX)
22262306a36Sopenharmony_ci		return 0;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (cap_id == cap)
22562306a36Sopenharmony_ci		return cap_ptr;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	next_cap_ptr = (reg & 0xff00) >> 8;
22862306a36Sopenharmony_ci	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ciu8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u8 next_cap_ptr;
23462306a36Sopenharmony_ci	u16 reg;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
23762306a36Sopenharmony_ci	next_cap_ptr = (reg & 0x00ff);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_find_capability);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
24462306a36Sopenharmony_ci					    u8 cap)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	u32 header;
24762306a36Sopenharmony_ci	int ttl;
24862306a36Sopenharmony_ci	int pos = PCI_CFG_SPACE_SIZE;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* minimum 8 bytes per capability */
25162306a36Sopenharmony_ci	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (start)
25462306a36Sopenharmony_ci		pos = start;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	header = dw_pcie_readl_dbi(pci, pos);
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * If we have no capabilities, this is indicated by cap ID,
25962306a36Sopenharmony_ci	 * cap version and next pointer all being 0.
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (header == 0)
26262306a36Sopenharmony_ci		return 0;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	while (ttl-- > 0) {
26562306a36Sopenharmony_ci		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
26662306a36Sopenharmony_ci			return pos;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		pos = PCI_EXT_CAP_NEXT(header);
26962306a36Sopenharmony_ci		if (pos < PCI_CFG_SPACE_SIZE)
27062306a36Sopenharmony_ci			break;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		header = dw_pcie_readl_dbi(pci, pos);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciu16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	return dw_pcie_find_next_ext_capability(pci, 0, cap);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciint dw_pcie_read(void __iomem *addr, int size, u32 *val)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)addr, size)) {
28762306a36Sopenharmony_ci		*val = 0;
28862306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (size == 4) {
29262306a36Sopenharmony_ci		*val = readl(addr);
29362306a36Sopenharmony_ci	} else if (size == 2) {
29462306a36Sopenharmony_ci		*val = readw(addr);
29562306a36Sopenharmony_ci	} else if (size == 1) {
29662306a36Sopenharmony_ci		*val = readb(addr);
29762306a36Sopenharmony_ci	} else {
29862306a36Sopenharmony_ci		*val = 0;
29962306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_read);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciint dw_pcie_write(void __iomem *addr, int size, u32 val)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)addr, size))
30962306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (size == 4)
31262306a36Sopenharmony_ci		writel(val, addr);
31362306a36Sopenharmony_ci	else if (size == 2)
31462306a36Sopenharmony_ci		writew(val, addr);
31562306a36Sopenharmony_ci	else if (size == 1)
31662306a36Sopenharmony_ci		writeb(val, addr);
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_write);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ciu32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	int ret;
32762306a36Sopenharmony_ci	u32 val;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (pci->ops && pci->ops->read_dbi)
33062306a36Sopenharmony_ci		return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
33362306a36Sopenharmony_ci	if (ret)
33462306a36Sopenharmony_ci		dev_err(pci->dev, "Read DBI address failed\n");
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return val;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_read_dbi);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	int ret;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (pci->ops && pci->ops->write_dbi) {
34562306a36Sopenharmony_ci		pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
34662306a36Sopenharmony_ci		return;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ret = dw_pcie_write(pci->dbi_base + reg, size, val);
35062306a36Sopenharmony_ci	if (ret)
35162306a36Sopenharmony_ci		dev_err(pci->dev, "Write DBI address failed\n");
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	int ret;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (pci->ops && pci->ops->write_dbi2) {
36062306a36Sopenharmony_ci		pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
36162306a36Sopenharmony_ci		return;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
36562306a36Sopenharmony_ci	if (ret)
36662306a36Sopenharmony_ci		dev_err(pci->dev, "write DBI address failed\n");
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic inline void __iomem *dw_pcie_select_atu(struct dw_pcie *pci, u32 dir,
37062306a36Sopenharmony_ci					       u32 index)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	if (dw_pcie_cap_is(pci, IATU_UNROLL))
37362306a36Sopenharmony_ci		return pci->atu_base + PCIE_ATU_UNROLL_BASE(dir, index);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | index);
37662306a36Sopenharmony_ci	return pci->atu_base;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 dir, u32 index, u32 reg)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	void __iomem *base;
38262306a36Sopenharmony_ci	int ret;
38362306a36Sopenharmony_ci	u32 val;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	base = dw_pcie_select_atu(pci, dir, index);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (pci->ops && pci->ops->read_dbi)
38862306a36Sopenharmony_ci		return pci->ops->read_dbi(pci, base, reg, 4);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = dw_pcie_read(base + reg, 4, &val);
39162306a36Sopenharmony_ci	if (ret)
39262306a36Sopenharmony_ci		dev_err(pci->dev, "Read ATU address failed\n");
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return val;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic void dw_pcie_writel_atu(struct dw_pcie *pci, u32 dir, u32 index,
39862306a36Sopenharmony_ci			       u32 reg, u32 val)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	void __iomem *base;
40162306a36Sopenharmony_ci	int ret;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	base = dw_pcie_select_atu(pci, dir, index);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (pci->ops && pci->ops->write_dbi) {
40662306a36Sopenharmony_ci		pci->ops->write_dbi(pci, base, reg, 4, val);
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	ret = dw_pcie_write(base + reg, 4, val);
41162306a36Sopenharmony_ci	if (ret)
41262306a36Sopenharmony_ci		dev_err(pci->dev, "Write ATU address failed\n");
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic inline u32 dw_pcie_readl_atu_ob(struct dw_pcie *pci, u32 index, u32 reg)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_OB, index, reg);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg,
42162306a36Sopenharmony_ci					 u32 val)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_OB, index, reg, val);
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic inline u32 dw_pcie_enable_ecrc(u32 val)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	/*
42962306a36Sopenharmony_ci	 * DesignWare core version 4.90A has a design issue where the 'TD'
43062306a36Sopenharmony_ci	 * bit in the Control register-1 of the ATU outbound region acts
43162306a36Sopenharmony_ci	 * like an override for the ECRC setting, i.e., the presence of TLP
43262306a36Sopenharmony_ci	 * Digest (ECRC) in the outgoing TLPs is solely determined by this
43362306a36Sopenharmony_ci	 * bit. This is contrary to the PCIe spec which says that the
43462306a36Sopenharmony_ci	 * enablement of the ECRC is solely determined by the AER
43562306a36Sopenharmony_ci	 * registers.
43662306a36Sopenharmony_ci	 *
43762306a36Sopenharmony_ci	 * Because of this, even when the ECRC is enabled through AER
43862306a36Sopenharmony_ci	 * registers, the transactions going through ATU won't have TLP
43962306a36Sopenharmony_ci	 * Digest as there is no way the PCI core AER code could program
44062306a36Sopenharmony_ci	 * the TD bit which is specific to the DesignWare core.
44162306a36Sopenharmony_ci	 *
44262306a36Sopenharmony_ci	 * The best way to handle this scenario is to program the TD bit
44362306a36Sopenharmony_ci	 * always. It affects only the traffic from root port to downstream
44462306a36Sopenharmony_ci	 * devices.
44562306a36Sopenharmony_ci	 *
44662306a36Sopenharmony_ci	 * At this point,
44762306a36Sopenharmony_ci	 * When ECRC is enabled in AER registers, everything works normally
44862306a36Sopenharmony_ci	 * When ECRC is NOT enabled in AER registers, then,
44962306a36Sopenharmony_ci	 * on Root Port:- TLP Digest (DWord size) gets appended to each packet
45062306a36Sopenharmony_ci	 *                even through it is not required. Since downstream
45162306a36Sopenharmony_ci	 *                TLPs are mostly for configuration accesses and BAR
45262306a36Sopenharmony_ci	 *                accesses, they are not in critical path and won't
45362306a36Sopenharmony_ci	 *                have much negative effect on the performance.
45462306a36Sopenharmony_ci	 * on End Point:- TLP Digest is received for some/all the packets coming
45562306a36Sopenharmony_ci	 *                from the root port. TLP Digest is ignored because,
45662306a36Sopenharmony_ci	 *                as per the PCIe Spec r5.0 v1.0 section 2.2.3
45762306a36Sopenharmony_ci	 *                "TLP Digest Rules", when an endpoint receives TLP
45862306a36Sopenharmony_ci	 *                Digest when its ECRC check functionality is disabled
45962306a36Sopenharmony_ci	 *                in AER registers, received TLP Digest is just ignored.
46062306a36Sopenharmony_ci	 * Since there is no issue or error reported either side, best way to
46162306a36Sopenharmony_ci	 * handle the scenario is to program TD bit by default.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return val | PCIE_ATU_TD;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
46862306a36Sopenharmony_ci				       int index, int type, u64 cpu_addr,
46962306a36Sopenharmony_ci				       u64 pci_addr, u64 size)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	u32 retries, val;
47262306a36Sopenharmony_ci	u64 limit_addr;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (pci->ops && pci->ops->cpu_addr_fixup)
47562306a36Sopenharmony_ci		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	limit_addr = cpu_addr + size - 1;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if ((limit_addr & ~pci->region_limit) != (cpu_addr & ~pci->region_limit) ||
48062306a36Sopenharmony_ci	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
48162306a36Sopenharmony_ci	    !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
48262306a36Sopenharmony_ci		return -EINVAL;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
48662306a36Sopenharmony_ci			      lower_32_bits(cpu_addr));
48762306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
48862306a36Sopenharmony_ci			      upper_32_bits(cpu_addr));
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LIMIT,
49162306a36Sopenharmony_ci			      lower_32_bits(limit_addr));
49262306a36Sopenharmony_ci	if (dw_pcie_ver_is_ge(pci, 460A))
49362306a36Sopenharmony_ci		dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_LIMIT,
49462306a36Sopenharmony_ci				      upper_32_bits(limit_addr));
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_TARGET,
49762306a36Sopenharmony_ci			      lower_32_bits(pci_addr));
49862306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_TARGET,
49962306a36Sopenharmony_ci			      upper_32_bits(pci_addr));
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	val = type | PCIE_ATU_FUNC_NUM(func_no);
50262306a36Sopenharmony_ci	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
50362306a36Sopenharmony_ci	    dw_pcie_ver_is_ge(pci, 460A))
50462306a36Sopenharmony_ci		val |= PCIE_ATU_INCREASE_REGION_SIZE;
50562306a36Sopenharmony_ci	if (dw_pcie_ver_is(pci, 490A))
50662306a36Sopenharmony_ci		val = dw_pcie_enable_ecrc(val);
50762306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/*
51262306a36Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
51362306a36Sopenharmony_ci	 * and I/O accesses.
51462306a36Sopenharmony_ci	 */
51562306a36Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
51662306a36Sopenharmony_ci		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
51762306a36Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
51862306a36Sopenharmony_ci			return 0;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return -ETIMEDOUT;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
52962306a36Sopenharmony_ci			      u64 cpu_addr, u64 pci_addr, u64 size)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	return __dw_pcie_prog_outbound_atu(pci, 0, index, type,
53262306a36Sopenharmony_ci					   cpu_addr, pci_addr, size);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ciint dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
53662306a36Sopenharmony_ci				 int type, u64 cpu_addr, u64 pci_addr,
53762306a36Sopenharmony_ci				 u64 size)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	return __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
54062306a36Sopenharmony_ci					   cpu_addr, pci_addr, size);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
54962306a36Sopenharmony_ci					 u32 val)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ciint dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
55562306a36Sopenharmony_ci			     u64 cpu_addr, u64 pci_addr, u64 size)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	u64 limit_addr = pci_addr + size - 1;
55862306a36Sopenharmony_ci	u32 retries, val;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
56162306a36Sopenharmony_ci	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
56262306a36Sopenharmony_ci	    !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
56362306a36Sopenharmony_ci		return -EINVAL;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
56762306a36Sopenharmony_ci			      lower_32_bits(pci_addr));
56862306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE,
56962306a36Sopenharmony_ci			      upper_32_bits(pci_addr));
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT,
57262306a36Sopenharmony_ci			      lower_32_bits(limit_addr));
57362306a36Sopenharmony_ci	if (dw_pcie_ver_is_ge(pci, 460A))
57462306a36Sopenharmony_ci		dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT,
57562306a36Sopenharmony_ci				      upper_32_bits(limit_addr));
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
57862306a36Sopenharmony_ci			      lower_32_bits(cpu_addr));
57962306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
58062306a36Sopenharmony_ci			      upper_32_bits(cpu_addr));
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	val = type;
58362306a36Sopenharmony_ci	if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) &&
58462306a36Sopenharmony_ci	    dw_pcie_ver_is_ge(pci, 460A))
58562306a36Sopenharmony_ci		val |= PCIE_ATU_INCREASE_REGION_SIZE;
58662306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val);
58762306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/*
59062306a36Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
59162306a36Sopenharmony_ci	 * and I/O accesses.
59262306a36Sopenharmony_ci	 */
59362306a36Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
59462306a36Sopenharmony_ci		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
59562306a36Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
59662306a36Sopenharmony_ci			return 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return -ETIMEDOUT;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ciint dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
60762306a36Sopenharmony_ci				int type, u64 cpu_addr, u8 bar)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	u32 retries, val;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!IS_ALIGNED(cpu_addr, pci->region_align))
61262306a36Sopenharmony_ci		return -EINVAL;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
61562306a36Sopenharmony_ci			      lower_32_bits(cpu_addr));
61662306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
61762306a36Sopenharmony_ci			      upper_32_bits(cpu_addr));
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
62062306a36Sopenharmony_ci			      PCIE_ATU_FUNC_NUM(func_no));
62162306a36Sopenharmony_ci	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
62262306a36Sopenharmony_ci			      PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
62362306a36Sopenharmony_ci			      PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/*
62662306a36Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
62762306a36Sopenharmony_ci	 * and I/O accesses.
62862306a36Sopenharmony_ci	 */
62962306a36Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
63062306a36Sopenharmony_ci		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
63162306a36Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
63262306a36Sopenharmony_ci			return 0;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return -ETIMEDOUT;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_civoid dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ciint dw_pcie_wait_for_link(struct dw_pcie *pci)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	u32 offset, val;
65062306a36Sopenharmony_ci	int retries;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Check if the link is up or not */
65362306a36Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
65462306a36Sopenharmony_ci		if (dw_pcie_link_up(pci))
65562306a36Sopenharmony_ci			break;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (retries >= LINK_WAIT_MAX_RETRIES) {
66162306a36Sopenharmony_ci		dev_info(pci->dev, "Phy link never came up\n");
66262306a36Sopenharmony_ci		return -ETIMEDOUT;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
66662306a36Sopenharmony_ci	val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
66962306a36Sopenharmony_ci		 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
67062306a36Sopenharmony_ci		 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return 0;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_wait_for_link);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciint dw_pcie_link_up(struct dw_pcie *pci)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	u32 val;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (pci->ops && pci->ops->link_up)
68162306a36Sopenharmony_ci		return pci->ops->link_up(pci);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1);
68462306a36Sopenharmony_ci	return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
68562306a36Sopenharmony_ci		(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_link_up);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_civoid dw_pcie_upconfig_setup(struct dw_pcie *pci)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	u32 val;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL);
69462306a36Sopenharmony_ci	val |= PORT_MLTI_UPCFG_SUPPORT;
69562306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	u32 cap, ctrl2, link_speed;
70262306a36Sopenharmony_ci	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
70562306a36Sopenharmony_ci	ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
70662306a36Sopenharmony_ci	ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	switch (pcie_link_speed[link_gen]) {
70962306a36Sopenharmony_ci	case PCIE_SPEED_2_5GT:
71062306a36Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
71162306a36Sopenharmony_ci		break;
71262306a36Sopenharmony_ci	case PCIE_SPEED_5_0GT:
71362306a36Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
71462306a36Sopenharmony_ci		break;
71562306a36Sopenharmony_ci	case PCIE_SPEED_8_0GT:
71662306a36Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
71762306a36Sopenharmony_ci		break;
71862306a36Sopenharmony_ci	case PCIE_SPEED_16_0GT:
71962306a36Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
72062306a36Sopenharmony_ci		break;
72162306a36Sopenharmony_ci	default:
72262306a36Sopenharmony_ci		/* Use hardware capability */
72362306a36Sopenharmony_ci		link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
72462306a36Sopenharmony_ci		ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
72562306a36Sopenharmony_ci		break;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
73162306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	u32 lnkcap, lwsc, plc;
73862306a36Sopenharmony_ci	u8 cap;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (!num_lanes)
74162306a36Sopenharmony_ci		return;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* Set the number of lanes */
74462306a36Sopenharmony_ci	plc = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
74562306a36Sopenharmony_ci	plc &= ~PORT_LINK_FAST_LINK_MODE;
74662306a36Sopenharmony_ci	plc &= ~PORT_LINK_MODE_MASK;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* Set link width speed control register */
74962306a36Sopenharmony_ci	lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
75062306a36Sopenharmony_ci	lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
75162306a36Sopenharmony_ci	switch (num_lanes) {
75262306a36Sopenharmony_ci	case 1:
75362306a36Sopenharmony_ci		plc |= PORT_LINK_MODE_1_LANES;
75462306a36Sopenharmony_ci		lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
75562306a36Sopenharmony_ci		break;
75662306a36Sopenharmony_ci	case 2:
75762306a36Sopenharmony_ci		plc |= PORT_LINK_MODE_2_LANES;
75862306a36Sopenharmony_ci		lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES;
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case 4:
76162306a36Sopenharmony_ci		plc |= PORT_LINK_MODE_4_LANES;
76262306a36Sopenharmony_ci		lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES;
76362306a36Sopenharmony_ci		break;
76462306a36Sopenharmony_ci	case 8:
76562306a36Sopenharmony_ci		plc |= PORT_LINK_MODE_8_LANES;
76662306a36Sopenharmony_ci		lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES;
76762306a36Sopenharmony_ci		break;
76862306a36Sopenharmony_ci	default:
76962306a36Sopenharmony_ci		dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
77062306a36Sopenharmony_ci		return;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
77362306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
77662306a36Sopenharmony_ci	lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
77762306a36Sopenharmony_ci	lnkcap &= ~PCI_EXP_LNKCAP_MLW;
77862306a36Sopenharmony_ci	lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
77962306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_civoid dw_pcie_iatu_detect(struct dw_pcie *pci)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	int max_region, ob, ib;
78562306a36Sopenharmony_ci	u32 val, min, dir;
78662306a36Sopenharmony_ci	u64 max;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
78962306a36Sopenharmony_ci	if (val == 0xFFFFFFFF) {
79062306a36Sopenharmony_ci		dw_pcie_cap_set(pci, IATU_UNROLL);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		max_region = min((int)pci->atu_size / 512, 256);
79362306a36Sopenharmony_ci	} else {
79462306a36Sopenharmony_ci		pci->atu_base = pci->dbi_base + PCIE_ATU_VIEWPORT_BASE;
79562306a36Sopenharmony_ci		pci->atu_size = PCIE_ATU_VIEWPORT_SIZE;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
79862306a36Sopenharmony_ci		max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	for (ob = 0; ob < max_region; ob++) {
80262306a36Sopenharmony_ci		dw_pcie_writel_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET, 0x11110000);
80362306a36Sopenharmony_ci		val = dw_pcie_readl_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET);
80462306a36Sopenharmony_ci		if (val != 0x11110000)
80562306a36Sopenharmony_ci			break;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	for (ib = 0; ib < max_region; ib++) {
80962306a36Sopenharmony_ci		dw_pcie_writel_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET, 0x11110000);
81062306a36Sopenharmony_ci		val = dw_pcie_readl_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET);
81162306a36Sopenharmony_ci		if (val != 0x11110000)
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (ob) {
81662306a36Sopenharmony_ci		dir = PCIE_ATU_REGION_DIR_OB;
81762306a36Sopenharmony_ci	} else if (ib) {
81862306a36Sopenharmony_ci		dir = PCIE_ATU_REGION_DIR_IB;
81962306a36Sopenharmony_ci	} else {
82062306a36Sopenharmony_ci		dev_err(pci->dev, "No iATU regions found\n");
82162306a36Sopenharmony_ci		return;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_LIMIT, 0x0);
82562306a36Sopenharmony_ci	min = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_LIMIT);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (dw_pcie_ver_is_ge(pci, 460A)) {
82862306a36Sopenharmony_ci		dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT, 0xFFFFFFFF);
82962306a36Sopenharmony_ci		max = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT);
83062306a36Sopenharmony_ci	} else {
83162306a36Sopenharmony_ci		max = 0;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	pci->num_ob_windows = ob;
83562306a36Sopenharmony_ci	pci->num_ib_windows = ib;
83662306a36Sopenharmony_ci	pci->region_align = 1 << fls(min);
83762306a36Sopenharmony_ci	pci->region_limit = (max << 32) | (SZ_4G - 1);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	dev_info(pci->dev, "iATU: unroll %s, %u ob, %u ib, align %uK, limit %lluG\n",
84062306a36Sopenharmony_ci		 dw_pcie_cap_is(pci, IATU_UNROLL) ? "T" : "F",
84162306a36Sopenharmony_ci		 pci->num_ob_windows, pci->num_ib_windows,
84262306a36Sopenharmony_ci		 pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic u32 dw_pcie_readl_dma(struct dw_pcie *pci, u32 reg)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	u32 val = 0;
84862306a36Sopenharmony_ci	int ret;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (pci->ops && pci->ops->read_dbi)
85162306a36Sopenharmony_ci		return pci->ops->read_dbi(pci, pci->edma.reg_base, reg, 4);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ret = dw_pcie_read(pci->edma.reg_base + reg, 4, &val);
85462306a36Sopenharmony_ci	if (ret)
85562306a36Sopenharmony_ci		dev_err(pci->dev, "Read DMA address failed\n");
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return val;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic int dw_pcie_edma_irq_vector(struct device *dev, unsigned int nr)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
86362306a36Sopenharmony_ci	char name[6];
86462306a36Sopenharmony_ci	int ret;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (nr >= EDMA_MAX_WR_CH + EDMA_MAX_RD_CH)
86762306a36Sopenharmony_ci		return -EINVAL;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	ret = platform_get_irq_byname_optional(pdev, "dma");
87062306a36Sopenharmony_ci	if (ret > 0)
87162306a36Sopenharmony_ci		return ret;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	snprintf(name, sizeof(name), "dma%u", nr);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	return platform_get_irq_byname_optional(pdev, name);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic struct dw_edma_plat_ops dw_pcie_edma_ops = {
87962306a36Sopenharmony_ci	.irq_vector = dw_pcie_edma_irq_vector,
88062306a36Sopenharmony_ci};
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic int dw_pcie_edma_find_chip(struct dw_pcie *pci)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	u32 val;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/*
88762306a36Sopenharmony_ci	 * Indirect eDMA CSRs access has been completely removed since v5.40a
88862306a36Sopenharmony_ci	 * thus no space is now reserved for the eDMA channels viewport and
88962306a36Sopenharmony_ci	 * former DMA CTRL register is no longer fixed to FFs.
89062306a36Sopenharmony_ci	 */
89162306a36Sopenharmony_ci	if (dw_pcie_ver_is_ge(pci, 540A))
89262306a36Sopenharmony_ci		val = 0xFFFFFFFF;
89362306a36Sopenharmony_ci	else
89462306a36Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	if (val == 0xFFFFFFFF && pci->edma.reg_base) {
89762306a36Sopenharmony_ci		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
90062306a36Sopenharmony_ci	} else if (val != 0xFFFFFFFF) {
90162306a36Sopenharmony_ci		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
90462306a36Sopenharmony_ci	} else {
90562306a36Sopenharmony_ci		return -ENODEV;
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	pci->edma.dev = pci->dev;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (!pci->edma.ops)
91162306a36Sopenharmony_ci		pci->edma.ops = &dw_pcie_edma_ops;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val);
91662306a36Sopenharmony_ci	pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	/* Sanity check the channels count if the mapping was incorrect */
91962306a36Sopenharmony_ci	if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH ||
92062306a36Sopenharmony_ci	    !pci->edma.ll_rd_cnt || pci->edma.ll_rd_cnt > EDMA_MAX_RD_CH)
92162306a36Sopenharmony_ci		return -EINVAL;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return 0;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic int dw_pcie_edma_irq_verify(struct dw_pcie *pci)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(pci->dev);
92962306a36Sopenharmony_ci	u16 ch_cnt = pci->edma.ll_wr_cnt + pci->edma.ll_rd_cnt;
93062306a36Sopenharmony_ci	char name[6];
93162306a36Sopenharmony_ci	int ret;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (pci->edma.nr_irqs == 1)
93462306a36Sopenharmony_ci		return 0;
93562306a36Sopenharmony_ci	else if (pci->edma.nr_irqs > 1)
93662306a36Sopenharmony_ci		return pci->edma.nr_irqs != ch_cnt ? -EINVAL : 0;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	ret = platform_get_irq_byname_optional(pdev, "dma");
93962306a36Sopenharmony_ci	if (ret > 0) {
94062306a36Sopenharmony_ci		pci->edma.nr_irqs = 1;
94162306a36Sopenharmony_ci		return 0;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	for (; pci->edma.nr_irqs < ch_cnt; pci->edma.nr_irqs++) {
94562306a36Sopenharmony_ci		snprintf(name, sizeof(name), "dma%d", pci->edma.nr_irqs);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		ret = platform_get_irq_byname_optional(pdev, name);
94862306a36Sopenharmony_ci		if (ret <= 0)
94962306a36Sopenharmony_ci			return -EINVAL;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return 0;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic int dw_pcie_edma_ll_alloc(struct dw_pcie *pci)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct dw_edma_region *ll;
95862306a36Sopenharmony_ci	dma_addr_t paddr;
95962306a36Sopenharmony_ci	int i;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	for (i = 0; i < pci->edma.ll_wr_cnt; i++) {
96262306a36Sopenharmony_ci		ll = &pci->edma.ll_region_wr[i];
96362306a36Sopenharmony_ci		ll->sz = DMA_LLP_MEM_SIZE;
96462306a36Sopenharmony_ci		ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
96562306a36Sopenharmony_ci						    &paddr, GFP_KERNEL);
96662306a36Sopenharmony_ci		if (!ll->vaddr.mem)
96762306a36Sopenharmony_ci			return -ENOMEM;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		ll->paddr = paddr;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	for (i = 0; i < pci->edma.ll_rd_cnt; i++) {
97362306a36Sopenharmony_ci		ll = &pci->edma.ll_region_rd[i];
97462306a36Sopenharmony_ci		ll->sz = DMA_LLP_MEM_SIZE;
97562306a36Sopenharmony_ci		ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
97662306a36Sopenharmony_ci						    &paddr, GFP_KERNEL);
97762306a36Sopenharmony_ci		if (!ll->vaddr.mem)
97862306a36Sopenharmony_ci			return -ENOMEM;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		ll->paddr = paddr;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return 0;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ciint dw_pcie_edma_detect(struct dw_pcie *pci)
98762306a36Sopenharmony_ci{
98862306a36Sopenharmony_ci	int ret;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/* Don't fail if no eDMA was found (for the backward compatibility) */
99162306a36Sopenharmony_ci	ret = dw_pcie_edma_find_chip(pci);
99262306a36Sopenharmony_ci	if (ret)
99362306a36Sopenharmony_ci		return 0;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* Don't fail on the IRQs verification (for the backward compatibility) */
99662306a36Sopenharmony_ci	ret = dw_pcie_edma_irq_verify(pci);
99762306a36Sopenharmony_ci	if (ret) {
99862306a36Sopenharmony_ci		dev_err(pci->dev, "Invalid eDMA IRQs found\n");
99962306a36Sopenharmony_ci		return 0;
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	ret = dw_pcie_edma_ll_alloc(pci);
100362306a36Sopenharmony_ci	if (ret) {
100462306a36Sopenharmony_ci		dev_err(pci->dev, "Couldn't allocate LLP memory\n");
100562306a36Sopenharmony_ci		return ret;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	/* Don't fail if the DW eDMA driver can't find the device */
100962306a36Sopenharmony_ci	ret = dw_edma_probe(&pci->edma);
101062306a36Sopenharmony_ci	if (ret && ret != -ENODEV) {
101162306a36Sopenharmony_ci		dev_err(pci->dev, "Couldn't register eDMA device\n");
101262306a36Sopenharmony_ci		return ret;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
101662306a36Sopenharmony_ci		 pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
101762306a36Sopenharmony_ci		 pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return 0;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_civoid dw_pcie_edma_remove(struct dw_pcie *pci)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	dw_edma_remove(&pci->edma);
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_civoid dw_pcie_setup(struct dw_pcie *pci)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	u32 val;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (pci->link_gen > 0)
103262306a36Sopenharmony_ci		dw_pcie_link_set_max_speed(pci, pci->link_gen);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/* Configure Gen1 N_FTS */
103562306a36Sopenharmony_ci	if (pci->n_fts[0]) {
103662306a36Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
103762306a36Sopenharmony_ci		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
103862306a36Sopenharmony_ci		val |= PORT_AFR_N_FTS(pci->n_fts[0]);
103962306a36Sopenharmony_ci		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
104062306a36Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Configure Gen2+ N_FTS */
104462306a36Sopenharmony_ci	if (pci->n_fts[1]) {
104562306a36Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
104662306a36Sopenharmony_ci		val &= ~PORT_LOGIC_N_FTS_MASK;
104762306a36Sopenharmony_ci		val |= pci->n_fts[1];
104862306a36Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	if (dw_pcie_cap_is(pci, CDM_CHECK)) {
105262306a36Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
105362306a36Sopenharmony_ci		val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
105462306a36Sopenharmony_ci		       PCIE_PL_CHK_REG_CHK_REG_START;
105562306a36Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
105962306a36Sopenharmony_ci	val &= ~PORT_LINK_FAST_LINK_MODE;
106062306a36Sopenharmony_ci	val |= PORT_LINK_DLL_LINK_EN;
106162306a36Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
106462306a36Sopenharmony_ci}
1065