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