18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Synopsys DesignWare PCIe host controller driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd.
68c2ecf20Sopenharmony_ci *		https://www.samsung.com
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Author: Jingoo Han <jg1.han@samsung.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/of.h>
138c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "../../pci.h"
178c2ecf20Sopenharmony_ci#include "pcie-designware.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * These interfaces resemble the pci_find_*capability() interfaces, but these
218c2ecf20Sopenharmony_ci * are for configuring host controllers, which are bridges *to* PCI devices but
228c2ecf20Sopenharmony_ci * are not PCI devices themselves.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
258c2ecf20Sopenharmony_ci				  u8 cap)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	u8 cap_id, next_cap_ptr;
288c2ecf20Sopenharmony_ci	u16 reg;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (!cap_ptr)
318c2ecf20Sopenharmony_ci		return 0;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	reg = dw_pcie_readw_dbi(pci, cap_ptr);
348c2ecf20Sopenharmony_ci	cap_id = (reg & 0x00ff);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (cap_id > PCI_CAP_ID_MAX)
378c2ecf20Sopenharmony_ci		return 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (cap_id == cap)
408c2ecf20Sopenharmony_ci		return cap_ptr;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	next_cap_ptr = (reg & 0xff00) >> 8;
438c2ecf20Sopenharmony_ci	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciu8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u8 next_cap_ptr;
498c2ecf20Sopenharmony_ci	u16 reg;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
528c2ecf20Sopenharmony_ci	next_cap_ptr = (reg & 0x00ff);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_find_capability);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
598c2ecf20Sopenharmony_ci					    u8 cap)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	u32 header;
628c2ecf20Sopenharmony_ci	int ttl;
638c2ecf20Sopenharmony_ci	int pos = PCI_CFG_SPACE_SIZE;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* minimum 8 bytes per capability */
668c2ecf20Sopenharmony_ci	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (start)
698c2ecf20Sopenharmony_ci		pos = start;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	header = dw_pcie_readl_dbi(pci, pos);
728c2ecf20Sopenharmony_ci	/*
738c2ecf20Sopenharmony_ci	 * If we have no capabilities, this is indicated by cap ID,
748c2ecf20Sopenharmony_ci	 * cap version and next pointer all being 0.
758c2ecf20Sopenharmony_ci	 */
768c2ecf20Sopenharmony_ci	if (header == 0)
778c2ecf20Sopenharmony_ci		return 0;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	while (ttl-- > 0) {
808c2ecf20Sopenharmony_ci		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
818c2ecf20Sopenharmony_ci			return pos;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		pos = PCI_EXT_CAP_NEXT(header);
848c2ecf20Sopenharmony_ci		if (pos < PCI_CFG_SPACE_SIZE)
858c2ecf20Sopenharmony_ci			break;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		header = dw_pcie_readl_dbi(pci, pos);
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return 0;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciu16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	return dw_pcie_find_next_ext_capability(pci, 0, cap);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint dw_pcie_read(void __iomem *addr, int size, u32 *val)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)addr, size)) {
1028c2ecf20Sopenharmony_ci		*val = 0;
1038c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (size == 4) {
1078c2ecf20Sopenharmony_ci		*val = readl(addr);
1088c2ecf20Sopenharmony_ci	} else if (size == 2) {
1098c2ecf20Sopenharmony_ci		*val = readw(addr);
1108c2ecf20Sopenharmony_ci	} else if (size == 1) {
1118c2ecf20Sopenharmony_ci		*val = readb(addr);
1128c2ecf20Sopenharmony_ci	} else {
1138c2ecf20Sopenharmony_ci		*val = 0;
1148c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_read);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ciint dw_pcie_write(void __iomem *addr, int size, u32 val)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)addr, size))
1248c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (size == 4)
1278c2ecf20Sopenharmony_ci		writel(val, addr);
1288c2ecf20Sopenharmony_ci	else if (size == 2)
1298c2ecf20Sopenharmony_ci		writew(val, addr);
1308c2ecf20Sopenharmony_ci	else if (size == 1)
1318c2ecf20Sopenharmony_ci		writeb(val, addr);
1328c2ecf20Sopenharmony_ci	else
1338c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_write);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciu32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	int ret;
1428c2ecf20Sopenharmony_ci	u32 val;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (pci->ops->read_dbi)
1458c2ecf20Sopenharmony_ci		return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
1488c2ecf20Sopenharmony_ci	if (ret)
1498c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Read DBI address failed\n");
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return val;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_read_dbi);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_civoid dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	int ret;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (pci->ops->write_dbi) {
1608c2ecf20Sopenharmony_ci		pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
1618c2ecf20Sopenharmony_ci		return;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	ret = dw_pcie_write(pci->dbi_base + reg, size, val);
1658c2ecf20Sopenharmony_ci	if (ret)
1668c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Write DBI address failed\n");
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_civoid dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	int ret;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (pci->ops->write_dbi2) {
1758c2ecf20Sopenharmony_ci		pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
1768c2ecf20Sopenharmony_ci		return;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
1808c2ecf20Sopenharmony_ci	if (ret)
1818c2ecf20Sopenharmony_ci		dev_err(pci->dev, "write DBI address failed\n");
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	int ret;
1878c2ecf20Sopenharmony_ci	u32 val;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (pci->ops->read_dbi)
1908c2ecf20Sopenharmony_ci		return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
1938c2ecf20Sopenharmony_ci	if (ret)
1948c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Read ATU address failed\n");
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return val;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int ret;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (pci->ops->write_dbi) {
2048c2ecf20Sopenharmony_ci		pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
2058c2ecf20Sopenharmony_ci		return;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	ret = dw_pcie_write(pci->atu_base + reg, 4, val);
2098c2ecf20Sopenharmony_ci	if (ret)
2108c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Write ATU address failed\n");
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return dw_pcie_readl_atu(pci, offset + reg);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
2218c2ecf20Sopenharmony_ci				     u32 val)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	dw_pcie_writel_atu(pci, offset + reg, val);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
2298c2ecf20Sopenharmony_ci					     int index, int type,
2308c2ecf20Sopenharmony_ci					     u64 cpu_addr, u64 pci_addr,
2318c2ecf20Sopenharmony_ci					     u32 size)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	u32 retries, val;
2348c2ecf20Sopenharmony_ci	u64 limit_addr = cpu_addr + size - 1;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
2378c2ecf20Sopenharmony_ci				 lower_32_bits(cpu_addr));
2388c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
2398c2ecf20Sopenharmony_ci				 upper_32_bits(cpu_addr));
2408c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
2418c2ecf20Sopenharmony_ci				 lower_32_bits(limit_addr));
2428c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
2438c2ecf20Sopenharmony_ci				 upper_32_bits(limit_addr));
2448c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
2458c2ecf20Sopenharmony_ci				 lower_32_bits(pci_addr));
2468c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
2478c2ecf20Sopenharmony_ci				 upper_32_bits(pci_addr));
2488c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
2498c2ecf20Sopenharmony_ci				 type | PCIE_ATU_FUNC_NUM(func_no));
2508c2ecf20Sopenharmony_ci	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
2518c2ecf20Sopenharmony_ci				 PCIE_ATU_ENABLE);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/*
2548c2ecf20Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
2558c2ecf20Sopenharmony_ci	 * and I/O accesses.
2568c2ecf20Sopenharmony_ci	 */
2578c2ecf20Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
2588c2ecf20Sopenharmony_ci		val = dw_pcie_readl_ob_unroll(pci, index,
2598c2ecf20Sopenharmony_ci					      PCIE_ATU_UNR_REGION_CTRL2);
2608c2ecf20Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
2618c2ecf20Sopenharmony_ci			return;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
2698c2ecf20Sopenharmony_ci					int index, int type, u64 cpu_addr,
2708c2ecf20Sopenharmony_ci					u64 pci_addr, u32 size)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	u32 retries, val;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (pci->ops->cpu_addr_fixup)
2758c2ecf20Sopenharmony_ci		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (pci->iatu_unroll_enabled) {
2788c2ecf20Sopenharmony_ci		dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
2798c2ecf20Sopenharmony_ci						 cpu_addr, pci_addr, size);
2808c2ecf20Sopenharmony_ci		return;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
2848c2ecf20Sopenharmony_ci			   PCIE_ATU_REGION_OUTBOUND | index);
2858c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
2868c2ecf20Sopenharmony_ci			   lower_32_bits(cpu_addr));
2878c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
2888c2ecf20Sopenharmony_ci			   upper_32_bits(cpu_addr));
2898c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
2908c2ecf20Sopenharmony_ci			   lower_32_bits(cpu_addr + size - 1));
2918c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
2928c2ecf20Sopenharmony_ci			   lower_32_bits(pci_addr));
2938c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
2948c2ecf20Sopenharmony_ci			   upper_32_bits(pci_addr));
2958c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
2968c2ecf20Sopenharmony_ci			   PCIE_ATU_FUNC_NUM(func_no));
2978c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
3018c2ecf20Sopenharmony_ci	 * and I/O accesses.
3028c2ecf20Sopenharmony_ci	 */
3038c2ecf20Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
3048c2ecf20Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
3058c2ecf20Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
3068c2ecf20Sopenharmony_ci			return;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_civoid dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
3148c2ecf20Sopenharmony_ci			       u64 cpu_addr, u64 pci_addr, u32 size)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
3178c2ecf20Sopenharmony_ci				    cpu_addr, pci_addr, size);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_civoid dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
3218c2ecf20Sopenharmony_ci				  int type, u64 cpu_addr, u64 pci_addr,
3228c2ecf20Sopenharmony_ci				  u32 size)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	__dw_pcie_prog_outbound_atu(pci, func_no, index, type,
3258c2ecf20Sopenharmony_ci				    cpu_addr, pci_addr, size);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return dw_pcie_readl_atu(pci, offset + reg);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
3368c2ecf20Sopenharmony_ci				     u32 val)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	dw_pcie_writel_atu(pci, offset + reg, val);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
3448c2ecf20Sopenharmony_ci					   int index, int bar, u64 cpu_addr,
3458c2ecf20Sopenharmony_ci					   enum dw_pcie_as_type as_type)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	int type;
3488c2ecf20Sopenharmony_ci	u32 retries, val;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
3518c2ecf20Sopenharmony_ci				 lower_32_bits(cpu_addr));
3528c2ecf20Sopenharmony_ci	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
3538c2ecf20Sopenharmony_ci				 upper_32_bits(cpu_addr));
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	switch (as_type) {
3568c2ecf20Sopenharmony_ci	case DW_PCIE_AS_MEM:
3578c2ecf20Sopenharmony_ci		type = PCIE_ATU_TYPE_MEM;
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case DW_PCIE_AS_IO:
3608c2ecf20Sopenharmony_ci		type = PCIE_ATU_TYPE_IO;
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	default:
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
3678c2ecf20Sopenharmony_ci				 PCIE_ATU_FUNC_NUM(func_no));
3688c2ecf20Sopenharmony_ci	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
3698c2ecf20Sopenharmony_ci				 PCIE_ATU_FUNC_NUM_MATCH_EN |
3708c2ecf20Sopenharmony_ci				 PCIE_ATU_ENABLE |
3718c2ecf20Sopenharmony_ci				 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/*
3748c2ecf20Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
3758c2ecf20Sopenharmony_ci	 * and I/O accesses.
3768c2ecf20Sopenharmony_ci	 */
3778c2ecf20Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
3788c2ecf20Sopenharmony_ci		val = dw_pcie_readl_ib_unroll(pci, index,
3798c2ecf20Sopenharmony_ci					      PCIE_ATU_UNR_REGION_CTRL2);
3808c2ecf20Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
3818c2ecf20Sopenharmony_ci			return 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return -EBUSY;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciint dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
3918c2ecf20Sopenharmony_ci			     int bar, u64 cpu_addr,
3928c2ecf20Sopenharmony_ci			     enum dw_pcie_as_type as_type)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	int type;
3958c2ecf20Sopenharmony_ci	u32 retries, val;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (pci->iatu_unroll_enabled)
3988c2ecf20Sopenharmony_ci		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
3998c2ecf20Sopenharmony_ci						       cpu_addr, as_type);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
4028c2ecf20Sopenharmony_ci			   index);
4038c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
4048c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	switch (as_type) {
4078c2ecf20Sopenharmony_ci	case DW_PCIE_AS_MEM:
4088c2ecf20Sopenharmony_ci		type = PCIE_ATU_TYPE_MEM;
4098c2ecf20Sopenharmony_ci		break;
4108c2ecf20Sopenharmony_ci	case DW_PCIE_AS_IO:
4118c2ecf20Sopenharmony_ci		type = PCIE_ATU_TYPE_IO;
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	default:
4148c2ecf20Sopenharmony_ci		return -EINVAL;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
4188c2ecf20Sopenharmony_ci			   PCIE_ATU_FUNC_NUM(func_no));
4198c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
4208c2ecf20Sopenharmony_ci			   PCIE_ATU_FUNC_NUM_MATCH_EN |
4218c2ecf20Sopenharmony_ci			   PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * Make sure ATU enable takes effect before any subsequent config
4258c2ecf20Sopenharmony_ci	 * and I/O accesses.
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
4288c2ecf20Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
4298c2ecf20Sopenharmony_ci		if (val & PCIE_ATU_ENABLE)
4308c2ecf20Sopenharmony_ci			return 0;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		mdelay(LINK_WAIT_IATU);
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return -EBUSY;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_civoid dw_pcie_disable_atu(struct dw_pcie *pci, int index,
4408c2ecf20Sopenharmony_ci			 enum dw_pcie_region_type type)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	u32 region;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	switch (type) {
4458c2ecf20Sopenharmony_ci	case DW_PCIE_REGION_INBOUND:
4468c2ecf20Sopenharmony_ci		region = PCIE_ATU_REGION_INBOUND;
4478c2ecf20Sopenharmony_ci		break;
4488c2ecf20Sopenharmony_ci	case DW_PCIE_REGION_OUTBOUND:
4498c2ecf20Sopenharmony_ci		region = PCIE_ATU_REGION_OUTBOUND;
4508c2ecf20Sopenharmony_ci		break;
4518c2ecf20Sopenharmony_ci	default:
4528c2ecf20Sopenharmony_ci		return;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (pci->iatu_unroll_enabled) {
4568c2ecf20Sopenharmony_ci		if (region == PCIE_ATU_REGION_INBOUND) {
4578c2ecf20Sopenharmony_ci			dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
4588c2ecf20Sopenharmony_ci						 ~(u32)PCIE_ATU_ENABLE);
4598c2ecf20Sopenharmony_ci		} else {
4608c2ecf20Sopenharmony_ci			dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
4618c2ecf20Sopenharmony_ci						 ~(u32)PCIE_ATU_ENABLE);
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci	} else {
4648c2ecf20Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
4658c2ecf20Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ciint dw_pcie_wait_for_link(struct dw_pcie *pci)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int retries;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* Check if the link is up or not */
4748c2ecf20Sopenharmony_ci	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
4758c2ecf20Sopenharmony_ci		if (dw_pcie_link_up(pci)) {
4768c2ecf20Sopenharmony_ci			dev_info(pci->dev, "Link up\n");
4778c2ecf20Sopenharmony_ci			return 0;
4788c2ecf20Sopenharmony_ci		}
4798c2ecf20Sopenharmony_ci		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	dev_info(pci->dev, "Phy link never came up\n");
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_wait_for_link);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ciint dw_pcie_link_up(struct dw_pcie *pci)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	u32 val;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (pci->ops->link_up)
4938c2ecf20Sopenharmony_ci		return pci->ops->link_up(pci);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	val = readl(pci->dbi_base + PCIE_PORT_DEBUG1);
4968c2ecf20Sopenharmony_ci	return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
4978c2ecf20Sopenharmony_ci		(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_civoid dw_pcie_upconfig_setup(struct dw_pcie *pci)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	u32 val;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL);
5058c2ecf20Sopenharmony_ci	val |= PORT_MLTI_UPCFG_SUPPORT;
5068c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val);
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	u32 cap, ctrl2, link_speed;
5138c2ecf20Sopenharmony_ci	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
5168c2ecf20Sopenharmony_ci	ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
5178c2ecf20Sopenharmony_ci	ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	switch (pcie_link_speed[link_gen]) {
5208c2ecf20Sopenharmony_ci	case PCIE_SPEED_2_5GT:
5218c2ecf20Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	case PCIE_SPEED_5_0GT:
5248c2ecf20Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
5258c2ecf20Sopenharmony_ci		break;
5268c2ecf20Sopenharmony_ci	case PCIE_SPEED_8_0GT:
5278c2ecf20Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
5288c2ecf20Sopenharmony_ci		break;
5298c2ecf20Sopenharmony_ci	case PCIE_SPEED_16_0GT:
5308c2ecf20Sopenharmony_ci		link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	default:
5338c2ecf20Sopenharmony_ci		/* Use hardware capability */
5348c2ecf20Sopenharmony_ci		link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
5358c2ecf20Sopenharmony_ci		ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
5368c2ecf20Sopenharmony_ci		break;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
5428c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	u32 val;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
5518c2ecf20Sopenharmony_ci	if (val == 0xffffffff)
5528c2ecf20Sopenharmony_ci		return 1;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return 0;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_civoid dw_pcie_setup(struct dw_pcie *pci)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	u32 val;
5608c2ecf20Sopenharmony_ci	struct device *dev = pci->dev;
5618c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
5628c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (pci->version >= 0x480A || (!pci->version &&
5658c2ecf20Sopenharmony_ci				       dw_pcie_iatu_unroll_enabled(pci))) {
5668c2ecf20Sopenharmony_ci		pci->iatu_unroll_enabled = true;
5678c2ecf20Sopenharmony_ci		if (!pci->atu_base)
5688c2ecf20Sopenharmony_ci			pci->atu_base =
5698c2ecf20Sopenharmony_ci			    devm_platform_ioremap_resource_byname(pdev, "atu");
5708c2ecf20Sopenharmony_ci		if (IS_ERR(pci->atu_base))
5718c2ecf20Sopenharmony_ci			pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
5748c2ecf20Sopenharmony_ci		"enabled" : "disabled");
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (pci->link_gen > 0)
5778c2ecf20Sopenharmony_ci		dw_pcie_link_set_max_speed(pci, pci->link_gen);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* Configure Gen1 N_FTS */
5808c2ecf20Sopenharmony_ci	if (pci->n_fts[0]) {
5818c2ecf20Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
5828c2ecf20Sopenharmony_ci		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
5838c2ecf20Sopenharmony_ci		val |= PORT_AFR_N_FTS(pci->n_fts[0]);
5848c2ecf20Sopenharmony_ci		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
5858c2ecf20Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Configure Gen2+ N_FTS */
5898c2ecf20Sopenharmony_ci	if (pci->n_fts[1]) {
5908c2ecf20Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
5918c2ecf20Sopenharmony_ci		val &= ~PORT_LOGIC_N_FTS_MASK;
5928c2ecf20Sopenharmony_ci		val |= pci->n_fts[1];
5938c2ecf20Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
5978c2ecf20Sopenharmony_ci	val &= ~PORT_LINK_FAST_LINK_MODE;
5988c2ecf20Sopenharmony_ci	val |= PORT_LINK_DLL_LINK_EN;
5998c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "snps,enable-cdm-check")) {
6028c2ecf20Sopenharmony_ci		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
6038c2ecf20Sopenharmony_ci		val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
6048c2ecf20Sopenharmony_ci		       PCIE_PL_CHK_REG_CHK_REG_START;
6058c2ecf20Sopenharmony_ci		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	of_property_read_u32(np, "num-lanes", &pci->num_lanes);
6098c2ecf20Sopenharmony_ci	if (!pci->num_lanes) {
6108c2ecf20Sopenharmony_ci		dev_dbg(pci->dev, "Using h/w default number of lanes\n");
6118c2ecf20Sopenharmony_ci		return;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* Set the number of lanes */
6158c2ecf20Sopenharmony_ci	val &= ~PORT_LINK_FAST_LINK_MODE;
6168c2ecf20Sopenharmony_ci	val &= ~PORT_LINK_MODE_MASK;
6178c2ecf20Sopenharmony_ci	switch (pci->num_lanes) {
6188c2ecf20Sopenharmony_ci	case 1:
6198c2ecf20Sopenharmony_ci		val |= PORT_LINK_MODE_1_LANES;
6208c2ecf20Sopenharmony_ci		break;
6218c2ecf20Sopenharmony_ci	case 2:
6228c2ecf20Sopenharmony_ci		val |= PORT_LINK_MODE_2_LANES;
6238c2ecf20Sopenharmony_ci		break;
6248c2ecf20Sopenharmony_ci	case 4:
6258c2ecf20Sopenharmony_ci		val |= PORT_LINK_MODE_4_LANES;
6268c2ecf20Sopenharmony_ci		break;
6278c2ecf20Sopenharmony_ci	case 8:
6288c2ecf20Sopenharmony_ci		val |= PORT_LINK_MODE_8_LANES;
6298c2ecf20Sopenharmony_ci		break;
6308c2ecf20Sopenharmony_ci	default:
6318c2ecf20Sopenharmony_ci		dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
6328c2ecf20Sopenharmony_ci		return;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* Set link width speed control register */
6378c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
6388c2ecf20Sopenharmony_ci	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
6398c2ecf20Sopenharmony_ci	switch (pci->num_lanes) {
6408c2ecf20Sopenharmony_ci	case 1:
6418c2ecf20Sopenharmony_ci		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
6428c2ecf20Sopenharmony_ci		break;
6438c2ecf20Sopenharmony_ci	case 2:
6448c2ecf20Sopenharmony_ci		val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
6458c2ecf20Sopenharmony_ci		break;
6468c2ecf20Sopenharmony_ci	case 4:
6478c2ecf20Sopenharmony_ci		val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
6488c2ecf20Sopenharmony_ci		break;
6498c2ecf20Sopenharmony_ci	case 8:
6508c2ecf20Sopenharmony_ci		val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
6518c2ecf20Sopenharmony_ci		break;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
6548c2ecf20Sopenharmony_ci}
655