18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008, 2009, 2010, 2011 Cavium Networks 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/pci.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/time.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h> 178c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-npei-defs.h> 188c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pciercx-defs.h> 198c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pescx-defs.h> 208c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pexp-defs.h> 218c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pemx-defs.h> 228c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-dpi-defs.h> 238c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-sli-defs.h> 248c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-sriox-defs.h> 258c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-helper-errata.h> 268c2ecf20Sopenharmony_ci#include <asm/octeon/pci-octeon.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */ 298c2ecf20Sopenharmony_ci#define MPS_CN5XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ 308c2ecf20Sopenharmony_ci#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */ 318c2ecf20Sopenharmony_ci#define MPS_CN6XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Module parameter to disable PCI probing */ 348c2ecf20Sopenharmony_cistatic int pcie_disable; 358c2ecf20Sopenharmony_cimodule_param(pcie_disable, int, S_IRUGO); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int enable_pcie_14459_war; 388c2ecf20Sopenharmony_cistatic int enable_pcie_bus_num_war[2]; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciunion cvmx_pcie_address { 418c2ecf20Sopenharmony_ci uint64_t u64; 428c2ecf20Sopenharmony_ci struct { 438c2ecf20Sopenharmony_ci uint64_t upper:2; /* Normally 2 for XKPHYS */ 448c2ecf20Sopenharmony_ci uint64_t reserved_49_61:13; /* Must be zero */ 458c2ecf20Sopenharmony_ci uint64_t io:1; /* 1 for IO space access */ 468c2ecf20Sopenharmony_ci uint64_t did:5; /* PCIe DID = 3 */ 478c2ecf20Sopenharmony_ci uint64_t subdid:3; /* PCIe SubDID = 1 */ 488c2ecf20Sopenharmony_ci uint64_t reserved_36_39:4; /* Must be zero */ 498c2ecf20Sopenharmony_ci uint64_t es:2; /* Endian swap = 1 */ 508c2ecf20Sopenharmony_ci uint64_t port:2; /* PCIe port 0,1 */ 518c2ecf20Sopenharmony_ci uint64_t reserved_29_31:3; /* Must be zero */ 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * Selects the type of the configuration request (0 = type 0, 548c2ecf20Sopenharmony_ci * 1 = type 1). 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci uint64_t ty:1; 578c2ecf20Sopenharmony_ci /* Target bus number sent in the ID in the request. */ 588c2ecf20Sopenharmony_ci uint64_t bus:8; 598c2ecf20Sopenharmony_ci /* 608c2ecf20Sopenharmony_ci * Target device number sent in the ID in the 618c2ecf20Sopenharmony_ci * request. Note that Dev must be zero for type 0 628c2ecf20Sopenharmony_ci * configuration requests. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci uint64_t dev:5; 658c2ecf20Sopenharmony_ci /* Target function number sent in the ID in the request. */ 668c2ecf20Sopenharmony_ci uint64_t func:3; 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * Selects a register in the configuration space of 698c2ecf20Sopenharmony_ci * the target. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci uint64_t reg:12; 728c2ecf20Sopenharmony_ci } config; 738c2ecf20Sopenharmony_ci struct { 748c2ecf20Sopenharmony_ci uint64_t upper:2; /* Normally 2 for XKPHYS */ 758c2ecf20Sopenharmony_ci uint64_t reserved_49_61:13; /* Must be zero */ 768c2ecf20Sopenharmony_ci uint64_t io:1; /* 1 for IO space access */ 778c2ecf20Sopenharmony_ci uint64_t did:5; /* PCIe DID = 3 */ 788c2ecf20Sopenharmony_ci uint64_t subdid:3; /* PCIe SubDID = 2 */ 798c2ecf20Sopenharmony_ci uint64_t reserved_36_39:4; /* Must be zero */ 808c2ecf20Sopenharmony_ci uint64_t es:2; /* Endian swap = 1 */ 818c2ecf20Sopenharmony_ci uint64_t port:2; /* PCIe port 0,1 */ 828c2ecf20Sopenharmony_ci uint64_t address:32; /* PCIe IO address */ 838c2ecf20Sopenharmony_ci } io; 848c2ecf20Sopenharmony_ci struct { 858c2ecf20Sopenharmony_ci uint64_t upper:2; /* Normally 2 for XKPHYS */ 868c2ecf20Sopenharmony_ci uint64_t reserved_49_61:13; /* Must be zero */ 878c2ecf20Sopenharmony_ci uint64_t io:1; /* 1 for IO space access */ 888c2ecf20Sopenharmony_ci uint64_t did:5; /* PCIe DID = 3 */ 898c2ecf20Sopenharmony_ci uint64_t subdid:3; /* PCIe SubDID = 3-6 */ 908c2ecf20Sopenharmony_ci uint64_t reserved_36_39:4; /* Must be zero */ 918c2ecf20Sopenharmony_ci uint64_t address:36; /* PCIe Mem address */ 928c2ecf20Sopenharmony_ci } mem; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int cvmx_pcie_rc_initialize(int pcie_port); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/** 988c2ecf20Sopenharmony_ci * Return the Core virtual base address for PCIe IO access. IOs are 998c2ecf20Sopenharmony_ci * read/written as an offset from this address. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the IO is for 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Returns 64bit Octeon IO base address for read/write 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic inline uint64_t cvmx_pcie_get_io_base_address(int pcie_port) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci union cvmx_pcie_address pcie_addr; 1088c2ecf20Sopenharmony_ci pcie_addr.u64 = 0; 1098c2ecf20Sopenharmony_ci pcie_addr.io.upper = 0; 1108c2ecf20Sopenharmony_ci pcie_addr.io.io = 1; 1118c2ecf20Sopenharmony_ci pcie_addr.io.did = 3; 1128c2ecf20Sopenharmony_ci pcie_addr.io.subdid = 2; 1138c2ecf20Sopenharmony_ci pcie_addr.io.es = 1; 1148c2ecf20Sopenharmony_ci pcie_addr.io.port = pcie_port; 1158c2ecf20Sopenharmony_ci return pcie_addr.u64; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * Size of the IO address region returned at address 1208c2ecf20Sopenharmony_ci * cvmx_pcie_get_io_base_address() 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the IO is for 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * Returns Size of the IO window 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic inline uint64_t cvmx_pcie_get_io_size(int pcie_port) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return 1ull << 32; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * Return the Core virtual base address for PCIe MEM access. Memory is 1338c2ecf20Sopenharmony_ci * read/written as an offset from this address. 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the IO is for 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * Returns 64bit Octeon IO base address for read/write 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cistatic inline uint64_t cvmx_pcie_get_mem_base_address(int pcie_port) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci union cvmx_pcie_address pcie_addr; 1428c2ecf20Sopenharmony_ci pcie_addr.u64 = 0; 1438c2ecf20Sopenharmony_ci pcie_addr.mem.upper = 0; 1448c2ecf20Sopenharmony_ci pcie_addr.mem.io = 1; 1458c2ecf20Sopenharmony_ci pcie_addr.mem.did = 3; 1468c2ecf20Sopenharmony_ci pcie_addr.mem.subdid = 3 + pcie_port; 1478c2ecf20Sopenharmony_ci return pcie_addr.u64; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/** 1518c2ecf20Sopenharmony_ci * Size of the Mem address region returned at address 1528c2ecf20Sopenharmony_ci * cvmx_pcie_get_mem_base_address() 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the IO is for 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * Returns Size of the Mem window 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic inline uint64_t cvmx_pcie_get_mem_size(int pcie_port) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return 1ull << 36; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/** 1648c2ecf20Sopenharmony_ci * Read a PCIe config space register indirectly. This is used for 1658c2ecf20Sopenharmony_ci * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to read from 1688c2ecf20Sopenharmony_ci * @cfg_offset: Address to read 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Returns Value read 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_cistatic uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { 1758c2ecf20Sopenharmony_ci union cvmx_pescx_cfg_rd pescx_cfg_rd; 1768c2ecf20Sopenharmony_ci pescx_cfg_rd.u64 = 0; 1778c2ecf20Sopenharmony_ci pescx_cfg_rd.s.addr = cfg_offset; 1788c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); 1798c2ecf20Sopenharmony_ci pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); 1808c2ecf20Sopenharmony_ci return pescx_cfg_rd.s.data; 1818c2ecf20Sopenharmony_ci } else { 1828c2ecf20Sopenharmony_ci union cvmx_pemx_cfg_rd pemx_cfg_rd; 1838c2ecf20Sopenharmony_ci pemx_cfg_rd.u64 = 0; 1848c2ecf20Sopenharmony_ci pemx_cfg_rd.s.addr = cfg_offset; 1858c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64); 1868c2ecf20Sopenharmony_ci pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port)); 1878c2ecf20Sopenharmony_ci return pemx_cfg_rd.s.data; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/** 1928c2ecf20Sopenharmony_ci * Write a PCIe config space register indirectly. This is used for 1938c2ecf20Sopenharmony_ci * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to write to 1968c2ecf20Sopenharmony_ci * @cfg_offset: Address to write 1978c2ecf20Sopenharmony_ci * @val: Value to write 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, 2008c2ecf20Sopenharmony_ci uint32_t val) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { 2038c2ecf20Sopenharmony_ci union cvmx_pescx_cfg_wr pescx_cfg_wr; 2048c2ecf20Sopenharmony_ci pescx_cfg_wr.u64 = 0; 2058c2ecf20Sopenharmony_ci pescx_cfg_wr.s.addr = cfg_offset; 2068c2ecf20Sopenharmony_ci pescx_cfg_wr.s.data = val; 2078c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); 2088c2ecf20Sopenharmony_ci } else { 2098c2ecf20Sopenharmony_ci union cvmx_pemx_cfg_wr pemx_cfg_wr; 2108c2ecf20Sopenharmony_ci pemx_cfg_wr.u64 = 0; 2118c2ecf20Sopenharmony_ci pemx_cfg_wr.s.addr = cfg_offset; 2128c2ecf20Sopenharmony_ci pemx_cfg_wr.s.data = val; 2138c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/** 2188c2ecf20Sopenharmony_ci * Build a PCIe config space request address for a device 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to access 2218c2ecf20Sopenharmony_ci * @bus: Sub bus 2228c2ecf20Sopenharmony_ci * @dev: Device ID 2238c2ecf20Sopenharmony_ci * @fn: Device sub function 2248c2ecf20Sopenharmony_ci * @reg: Register to access 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Returns 64bit Octeon IO address 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, 2298c2ecf20Sopenharmony_ci int dev, int fn, int reg) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci union cvmx_pcie_address pcie_addr; 2328c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg006 pciercx_cfg006; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci pciercx_cfg006.u32 = 2358c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port)); 2368c2ecf20Sopenharmony_ci if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0)) 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci pcie_addr.u64 = 0; 2408c2ecf20Sopenharmony_ci pcie_addr.config.upper = 2; 2418c2ecf20Sopenharmony_ci pcie_addr.config.io = 1; 2428c2ecf20Sopenharmony_ci pcie_addr.config.did = 3; 2438c2ecf20Sopenharmony_ci pcie_addr.config.subdid = 1; 2448c2ecf20Sopenharmony_ci pcie_addr.config.es = 1; 2458c2ecf20Sopenharmony_ci pcie_addr.config.port = pcie_port; 2468c2ecf20Sopenharmony_ci pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum); 2478c2ecf20Sopenharmony_ci pcie_addr.config.bus = bus; 2488c2ecf20Sopenharmony_ci pcie_addr.config.dev = dev; 2498c2ecf20Sopenharmony_ci pcie_addr.config.func = fn; 2508c2ecf20Sopenharmony_ci pcie_addr.config.reg = reg; 2518c2ecf20Sopenharmony_ci return pcie_addr.u64; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * Read 8bits from a Device's config space 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 2588c2ecf20Sopenharmony_ci * @bus: Sub bus 2598c2ecf20Sopenharmony_ci * @dev: Device ID 2608c2ecf20Sopenharmony_ci * @fn: Device sub function 2618c2ecf20Sopenharmony_ci * @reg: Register to access 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Returns Result of the read 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic uint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, 2668c2ecf20Sopenharmony_ci int fn, int reg) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci uint64_t address = 2698c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 2708c2ecf20Sopenharmony_ci if (address) 2718c2ecf20Sopenharmony_ci return cvmx_read64_uint8(address); 2728c2ecf20Sopenharmony_ci else 2738c2ecf20Sopenharmony_ci return 0xff; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * Read 16bits from a Device's config space 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 2808c2ecf20Sopenharmony_ci * @bus: Sub bus 2818c2ecf20Sopenharmony_ci * @dev: Device ID 2828c2ecf20Sopenharmony_ci * @fn: Device sub function 2838c2ecf20Sopenharmony_ci * @reg: Register to access 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * Returns Result of the read 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_cistatic uint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, 2888c2ecf20Sopenharmony_ci int fn, int reg) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci uint64_t address = 2918c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 2928c2ecf20Sopenharmony_ci if (address) 2938c2ecf20Sopenharmony_ci return le16_to_cpu(cvmx_read64_uint16(address)); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci return 0xffff; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/** 2998c2ecf20Sopenharmony_ci * Read 32bits from a Device's config space 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 3028c2ecf20Sopenharmony_ci * @bus: Sub bus 3038c2ecf20Sopenharmony_ci * @dev: Device ID 3048c2ecf20Sopenharmony_ci * @fn: Device sub function 3058c2ecf20Sopenharmony_ci * @reg: Register to access 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Returns Result of the read 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic uint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, 3108c2ecf20Sopenharmony_ci int fn, int reg) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci uint64_t address = 3138c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 3148c2ecf20Sopenharmony_ci if (address) 3158c2ecf20Sopenharmony_ci return le32_to_cpu(cvmx_read64_uint32(address)); 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci return 0xffffffff; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * Write 8bits to a Device's config space 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 3248c2ecf20Sopenharmony_ci * @bus: Sub bus 3258c2ecf20Sopenharmony_ci * @dev: Device ID 3268c2ecf20Sopenharmony_ci * @fn: Device sub function 3278c2ecf20Sopenharmony_ci * @reg: Register to access 3288c2ecf20Sopenharmony_ci * @val: Value to write 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, 3318c2ecf20Sopenharmony_ci int reg, uint8_t val) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci uint64_t address = 3348c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 3358c2ecf20Sopenharmony_ci if (address) 3368c2ecf20Sopenharmony_ci cvmx_write64_uint8(address, val); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * Write 16bits to a Device's config space 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 3438c2ecf20Sopenharmony_ci * @bus: Sub bus 3448c2ecf20Sopenharmony_ci * @dev: Device ID 3458c2ecf20Sopenharmony_ci * @fn: Device sub function 3468c2ecf20Sopenharmony_ci * @reg: Register to access 3478c2ecf20Sopenharmony_ci * @val: Value to write 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_cistatic void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, 3508c2ecf20Sopenharmony_ci int reg, uint16_t val) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci uint64_t address = 3538c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 3548c2ecf20Sopenharmony_ci if (address) 3558c2ecf20Sopenharmony_ci cvmx_write64_uint16(address, cpu_to_le16(val)); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/** 3598c2ecf20Sopenharmony_ci * Write 32bits to a Device's config space 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * @pcie_port: PCIe port the device is on 3628c2ecf20Sopenharmony_ci * @bus: Sub bus 3638c2ecf20Sopenharmony_ci * @dev: Device ID 3648c2ecf20Sopenharmony_ci * @fn: Device sub function 3658c2ecf20Sopenharmony_ci * @reg: Register to access 3668c2ecf20Sopenharmony_ci * @val: Value to write 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_cistatic void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, 3698c2ecf20Sopenharmony_ci int reg, uint32_t val) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci uint64_t address = 3728c2ecf20Sopenharmony_ci __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 3738c2ecf20Sopenharmony_ci if (address) 3748c2ecf20Sopenharmony_ci cvmx_write64_uint32(address, cpu_to_le32(val)); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/** 3788c2ecf20Sopenharmony_ci * Initialize the RC config space CSRs 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistatic void __cvmx_pcie_rc_initialize_config_space(int pcie_port) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg030 pciercx_cfg030; 3858c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg070 pciercx_cfg070; 3868c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg001 pciercx_cfg001; 3878c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg032 pciercx_cfg032; 3888c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg006 pciercx_cfg006; 3898c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg008 pciercx_cfg008; 3908c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg009 pciercx_cfg009; 3918c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg010 pciercx_cfg010; 3928c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg011 pciercx_cfg011; 3938c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg035 pciercx_cfg035; 3948c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg075 pciercx_cfg075; 3958c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg034 pciercx_cfg034; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Max Payload Size (PCIE*_CFG030[MPS]) */ 3988c2ecf20Sopenharmony_ci /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ 3998c2ecf20Sopenharmony_ci /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ 4008c2ecf20Sopenharmony_ci /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); 4038c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { 4048c2ecf20Sopenharmony_ci pciercx_cfg030.s.mps = MPS_CN5XXX; 4058c2ecf20Sopenharmony_ci pciercx_cfg030.s.mrrs = MRRS_CN5XXX; 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci pciercx_cfg030.s.mps = MPS_CN6XXX; 4088c2ecf20Sopenharmony_ci pciercx_cfg030.s.mrrs = MRRS_CN6XXX; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci * Enable relaxed order processing. This will allow devices to 4128c2ecf20Sopenharmony_ci * affect read response ordering. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci pciercx_cfg030.s.ro_en = 1; 4158c2ecf20Sopenharmony_ci /* Enable no snoop processing. Not used by Octeon */ 4168c2ecf20Sopenharmony_ci pciercx_cfg030.s.ns_en = 1; 4178c2ecf20Sopenharmony_ci /* Correctable error reporting enable. */ 4188c2ecf20Sopenharmony_ci pciercx_cfg030.s.ce_en = 1; 4198c2ecf20Sopenharmony_ci /* Non-fatal error reporting enable. */ 4208c2ecf20Sopenharmony_ci pciercx_cfg030.s.nfe_en = 1; 4218c2ecf20Sopenharmony_ci /* Fatal error reporting enable. */ 4228c2ecf20Sopenharmony_ci pciercx_cfg030.s.fe_en = 1; 4238c2ecf20Sopenharmony_ci /* Unsupported request reporting enable. */ 4248c2ecf20Sopenharmony_ci pciercx_cfg030.s.ur_en = 1; 4258c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { 4298c2ecf20Sopenharmony_ci union cvmx_npei_ctl_status2 npei_ctl_status2; 4308c2ecf20Sopenharmony_ci /* 4318c2ecf20Sopenharmony_ci * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match 4328c2ecf20Sopenharmony_ci * PCIE*_CFG030[MPS]. Max Read Request Size 4338c2ecf20Sopenharmony_ci * (NPEI_CTL_STATUS2[MRRS]) must not exceed 4348c2ecf20Sopenharmony_ci * PCIE*_CFG030[MRRS] 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); 4378c2ecf20Sopenharmony_ci /* Max payload size = 128 bytes for best Octeon DMA performance */ 4388c2ecf20Sopenharmony_ci npei_ctl_status2.s.mps = MPS_CN5XXX; 4398c2ecf20Sopenharmony_ci /* Max read request size = 128 bytes for best Octeon DMA performance */ 4408c2ecf20Sopenharmony_ci npei_ctl_status2.s.mrrs = MRRS_CN5XXX; 4418c2ecf20Sopenharmony_ci if (pcie_port) 4428c2ecf20Sopenharmony_ci npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ 4438c2ecf20Sopenharmony_ci else 4448c2ecf20Sopenharmony_ci npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); 4478c2ecf20Sopenharmony_ci } else { 4488c2ecf20Sopenharmony_ci /* 4498c2ecf20Sopenharmony_ci * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match 4508c2ecf20Sopenharmony_ci * PCIE*_CFG030[MPS]. Max Read Request Size 4518c2ecf20Sopenharmony_ci * (DPI_SLI_PRTX_CFG[MRRS]) must not exceed 4528c2ecf20Sopenharmony_ci * PCIE*_CFG030[MRRS]. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci union cvmx_dpi_sli_prtx_cfg prt_cfg; 4558c2ecf20Sopenharmony_ci union cvmx_sli_s2m_portx_ctl sli_s2m_portx_ctl; 4568c2ecf20Sopenharmony_ci prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); 4578c2ecf20Sopenharmony_ci prt_cfg.s.mps = MPS_CN6XXX; 4588c2ecf20Sopenharmony_ci prt_cfg.s.mrrs = MRRS_CN6XXX; 4598c2ecf20Sopenharmony_ci /* Max outstanding load request. */ 4608c2ecf20Sopenharmony_ci prt_cfg.s.molr = 32; 4618c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); 4648c2ecf20Sopenharmony_ci sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX; 4658c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ 4698c2ecf20Sopenharmony_ci pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); 4708c2ecf20Sopenharmony_ci pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ 4718c2ecf20Sopenharmony_ci pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ 4728c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * Access Enables (PCIE*_CFG001[MSAE,ME]) 4768c2ecf20Sopenharmony_ci * ME and MSAE should always be set. 4778c2ecf20Sopenharmony_ci * Interrupt Disable (PCIE*_CFG001[I_DIS]) 4788c2ecf20Sopenharmony_ci * System Error Message Enable (PCIE*_CFG001[SEE]) 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); 4818c2ecf20Sopenharmony_ci pciercx_cfg001.s.msae = 1; /* Memory space enable. */ 4828c2ecf20Sopenharmony_ci pciercx_cfg001.s.me = 1; /* Bus master enable. */ 4838c2ecf20Sopenharmony_ci pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ 4848c2ecf20Sopenharmony_ci pciercx_cfg001.s.see = 1; /* SERR# enable */ 4858c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Advanced Error Recovery Message Enables */ 4888c2ecf20Sopenharmony_ci /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ 4898c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0); 4908c2ecf20Sopenharmony_ci /* Use CVMX_PCIERCX_CFG067 hardware default */ 4918c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ 4958c2ecf20Sopenharmony_ci pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 4968c2ecf20Sopenharmony_ci pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ 4978c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * Link Width Mode (PCIERCn_CFG452[LME]) - Set during 5018c2ecf20Sopenharmony_ci * cvmx_pcie_rc_initialize_link() 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * Primary Bus Number (PCIERCn_CFG006[PBNUM]) 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci * We set the primary bus number to 1 so IDT bridges are 5068c2ecf20Sopenharmony_ci * happy. They don't like zero. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci pciercx_cfg006.u32 = 0; 5098c2ecf20Sopenharmony_ci pciercx_cfg006.s.pbnum = 1; 5108c2ecf20Sopenharmony_ci pciercx_cfg006.s.sbnum = 1; 5118c2ecf20Sopenharmony_ci pciercx_cfg006.s.subbnum = 1; 5128c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * Memory-mapped I/O BAR (PCIERCn_CFG008) 5178c2ecf20Sopenharmony_ci * Most applications should disable the memory-mapped I/O BAR by 5188c2ecf20Sopenharmony_ci * setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci pciercx_cfg008.u32 = 0; 5218c2ecf20Sopenharmony_ci pciercx_cfg008.s.mb_addr = 0x100; 5228c2ecf20Sopenharmony_ci pciercx_cfg008.s.ml_addr = 0; 5238c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) 5288c2ecf20Sopenharmony_ci * Most applications should disable the prefetchable BAR by setting 5298c2ecf20Sopenharmony_ci * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < 5308c2ecf20Sopenharmony_ci * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); 5338c2ecf20Sopenharmony_ci pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); 5348c2ecf20Sopenharmony_ci pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); 5358c2ecf20Sopenharmony_ci pciercx_cfg009.s.lmem_base = 0x100; 5368c2ecf20Sopenharmony_ci pciercx_cfg009.s.lmem_limit = 0; 5378c2ecf20Sopenharmony_ci pciercx_cfg010.s.umem_base = 0x100; 5388c2ecf20Sopenharmony_ci pciercx_cfg011.s.umem_limit = 0; 5398c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); 5408c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); 5418c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* 5448c2ecf20Sopenharmony_ci * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) 5458c2ecf20Sopenharmony_ci * PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_ci pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); 5488c2ecf20Sopenharmony_ci pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ 5498c2ecf20Sopenharmony_ci pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ 5508c2ecf20Sopenharmony_ci pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ 5518c2ecf20Sopenharmony_ci pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ 5528c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * Advanced Error Recovery Interrupt Enables 5568c2ecf20Sopenharmony_ci * (PCIERCn_CFG075[CERE,NFERE,FERE]) 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); 5598c2ecf20Sopenharmony_ci pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ 5608c2ecf20Sopenharmony_ci pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ 5618c2ecf20Sopenharmony_ci pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ 5628c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* 5658c2ecf20Sopenharmony_ci * HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], 5668c2ecf20Sopenharmony_ci * PCIERCn_CFG034[DLLS_EN,CCINT_EN]) 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); 5698c2ecf20Sopenharmony_ci pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ 5708c2ecf20Sopenharmony_ci pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ 5718c2ecf20Sopenharmony_ci pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ 5728c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/** 5768c2ecf20Sopenharmony_ci * Initialize a host mode PCIe gen 1 link. This function takes a PCIe 5778c2ecf20Sopenharmony_ci * port from reset to a link up state. Software can then begin 5788c2ecf20Sopenharmony_ci * configuring the rest of the link. 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * Returns Zero on success 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_cistatic int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci uint64_t start_cycle; 5878c2ecf20Sopenharmony_ci union cvmx_pescx_ctl_status pescx_ctl_status; 5888c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg452 pciercx_cfg452; 5898c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg032 pciercx_cfg032; 5908c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg448 pciercx_cfg448; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Set the lane width */ 5938c2ecf20Sopenharmony_ci pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); 5948c2ecf20Sopenharmony_ci pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); 5958c2ecf20Sopenharmony_ci if (pescx_ctl_status.s.qlm_cfg == 0) 5968c2ecf20Sopenharmony_ci /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ 5978c2ecf20Sopenharmony_ci pciercx_cfg452.s.lme = 0xf; 5988c2ecf20Sopenharmony_ci else 5998c2ecf20Sopenharmony_ci /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ 6008c2ecf20Sopenharmony_ci pciercx_cfg452.s.lme = 0x7; 6018c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* 6048c2ecf20Sopenharmony_ci * CN52XX pass 1.x has an errata where length mismatches on UR 6058c2ecf20Sopenharmony_ci * responses can cause bus errors on 64bit memory 6068c2ecf20Sopenharmony_ci * reads. Turning off length error checking fixes this. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { 6098c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg455 pciercx_cfg455; 6108c2ecf20Sopenharmony_ci pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); 6118c2ecf20Sopenharmony_ci pciercx_cfg455.s.m_cpl_len_err = 1; 6128c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* Lane swap needs to be manually enabled for CN52XX */ 6168c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { 6178c2ecf20Sopenharmony_ci pescx_ctl_status.s.lane_swp = 1; 6188c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Bring up the link */ 6228c2ecf20Sopenharmony_ci pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); 6238c2ecf20Sopenharmony_ci pescx_ctl_status.s.lnk_enb = 1; 6248c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to 6288c2ecf20Sopenharmony_ci * be disabled. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) 6318c2ecf20Sopenharmony_ci __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Wait for the link to come up */ 6348c2ecf20Sopenharmony_ci start_cycle = cvmx_get_cycle(); 6358c2ecf20Sopenharmony_ci do { 6368c2ecf20Sopenharmony_ci if (cvmx_get_cycle() - start_cycle > 2 * octeon_get_clock_rate()) { 6378c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); 6388c2ecf20Sopenharmony_ci return -1; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci __delay(10000); 6418c2ecf20Sopenharmony_ci pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 6428c2ecf20Sopenharmony_ci } while (pciercx_cfg032.s.dlla == 0); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Clear all pending errors */ 6458c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM)); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Update the Replay Time Limit. Empirically, some PCIe 6498c2ecf20Sopenharmony_ci * devices take a little longer to respond than expected under 6508c2ecf20Sopenharmony_ci * load. As a workaround for this we configure the Replay Time 6518c2ecf20Sopenharmony_ci * Limit to the value expected for a 512 byte MPS instead of 6528c2ecf20Sopenharmony_ci * our actual 256 byte MPS. The numbers below are directly 6538c2ecf20Sopenharmony_ci * from the PCIe spec table 3-4. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); 6568c2ecf20Sopenharmony_ci switch (pciercx_cfg032.s.nlw) { 6578c2ecf20Sopenharmony_ci case 1: /* 1 lane */ 6588c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 1677; 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci case 2: /* 2 lanes */ 6618c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 867; 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci case 4: /* 4 lanes */ 6648c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 462; 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case 8: /* 8 lanes */ 6678c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 258; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic void __cvmx_increment_ba(union cvmx_sli_mem_access_subidx *pmas) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 6788c2ecf20Sopenharmony_ci pmas->cn68xx.ba++; 6798c2ecf20Sopenharmony_ci else 6808c2ecf20Sopenharmony_ci pmas->s.ba++; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci/** 6848c2ecf20Sopenharmony_ci * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't 6858c2ecf20Sopenharmony_ci * enumerate the bus. 6868c2ecf20Sopenharmony_ci * 6878c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * Returns Zero on success 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_cistatic int __cvmx_pcie_rc_initialize_gen1(int pcie_port) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci int i; 6948c2ecf20Sopenharmony_ci int base; 6958c2ecf20Sopenharmony_ci u64 addr_swizzle; 6968c2ecf20Sopenharmony_ci union cvmx_ciu_soft_prst ciu_soft_prst; 6978c2ecf20Sopenharmony_ci union cvmx_pescx_bist_status pescx_bist_status; 6988c2ecf20Sopenharmony_ci union cvmx_pescx_bist_status2 pescx_bist_status2; 6998c2ecf20Sopenharmony_ci union cvmx_npei_ctl_status npei_ctl_status; 7008c2ecf20Sopenharmony_ci union cvmx_npei_mem_access_ctl npei_mem_access_ctl; 7018c2ecf20Sopenharmony_ci union cvmx_npei_mem_access_subidx mem_access_subid; 7028c2ecf20Sopenharmony_ci union cvmx_npei_dbg_data npei_dbg_data; 7038c2ecf20Sopenharmony_ci union cvmx_pescx_ctl_status2 pescx_ctl_status2; 7048c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg032 pciercx_cfg032; 7058c2ecf20Sopenharmony_ci union cvmx_npei_bar1_indexx bar1_index; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ciretry: 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * Make sure we aren't trying to setup a target mode interface 7108c2ecf20Sopenharmony_ci * in host mode. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); 7138c2ecf20Sopenharmony_ci if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) { 7148c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port); 7158c2ecf20Sopenharmony_ci return -1; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * Make sure a CN52XX isn't trying to bring up port 1 when it 7208c2ecf20Sopenharmony_ci * is disabled. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { 7238c2ecf20Sopenharmony_ci npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 7248c2ecf20Sopenharmony_ci if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) { 7258c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n"); 7268c2ecf20Sopenharmony_ci return -1; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * PCIe switch arbitration mode. '0' == fixed priority NPEI, 7328c2ecf20Sopenharmony_ci * PCIe0, then PCIe1. '1' == round robin. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci npei_ctl_status.s.arb = 1; 7358c2ecf20Sopenharmony_ci /* Allow up to 0x20 config retries */ 7368c2ecf20Sopenharmony_ci npei_ctl_status.s.cfg_rtry = 0x20; 7378c2ecf20Sopenharmony_ci /* 7388c2ecf20Sopenharmony_ci * CN52XX pass1.x has an errata where P0_NTAGS and P1_NTAGS 7398c2ecf20Sopenharmony_ci * don't reset. 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { 7428c2ecf20Sopenharmony_ci npei_ctl_status.s.p0_ntags = 0x20; 7438c2ecf20Sopenharmony_ci npei_ctl_status.s.p1_ntags = 0x20; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS, npei_ctl_status.u64); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Bring the PCIe out of reset */ 7488c2ecf20Sopenharmony_ci if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) { 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * The EBH5200 board swapped the PCIe reset lines on 7518c2ecf20Sopenharmony_ci * the board. As a workaround for this bug, we bring 7528c2ecf20Sopenharmony_ci * both PCIe ports out of reset at the same time 7538c2ecf20Sopenharmony_ci * instead of on separate calls. So for port 0, we 7548c2ecf20Sopenharmony_ci * bring both out of reset and do nothing on port 1 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_ci if (pcie_port == 0) { 7578c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 7588c2ecf20Sopenharmony_ci /* 7598c2ecf20Sopenharmony_ci * After a chip reset the PCIe will also be in 7608c2ecf20Sopenharmony_ci * reset. If it isn't, most likely someone is 7618c2ecf20Sopenharmony_ci * trying to init it again without a proper 7628c2ecf20Sopenharmony_ci * PCIe reset. 7638c2ecf20Sopenharmony_ci */ 7648c2ecf20Sopenharmony_ci if (ciu_soft_prst.s.soft_prst == 0) { 7658c2ecf20Sopenharmony_ci /* Reset the ports */ 7668c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 1; 7678c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 7688c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 7698c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 1; 7708c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 7718c2ecf20Sopenharmony_ci /* Wait until pcie resets the ports. */ 7728c2ecf20Sopenharmony_ci udelay(2000); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 7758c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 7768c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 7778c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 7788c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 7798c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } else { 7828c2ecf20Sopenharmony_ci /* 7838c2ecf20Sopenharmony_ci * The normal case: The PCIe ports are completely 7848c2ecf20Sopenharmony_ci * separate and can be brought out of reset 7858c2ecf20Sopenharmony_ci * independently. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci if (pcie_port) 7888c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 7898c2ecf20Sopenharmony_ci else 7908c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 7918c2ecf20Sopenharmony_ci /* 7928c2ecf20Sopenharmony_ci * After a chip reset the PCIe will also be in 7938c2ecf20Sopenharmony_ci * reset. If it isn't, most likely someone is trying 7948c2ecf20Sopenharmony_ci * to init it again without a proper PCIe reset. 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci if (ciu_soft_prst.s.soft_prst == 0) { 7978c2ecf20Sopenharmony_ci /* Reset the port */ 7988c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 1; 7998c2ecf20Sopenharmony_ci if (pcie_port) 8008c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 8018c2ecf20Sopenharmony_ci else 8028c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 8038c2ecf20Sopenharmony_ci /* Wait until pcie resets the ports. */ 8048c2ecf20Sopenharmony_ci udelay(2000); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci if (pcie_port) { 8078c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 8088c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 8098c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 8108c2ecf20Sopenharmony_ci } else { 8118c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 8128c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 8138c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* 8188c2ecf20Sopenharmony_ci * Wait for PCIe reset to complete. Due to errata PCIE-700, we 8198c2ecf20Sopenharmony_ci * don't poll PESCX_CTL_STATUS2[PCIERST], but simply wait a 8208c2ecf20Sopenharmony_ci * fixed number of cycles. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_ci __delay(400000); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci * PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of 8268c2ecf20Sopenharmony_ci * CN56XX and CN52XX, so we only probe it on newer chips 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { 8298c2ecf20Sopenharmony_ci /* Clear PCLK_RUN so we can check if the clock is running */ 8308c2ecf20Sopenharmony_ci pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); 8318c2ecf20Sopenharmony_ci pescx_ctl_status2.s.pclk_run = 1; 8328c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); 8338c2ecf20Sopenharmony_ci /* Now that we cleared PCLK_RUN, wait for it to be set 8348c2ecf20Sopenharmony_ci * again telling us the clock is running 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), 8378c2ecf20Sopenharmony_ci union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) { 8388c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port); 8398c2ecf20Sopenharmony_ci return -1; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * Check and make sure PCIe came out of reset. If it doesn't 8458c2ecf20Sopenharmony_ci * the board probably hasn't wired the clocks up and the 8468c2ecf20Sopenharmony_ci * interface should be skipped. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); 8498c2ecf20Sopenharmony_ci if (pescx_ctl_status2.s.pcierst) { 8508c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); 8518c2ecf20Sopenharmony_ci return -1; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * Check BIST2 status. If any bits are set skip this 8568c2ecf20Sopenharmony_ci * interface. This is an attempt to catch PCIE-813 on pass 1 8578c2ecf20Sopenharmony_ci * parts. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); 8608c2ecf20Sopenharmony_ci if (pescx_bist_status2.u64) { 8618c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", 8628c2ecf20Sopenharmony_ci pcie_port); 8638c2ecf20Sopenharmony_ci return -1; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Check BIST status */ 8678c2ecf20Sopenharmony_ci pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); 8688c2ecf20Sopenharmony_ci if (pescx_bist_status.u64) 8698c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", 8708c2ecf20Sopenharmony_ci pcie_port, CAST64(pescx_bist_status.u64)); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* Initialize the config space CSRs */ 8738c2ecf20Sopenharmony_ci __cvmx_pcie_rc_initialize_config_space(pcie_port); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Bring the link up */ 8768c2ecf20Sopenharmony_ci if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) { 8778c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", 8788c2ecf20Sopenharmony_ci pcie_port); 8798c2ecf20Sopenharmony_ci return -1; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ 8838c2ecf20Sopenharmony_ci npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL); 8848c2ecf20Sopenharmony_ci npei_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ 8858c2ecf20Sopenharmony_ci npei_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ 8868c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Setup Mem access SubDIDs */ 8898c2ecf20Sopenharmony_ci mem_access_subid.u64 = 0; 8908c2ecf20Sopenharmony_ci mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ 8918c2ecf20Sopenharmony_ci mem_access_subid.s.nmerge = 1; /* Due to an errata on pass 1 chips, no merging is allowed. */ 8928c2ecf20Sopenharmony_ci mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ 8938c2ecf20Sopenharmony_ci mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ 8948c2ecf20Sopenharmony_ci mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ 8958c2ecf20Sopenharmony_ci mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */ 8968c2ecf20Sopenharmony_ci mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */ 8978c2ecf20Sopenharmony_ci mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */ 8988c2ecf20Sopenharmony_ci mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* 9018c2ecf20Sopenharmony_ci * Setup mem access 12-15 for port 0, 16-19 for port 1, 9028c2ecf20Sopenharmony_ci * supplying 36 bits of address space. 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_ci for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { 9058c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); 9068c2ecf20Sopenharmony_ci mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */ 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* 9108c2ecf20Sopenharmony_ci * Disable the peer to peer forwarding register. This must be 9118c2ecf20Sopenharmony_ci * setup by the OS after it enumerates the bus and assigns 9128c2ecf20Sopenharmony_ci * addresses to the PCIe busses. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 9158c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1); 9168c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ 9208c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */ 9238c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci bar1_index.u32 = 0; 9268c2ecf20Sopenharmony_ci bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); 9278c2ecf20Sopenharmony_ci bar1_index.s.ca = 1; /* Not Cached */ 9288c2ecf20Sopenharmony_ci bar1_index.s.end_swp = 1; /* Endian Swap mode */ 9298c2ecf20Sopenharmony_ci bar1_index.s.addr_v = 1; /* Valid entry */ 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci base = pcie_port ? 16 : 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Big endian swizzle for 32-bit PEXP_NCB register. */ 9348c2ecf20Sopenharmony_ci#ifdef __MIPSEB__ 9358c2ecf20Sopenharmony_ci addr_swizzle = 4; 9368c2ecf20Sopenharmony_ci#else 9378c2ecf20Sopenharmony_ci addr_swizzle = 0; 9388c2ecf20Sopenharmony_ci#endif 9398c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 9408c2ecf20Sopenharmony_ci cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle), 9418c2ecf20Sopenharmony_ci bar1_index.u32); 9428c2ecf20Sopenharmony_ci base++; 9438c2ecf20Sopenharmony_ci /* 256MB / 16 >> 22 == 4 */ 9448c2ecf20Sopenharmony_ci bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* 9488c2ecf20Sopenharmony_ci * Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take 9498c2ecf20Sopenharmony_ci * precedence where they overlap. It also overlaps with the 9508c2ecf20Sopenharmony_ci * device addresses, so make sure the peer to peer forwarding 9518c2ecf20Sopenharmony_ci * is set right. 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PESCX_P2N_BAR2_START(pcie_port), 0); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* 9568c2ecf20Sopenharmony_ci * Setup BAR2 attributes 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) 9598c2ecf20Sopenharmony_ci * - PTLP_RO,CTLP_RO should normally be set (except for debug). 9608c2ecf20Sopenharmony_ci * - WAIT_COM=0 will likely work for all applications. 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]). 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_ci if (pcie_port) { 9658c2ecf20Sopenharmony_ci union cvmx_npei_ctl_port1 npei_ctl_port; 9668c2ecf20Sopenharmony_ci npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT1); 9678c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_enb = 1; 9688c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_esx = 1; 9698c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_cax = 0; 9708c2ecf20Sopenharmony_ci npei_ctl_port.s.ptlp_ro = 1; 9718c2ecf20Sopenharmony_ci npei_ctl_port.s.ctlp_ro = 1; 9728c2ecf20Sopenharmony_ci npei_ctl_port.s.wait_com = 0; 9738c2ecf20Sopenharmony_ci npei_ctl_port.s.waitl_com = 0; 9748c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT1, npei_ctl_port.u64); 9758c2ecf20Sopenharmony_ci } else { 9768c2ecf20Sopenharmony_ci union cvmx_npei_ctl_port0 npei_ctl_port; 9778c2ecf20Sopenharmony_ci npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT0); 9788c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_enb = 1; 9798c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_esx = 1; 9808c2ecf20Sopenharmony_ci npei_ctl_port.s.bar2_cax = 0; 9818c2ecf20Sopenharmony_ci npei_ctl_port.s.ptlp_ro = 1; 9828c2ecf20Sopenharmony_ci npei_ctl_port.s.ctlp_ro = 1; 9838c2ecf20Sopenharmony_ci npei_ctl_port.s.wait_com = 0; 9848c2ecf20Sopenharmony_ci npei_ctl_port.s.waitl_com = 0; 9858c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64); 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * Both pass 1 and pass 2 of CN52XX and CN56XX have an errata 9908c2ecf20Sopenharmony_ci * that causes TLP ordering to not be preserved after multiple 9918c2ecf20Sopenharmony_ci * PCIe port resets. This code detects this fault and corrects 9928c2ecf20Sopenharmony_ci * it by aligning the TLP counters properly. Another link 9938c2ecf20Sopenharmony_ci * reset is then performed. See PCIE-13340 9948c2ecf20Sopenharmony_ci */ 9958c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || 9968c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) || 9978c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || 9988c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { 9998c2ecf20Sopenharmony_ci union cvmx_npei_dbg_data dbg_data; 10008c2ecf20Sopenharmony_ci int old_in_fif_p_count; 10018c2ecf20Sopenharmony_ci int in_fif_p_count; 10028c2ecf20Sopenharmony_ci int out_p_count; 10038c2ecf20Sopenharmony_ci int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1; 10048c2ecf20Sopenharmony_ci int i; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* 10078c2ecf20Sopenharmony_ci * Choose a write address of 1MB. It should be 10088c2ecf20Sopenharmony_ci * harmless as all bars haven't been setup. 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_ci uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* 10138c2ecf20Sopenharmony_ci * Make sure at least in_p_offset have been executed before we try and 10148c2ecf20Sopenharmony_ci * read in_fif_p_count 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_ci i = in_p_offset; 10178c2ecf20Sopenharmony_ci while (i--) { 10188c2ecf20Sopenharmony_ci cvmx_write64_uint32(write_address, 0); 10198c2ecf20Sopenharmony_ci __delay(10000); 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* 10238c2ecf20Sopenharmony_ci * Read the IN_FIF_P_COUNT from the debug 10248c2ecf20Sopenharmony_ci * select. IN_FIF_P_COUNT can be unstable sometimes so 10258c2ecf20Sopenharmony_ci * read it twice with a write between the reads. This 10268c2ecf20Sopenharmony_ci * way we can tell the value is good as it will 10278c2ecf20Sopenharmony_ci * increment by one due to the write 10288c2ecf20Sopenharmony_ci */ 10298c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc); 10308c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); 10318c2ecf20Sopenharmony_ci do { 10328c2ecf20Sopenharmony_ci dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 10338c2ecf20Sopenharmony_ci old_in_fif_p_count = dbg_data.s.data & 0xff; 10348c2ecf20Sopenharmony_ci cvmx_write64_uint32(write_address, 0); 10358c2ecf20Sopenharmony_ci __delay(10000); 10368c2ecf20Sopenharmony_ci dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 10378c2ecf20Sopenharmony_ci in_fif_p_count = dbg_data.s.data & 0xff; 10388c2ecf20Sopenharmony_ci } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* Update in_fif_p_count for it's offset with respect to out_p_count */ 10418c2ecf20Sopenharmony_ci in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Read the OUT_P_COUNT from the debug select */ 10448c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f); 10458c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); 10468c2ecf20Sopenharmony_ci dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 10478c2ecf20Sopenharmony_ci out_p_count = (dbg_data.s.data>>1) & 0xff; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* Check that the two counters are aligned */ 10508c2ecf20Sopenharmony_ci if (out_p_count != in_fif_p_count) { 10518c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); 10528c2ecf20Sopenharmony_ci while (in_fif_p_count != 0) { 10538c2ecf20Sopenharmony_ci cvmx_write64_uint32(write_address, 0); 10548c2ecf20Sopenharmony_ci __delay(10000); 10558c2ecf20Sopenharmony_ci in_fif_p_count = (in_fif_p_count + 1) & 0xff; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci /* 10588c2ecf20Sopenharmony_ci * The EBH5200 board swapped the PCIe reset 10598c2ecf20Sopenharmony_ci * lines on the board. This means we must 10608c2ecf20Sopenharmony_ci * bring both links down and up, which will 10618c2ecf20Sopenharmony_ci * cause the PCIe0 to need alignment 10628c2ecf20Sopenharmony_ci * again. Lots of messages will be displayed, 10638c2ecf20Sopenharmony_ci * but everything should work 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) && 10668c2ecf20Sopenharmony_ci (pcie_port == 1)) 10678c2ecf20Sopenharmony_ci cvmx_pcie_rc_initialize(0); 10688c2ecf20Sopenharmony_ci /* Rety bringing this port up */ 10698c2ecf20Sopenharmony_ci goto retry; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Display the link status */ 10748c2ecf20Sopenharmony_ci pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 10758c2ecf20Sopenharmony_ci cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 0; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/** 10818c2ecf20Sopenharmony_ci * Initialize a host mode PCIe gen 2 link. This function takes a PCIe 10828c2ecf20Sopenharmony_ci * port from reset to a link up state. Software can then begin 10838c2ecf20Sopenharmony_ci * configuring the rest of the link. 10848c2ecf20Sopenharmony_ci * 10858c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 10868c2ecf20Sopenharmony_ci * 10878c2ecf20Sopenharmony_ci * Return Zero on success. 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_cistatic int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci uint64_t start_cycle; 10928c2ecf20Sopenharmony_ci union cvmx_pemx_ctl_status pem_ctl_status; 10938c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg032 pciercx_cfg032; 10948c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg448 pciercx_cfg448; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Bring up the link */ 10978c2ecf20Sopenharmony_ci pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); 10988c2ecf20Sopenharmony_ci pem_ctl_status.s.lnk_enb = 1; 10998c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Wait for the link to come up */ 11028c2ecf20Sopenharmony_ci start_cycle = cvmx_get_cycle(); 11038c2ecf20Sopenharmony_ci do { 11048c2ecf20Sopenharmony_ci if (cvmx_get_cycle() - start_cycle > octeon_get_clock_rate()) 11058c2ecf20Sopenharmony_ci return -1; 11068c2ecf20Sopenharmony_ci __delay(10000); 11078c2ecf20Sopenharmony_ci pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 11088c2ecf20Sopenharmony_ci } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* 11118c2ecf20Sopenharmony_ci * Update the Replay Time Limit. Empirically, some PCIe 11128c2ecf20Sopenharmony_ci * devices take a little longer to respond than expected under 11138c2ecf20Sopenharmony_ci * load. As a workaround for this we configure the Replay Time 11148c2ecf20Sopenharmony_ci * Limit to the value expected for a 512 byte MPS instead of 11158c2ecf20Sopenharmony_ci * our actual 256 byte MPS. The numbers below are directly 11168c2ecf20Sopenharmony_ci * from the PCIe spec table 3-4 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); 11198c2ecf20Sopenharmony_ci switch (pciercx_cfg032.s.nlw) { 11208c2ecf20Sopenharmony_ci case 1: /* 1 lane */ 11218c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 1677; 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci case 2: /* 2 lanes */ 11248c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 867; 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci case 4: /* 4 lanes */ 11278c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 462; 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci case 8: /* 8 lanes */ 11308c2ecf20Sopenharmony_ci pciercx_cfg448.s.rtl = 258; 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/** 11408c2ecf20Sopenharmony_ci * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate 11418c2ecf20Sopenharmony_ci * the bus. 11428c2ecf20Sopenharmony_ci * 11438c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 11448c2ecf20Sopenharmony_ci * 11458c2ecf20Sopenharmony_ci * Returns Zero on success. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_cistatic int __cvmx_pcie_rc_initialize_gen2(int pcie_port) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci int i; 11508c2ecf20Sopenharmony_ci union cvmx_ciu_soft_prst ciu_soft_prst; 11518c2ecf20Sopenharmony_ci union cvmx_mio_rst_ctlx mio_rst_ctl; 11528c2ecf20Sopenharmony_ci union cvmx_pemx_bar_ctl pemx_bar_ctl; 11538c2ecf20Sopenharmony_ci union cvmx_pemx_ctl_status pemx_ctl_status; 11548c2ecf20Sopenharmony_ci union cvmx_pemx_bist_status pemx_bist_status; 11558c2ecf20Sopenharmony_ci union cvmx_pemx_bist_status2 pemx_bist_status2; 11568c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg032 pciercx_cfg032; 11578c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg515 pciercx_cfg515; 11588c2ecf20Sopenharmony_ci union cvmx_sli_ctl_portx sli_ctl_portx; 11598c2ecf20Sopenharmony_ci union cvmx_sli_mem_access_ctl sli_mem_access_ctl; 11608c2ecf20Sopenharmony_ci union cvmx_sli_mem_access_subidx mem_access_subid; 11618c2ecf20Sopenharmony_ci union cvmx_sriox_status_reg sriox_status_reg; 11628c2ecf20Sopenharmony_ci union cvmx_pemx_bar1_indexx bar1_index; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_SRIO)) { 11658c2ecf20Sopenharmony_ci /* Make sure this interface isn't SRIO */ 11668c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * The CN66XX requires reading the 11698c2ecf20Sopenharmony_ci * MIO_QLMX_CFG register to figure out the 11708c2ecf20Sopenharmony_ci * port type. 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci union cvmx_mio_qlmx_cfg qlmx_cfg; 11738c2ecf20Sopenharmony_ci qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port)); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (qlmx_cfg.s.qlm_spd == 15) { 11768c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port); 11778c2ecf20Sopenharmony_ci return -1; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci switch (qlmx_cfg.s.qlm_spd) { 11818c2ecf20Sopenharmony_ci case 0x1: /* SRIO 1x4 short */ 11828c2ecf20Sopenharmony_ci case 0x3: /* SRIO 1x4 long */ 11838c2ecf20Sopenharmony_ci case 0x4: /* SRIO 2x2 short */ 11848c2ecf20Sopenharmony_ci case 0x6: /* SRIO 2x2 long */ 11858c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); 11868c2ecf20Sopenharmony_ci return -1; 11878c2ecf20Sopenharmony_ci case 0x9: /* SGMII */ 11888c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port); 11898c2ecf20Sopenharmony_ci return -1; 11908c2ecf20Sopenharmony_ci case 0xb: /* XAUI */ 11918c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port); 11928c2ecf20Sopenharmony_ci return -1; 11938c2ecf20Sopenharmony_ci case 0x0: /* PCIE gen2 */ 11948c2ecf20Sopenharmony_ci case 0x8: /* PCIE gen2 (alias) */ 11958c2ecf20Sopenharmony_ci case 0x2: /* PCIE gen1 */ 11968c2ecf20Sopenharmony_ci case 0xa: /* PCIE gen1 (alias) */ 11978c2ecf20Sopenharmony_ci break; 11988c2ecf20Sopenharmony_ci default: 11998c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port); 12008c2ecf20Sopenharmony_ci return -1; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci } else { 12038c2ecf20Sopenharmony_ci sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); 12048c2ecf20Sopenharmony_ci if (sriox_status_reg.s.srio) { 12058c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); 12068c2ecf20Sopenharmony_ci return -1; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci#if 0 12128c2ecf20Sopenharmony_ci /* This code is so that the PCIe analyzer is able to see 63XX traffic */ 12138c2ecf20Sopenharmony_ci pr_notice("PCIE : init for pcie analyzer.\n"); 12148c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_init(); 12158c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); 12168c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); 12178c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); 12188c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); 12198c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); 12208c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); 12218c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); 12228c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); 12238c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); 12248c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); 12258c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); 12268c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); 12278c2ecf20Sopenharmony_ci cvmx_helper_qlm_jtag_update(pcie_port); 12288c2ecf20Sopenharmony_ci#endif 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* Make sure we aren't trying to setup a target mode interface in host mode */ 12318c2ecf20Sopenharmony_ci mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); 12328c2ecf20Sopenharmony_ci if (!mio_rst_ctl.s.host_mode) { 12338c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port); 12348c2ecf20Sopenharmony_ci return -1; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ 12388c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) { 12398c2ecf20Sopenharmony_ci if (pcie_port) { 12408c2ecf20Sopenharmony_ci union cvmx_ciu_qlm ciu_qlm; 12418c2ecf20Sopenharmony_ci ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1); 12428c2ecf20Sopenharmony_ci ciu_qlm.s.txbypass = 1; 12438c2ecf20Sopenharmony_ci ciu_qlm.s.txdeemph = 5; 12448c2ecf20Sopenharmony_ci ciu_qlm.s.txmargin = 0x17; 12458c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64); 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci union cvmx_ciu_qlm ciu_qlm; 12488c2ecf20Sopenharmony_ci ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0); 12498c2ecf20Sopenharmony_ci ciu_qlm.s.txbypass = 1; 12508c2ecf20Sopenharmony_ci ciu_qlm.s.txdeemph = 5; 12518c2ecf20Sopenharmony_ci ciu_qlm.s.txmargin = 0x17; 12528c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci /* Bring the PCIe out of reset */ 12568c2ecf20Sopenharmony_ci if (pcie_port) 12578c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 12588c2ecf20Sopenharmony_ci else 12598c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * After a chip reset the PCIe will also be in reset. If it 12628c2ecf20Sopenharmony_ci * isn't, most likely someone is trying to init it again 12638c2ecf20Sopenharmony_ci * without a proper PCIe reset 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_ci if (ciu_soft_prst.s.soft_prst == 0) { 12668c2ecf20Sopenharmony_ci /* Reset the port */ 12678c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 1; 12688c2ecf20Sopenharmony_ci if (pcie_port) 12698c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 12708c2ecf20Sopenharmony_ci else 12718c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 12728c2ecf20Sopenharmony_ci /* Wait until pcie resets the ports. */ 12738c2ecf20Sopenharmony_ci udelay(2000); 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci if (pcie_port) { 12768c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 12778c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 12788c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 12798c2ecf20Sopenharmony_ci } else { 12808c2ecf20Sopenharmony_ci ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 12818c2ecf20Sopenharmony_ci ciu_soft_prst.s.soft_prst = 0; 12828c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* Wait for PCIe reset to complete */ 12868c2ecf20Sopenharmony_ci udelay(1000); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* 12898c2ecf20Sopenharmony_ci * Check and make sure PCIe came out of reset. If it doesn't 12908c2ecf20Sopenharmony_ci * the board probably hasn't wired the clocks up and the 12918c2ecf20Sopenharmony_ci * interface should be skipped. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) { 12948c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); 12958c2ecf20Sopenharmony_ci return -1; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Check BIST status */ 12998c2ecf20Sopenharmony_ci pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port)); 13008c2ecf20Sopenharmony_ci if (pemx_bist_status.u64) 13018c2ecf20Sopenharmony_ci pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64)); 13028c2ecf20Sopenharmony_ci pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); 13038c2ecf20Sopenharmony_ci /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ 13048c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) 13058c2ecf20Sopenharmony_ci pemx_bist_status2.u64 &= ~0x3full; 13068c2ecf20Sopenharmony_ci if (pemx_bist_status2.u64) 13078c2ecf20Sopenharmony_ci pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64)); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* Initialize the config space CSRs */ 13108c2ecf20Sopenharmony_ci __cvmx_pcie_rc_initialize_config_space(pcie_port); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Enable gen2 speed selection */ 13138c2ecf20Sopenharmony_ci pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port)); 13148c2ecf20Sopenharmony_ci pciercx_cfg515.s.dsc = 1; 13158c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* Bring the link up */ 13188c2ecf20Sopenharmony_ci if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { 13198c2ecf20Sopenharmony_ci /* 13208c2ecf20Sopenharmony_ci * Some gen1 devices don't handle the gen 2 training 13218c2ecf20Sopenharmony_ci * correctly. Disable gen2 and try again with only 13228c2ecf20Sopenharmony_ci * gen1 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg031 pciercx_cfg031; 13258c2ecf20Sopenharmony_ci pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port)); 13268c2ecf20Sopenharmony_ci pciercx_cfg031.s.mls = 1; 13278c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); 13288c2ecf20Sopenharmony_ci if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { 13298c2ecf20Sopenharmony_ci pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); 13308c2ecf20Sopenharmony_ci return -1; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ 13358c2ecf20Sopenharmony_ci sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL); 13368c2ecf20Sopenharmony_ci sli_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ 13378c2ecf20Sopenharmony_ci sli_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ 13388c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* Setup Mem access SubDIDs */ 13418c2ecf20Sopenharmony_ci mem_access_subid.u64 = 0; 13428c2ecf20Sopenharmony_ci mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ 13438c2ecf20Sopenharmony_ci mem_access_subid.s.nmerge = 0; /* Allow merging as it works on CN6XXX. */ 13448c2ecf20Sopenharmony_ci mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ 13458c2ecf20Sopenharmony_ci mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ 13468c2ecf20Sopenharmony_ci mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ 13478c2ecf20Sopenharmony_ci mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ 13488c2ecf20Sopenharmony_ci /* PCIe Adddress Bits <63:34>. */ 13498c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 13508c2ecf20Sopenharmony_ci mem_access_subid.cn68xx.ba = 0; 13518c2ecf20Sopenharmony_ci else 13528c2ecf20Sopenharmony_ci mem_access_subid.s.ba = 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* 13558c2ecf20Sopenharmony_ci * Setup mem access 12-15 for port 0, 16-19 for port 1, 13568c2ecf20Sopenharmony_ci * supplying 36 bits of address space. 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_ci for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { 13598c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); 13608c2ecf20Sopenharmony_ci /* Set each SUBID to extend the addressable range */ 13618c2ecf20Sopenharmony_ci __cvmx_increment_ba(&mem_access_subid); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* 13658c2ecf20Sopenharmony_ci * Disable the peer to peer forwarding register. This must be 13668c2ecf20Sopenharmony_ci * setup by the OS after it enumerates the bus and assigns 13678c2ecf20Sopenharmony_ci * addresses to the PCIe busses. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 13708c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); 13718c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ 13758c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci /* 13788c2ecf20Sopenharmony_ci * Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take 13798c2ecf20Sopenharmony_ci * precedence where they overlap. It also overlaps with the 13808c2ecf20Sopenharmony_ci * device addresses, so make sure the peer to peer forwarding 13818c2ecf20Sopenharmony_ci * is set right. 13828c2ecf20Sopenharmony_ci */ 13838c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* 13868c2ecf20Sopenharmony_ci * Setup BAR2 attributes 13878c2ecf20Sopenharmony_ci * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) 13888c2ecf20Sopenharmony_ci * - PTLP_RO,CTLP_RO should normally be set (except for debug). 13898c2ecf20Sopenharmony_ci * - WAIT_COM=0 will likely work for all applications. 13908c2ecf20Sopenharmony_ci * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port)); 13938c2ecf20Sopenharmony_ci pemx_bar_ctl.s.bar1_siz = 3; /* 256MB BAR1*/ 13948c2ecf20Sopenharmony_ci pemx_bar_ctl.s.bar2_enb = 1; 13958c2ecf20Sopenharmony_ci pemx_bar_ctl.s.bar2_esx = 1; 13968c2ecf20Sopenharmony_ci pemx_bar_ctl.s.bar2_cax = 0; 13978c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64); 13988c2ecf20Sopenharmony_ci sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port)); 13998c2ecf20Sopenharmony_ci sli_ctl_portx.s.ptlp_ro = 1; 14008c2ecf20Sopenharmony_ci sli_ctl_portx.s.ctlp_ro = 1; 14018c2ecf20Sopenharmony_ci sli_ctl_portx.s.wait_com = 0; 14028c2ecf20Sopenharmony_ci sli_ctl_portx.s.waitl_com = 0; 14038c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* BAR1 follows BAR2 */ 14068c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci bar1_index.u64 = 0; 14098c2ecf20Sopenharmony_ci bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); 14108c2ecf20Sopenharmony_ci bar1_index.s.ca = 1; /* Not Cached */ 14118c2ecf20Sopenharmony_ci bar1_index.s.end_swp = 1; /* Endian Swap mode */ 14128c2ecf20Sopenharmony_ci bar1_index.s.addr_v = 1; /* Valid entry */ 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 14158c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64); 14168c2ecf20Sopenharmony_ci /* 256MB / 16 >> 22 == 4 */ 14178c2ecf20Sopenharmony_ci bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * Allow config retries for 250ms. Count is based off the 5Ghz 14228c2ecf20Sopenharmony_ci * SERDES clock. 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); 14258c2ecf20Sopenharmony_ci pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000; 14268c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* Display the link status */ 14298c2ecf20Sopenharmony_ci pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 14308c2ecf20Sopenharmony_ci pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci/** 14368c2ecf20Sopenharmony_ci * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. 14378c2ecf20Sopenharmony_ci * 14388c2ecf20Sopenharmony_ci * @pcie_port: PCIe port to initialize 14398c2ecf20Sopenharmony_ci * 14408c2ecf20Sopenharmony_ci * Returns Zero on success 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_cistatic int cvmx_pcie_rc_initialize(int pcie_port) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci int result; 14458c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) 14468c2ecf20Sopenharmony_ci result = __cvmx_pcie_rc_initialize_gen1(pcie_port); 14478c2ecf20Sopenharmony_ci else 14488c2ecf20Sopenharmony_ci result = __cvmx_pcie_rc_initialize_gen2(pcie_port); 14498c2ecf20Sopenharmony_ci return result; 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci/* Above was cvmx-pcie.c, below original pcie.c */ 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci/** 14558c2ecf20Sopenharmony_ci * Map a PCI device to the appropriate interrupt line 14568c2ecf20Sopenharmony_ci * 14578c2ecf20Sopenharmony_ci * @dev: The Linux PCI device structure for the device to map 14588c2ecf20Sopenharmony_ci * @slot: The slot number for this device on __BUS 0__. Linux 14598c2ecf20Sopenharmony_ci * enumerates through all the bridges and figures out the 14608c2ecf20Sopenharmony_ci * slot on Bus 0 where this device eventually hooks to. 14618c2ecf20Sopenharmony_ci * @pin: The PCI interrupt pin read from the device, then swizzled 14628c2ecf20Sopenharmony_ci * as it goes through each bridge. 14638c2ecf20Sopenharmony_ci * Returns Interrupt number for the device 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ciint octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci /* 14688c2ecf20Sopenharmony_ci * The EBH5600 board with the PCI to PCIe bridge mistakenly 14698c2ecf20Sopenharmony_ci * wires the first slot for both device id 2 and interrupt 14708c2ecf20Sopenharmony_ci * A. According to the PCI spec, device id 2 should be C. The 14718c2ecf20Sopenharmony_ci * following kludge attempts to fix this. 14728c2ecf20Sopenharmony_ci */ 14738c2ecf20Sopenharmony_ci if (strstr(octeon_board_type_string(), "EBH5600") && 14748c2ecf20Sopenharmony_ci dev->bus && dev->bus->parent) { 14758c2ecf20Sopenharmony_ci /* 14768c2ecf20Sopenharmony_ci * Iterate all the way up the device chain and find 14778c2ecf20Sopenharmony_ci * the root bus. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci while (dev->bus && dev->bus->parent) 14808c2ecf20Sopenharmony_ci dev = to_pci_dev(dev->bus->bridge); 14818c2ecf20Sopenharmony_ci /* 14828c2ecf20Sopenharmony_ci * If the root bus is number 0 and the PEX 8114 is the 14838c2ecf20Sopenharmony_ci * root, assume we are behind the miswired bus. We 14848c2ecf20Sopenharmony_ci * need to correct the swizzle level by two. Yuck. 14858c2ecf20Sopenharmony_ci */ 14868c2ecf20Sopenharmony_ci if ((dev->bus->number == 1) && 14878c2ecf20Sopenharmony_ci (dev->vendor == 0x10b5) && (dev->device == 0x8114)) { 14888c2ecf20Sopenharmony_ci /* 14898c2ecf20Sopenharmony_ci * The pin field is one based, not zero. We 14908c2ecf20Sopenharmony_ci * need to swizzle it by minus two. 14918c2ecf20Sopenharmony_ci */ 14928c2ecf20Sopenharmony_ci pin = ((pin - 3) & 3) + 1; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci /* 14968c2ecf20Sopenharmony_ci * The -1 is because pin starts with one, not zero. It might 14978c2ecf20Sopenharmony_ci * be that this equation needs to include the slot number, but 14988c2ecf20Sopenharmony_ci * I don't have hardware to check that against. 14998c2ecf20Sopenharmony_ci */ 15008c2ecf20Sopenharmony_ci return pin - 1 + OCTEON_IRQ_PCI_INT0; 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic void set_cfg_read_retry(u32 retry_cnt) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci union cvmx_pemx_ctl_status pemx_ctl; 15068c2ecf20Sopenharmony_ci pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); 15078c2ecf20Sopenharmony_ci pemx_ctl.s.cfg_rtry = retry_cnt; 15088c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic u32 disable_cfg_read_retry(void) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci u32 retry_cnt; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci union cvmx_pemx_ctl_status pemx_ctl; 15178c2ecf20Sopenharmony_ci pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); 15188c2ecf20Sopenharmony_ci retry_cnt = pemx_ctl.s.cfg_rtry; 15198c2ecf20Sopenharmony_ci pemx_ctl.s.cfg_rtry = 0; 15208c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); 15218c2ecf20Sopenharmony_ci return retry_cnt; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic int is_cfg_retry(void) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci union cvmx_pemx_int_sum pemx_int_sum; 15278c2ecf20Sopenharmony_ci pemx_int_sum.u64 = cvmx_read_csr(CVMX_PEMX_INT_SUM(1)); 15288c2ecf20Sopenharmony_ci if (pemx_int_sum.s.crs_dr) 15298c2ecf20Sopenharmony_ci return 1; 15308c2ecf20Sopenharmony_ci return 0; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci/* 15348c2ecf20Sopenharmony_ci * Read a value from configuration space 15358c2ecf20Sopenharmony_ci * 15368c2ecf20Sopenharmony_ci */ 15378c2ecf20Sopenharmony_cistatic int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus, 15388c2ecf20Sopenharmony_ci unsigned int devfn, int reg, int size, 15398c2ecf20Sopenharmony_ci u32 *val) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci union octeon_cvmemctl cvmmemctl; 15428c2ecf20Sopenharmony_ci union octeon_cvmemctl cvmmemctl_save; 15438c2ecf20Sopenharmony_ci int bus_number = bus->number; 15448c2ecf20Sopenharmony_ci int cfg_retry = 0; 15458c2ecf20Sopenharmony_ci int retry_cnt = 0; 15468c2ecf20Sopenharmony_ci int max_retry_cnt = 10; 15478c2ecf20Sopenharmony_ci u32 cfg_retry_cnt = 0; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci cvmmemctl_save.u64 = 0; 15508c2ecf20Sopenharmony_ci BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); 15518c2ecf20Sopenharmony_ci /* 15528c2ecf20Sopenharmony_ci * For the top level bus make sure our hardware bus number 15538c2ecf20Sopenharmony_ci * matches the software one 15548c2ecf20Sopenharmony_ci */ 15558c2ecf20Sopenharmony_ci if (bus->parent == NULL) { 15568c2ecf20Sopenharmony_ci if (enable_pcie_bus_num_war[pcie_port]) 15578c2ecf20Sopenharmony_ci bus_number = 0; 15588c2ecf20Sopenharmony_ci else { 15598c2ecf20Sopenharmony_ci union cvmx_pciercx_cfg006 pciercx_cfg006; 15608c2ecf20Sopenharmony_ci pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, 15618c2ecf20Sopenharmony_ci CVMX_PCIERCX_CFG006(pcie_port)); 15628c2ecf20Sopenharmony_ci if (pciercx_cfg006.s.pbnum != bus_number) { 15638c2ecf20Sopenharmony_ci pciercx_cfg006.s.pbnum = bus_number; 15648c2ecf20Sopenharmony_ci pciercx_cfg006.s.sbnum = bus_number; 15658c2ecf20Sopenharmony_ci pciercx_cfg006.s.subbnum = bus_number; 15668c2ecf20Sopenharmony_ci cvmx_pcie_cfgx_write(pcie_port, 15678c2ecf20Sopenharmony_ci CVMX_PCIERCX_CFG006(pcie_port), 15688c2ecf20Sopenharmony_ci pciercx_cfg006.u32); 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci /* 15748c2ecf20Sopenharmony_ci * PCIe only has a single device connected to Octeon. It is 15758c2ecf20Sopenharmony_ci * always device ID 0. Don't bother doing reads for other 15768c2ecf20Sopenharmony_ci * device IDs on the first segment. 15778c2ecf20Sopenharmony_ci */ 15788c2ecf20Sopenharmony_ci if ((bus->parent == NULL) && (devfn >> 3 != 0)) 15798c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* 15828c2ecf20Sopenharmony_ci * The following is a workaround for the CN57XX, CN56XX, 15838c2ecf20Sopenharmony_ci * CN55XX, and CN54XX errata with PCIe config reads from non 15848c2ecf20Sopenharmony_ci * existent devices. These chips will hang the PCIe link if a 15858c2ecf20Sopenharmony_ci * config read is performed that causes a UR response. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) || 15888c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) { 15898c2ecf20Sopenharmony_ci /* 15908c2ecf20Sopenharmony_ci * For our EBH5600 board, port 0 has a bridge with two 15918c2ecf20Sopenharmony_ci * PCI-X slots. We need a new special checks to make 15928c2ecf20Sopenharmony_ci * sure we only probe valid stuff. The PCIe->PCI-X 15938c2ecf20Sopenharmony_ci * bridge only respondes to device ID 0, function 15948c2ecf20Sopenharmony_ci * 0-1 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci if ((bus->parent == NULL) && (devfn >= 2)) 15978c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 15988c2ecf20Sopenharmony_ci /* 15998c2ecf20Sopenharmony_ci * The PCI-X slots are device ID 2,3. Choose one of 16008c2ecf20Sopenharmony_ci * the below "if" blocks based on what is plugged into 16018c2ecf20Sopenharmony_ci * the board. 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_ci#if 1 16048c2ecf20Sopenharmony_ci /* Use this option if you aren't using either slot */ 16058c2ecf20Sopenharmony_ci if (bus_number == 2) 16068c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16078c2ecf20Sopenharmony_ci#elif 0 16088c2ecf20Sopenharmony_ci /* 16098c2ecf20Sopenharmony_ci * Use this option if you are using the first slot but 16108c2ecf20Sopenharmony_ci * not the second. 16118c2ecf20Sopenharmony_ci */ 16128c2ecf20Sopenharmony_ci if ((bus_number == 2) && (devfn >> 3 != 2)) 16138c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16148c2ecf20Sopenharmony_ci#elif 0 16158c2ecf20Sopenharmony_ci /* 16168c2ecf20Sopenharmony_ci * Use this option if you are using the second slot 16178c2ecf20Sopenharmony_ci * but not the first. 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci if ((bus_number == 2) && (devfn >> 3 != 3)) 16208c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16218c2ecf20Sopenharmony_ci#elif 0 16228c2ecf20Sopenharmony_ci /* Use this opion if you are using both slots */ 16238c2ecf20Sopenharmony_ci if ((bus_number == 2) && 16248c2ecf20Sopenharmony_ci !((devfn == (2 << 3)) || (devfn == (3 << 3)))) 16258c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16268c2ecf20Sopenharmony_ci#endif 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* The following #if gives a more complicated example. This is 16298c2ecf20Sopenharmony_ci the required checks for running a Nitrox CN16XX-NHBX in the 16308c2ecf20Sopenharmony_ci slot of the EBH5600. This card has a PLX PCIe bridge with 16318c2ecf20Sopenharmony_ci four Nitrox PLX parts behind it */ 16328c2ecf20Sopenharmony_ci#if 0 16338c2ecf20Sopenharmony_ci /* PLX bridge with 4 ports */ 16348c2ecf20Sopenharmony_ci if ((bus_number == 4) && 16358c2ecf20Sopenharmony_ci !((devfn >> 3 >= 1) && (devfn >> 3 <= 4))) 16368c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16378c2ecf20Sopenharmony_ci /* Nitrox behind PLX 1 */ 16388c2ecf20Sopenharmony_ci if ((bus_number == 5) && (devfn >> 3 != 0)) 16398c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16408c2ecf20Sopenharmony_ci /* Nitrox behind PLX 2 */ 16418c2ecf20Sopenharmony_ci if ((bus_number == 6) && (devfn >> 3 != 0)) 16428c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16438c2ecf20Sopenharmony_ci /* Nitrox behind PLX 3 */ 16448c2ecf20Sopenharmony_ci if ((bus_number == 7) && (devfn >> 3 != 0)) 16458c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16468c2ecf20Sopenharmony_ci /* Nitrox behind PLX 4 */ 16478c2ecf20Sopenharmony_ci if ((bus_number == 8) && (devfn >> 3 != 0)) 16488c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16498c2ecf20Sopenharmony_ci#endif 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci /* 16528c2ecf20Sopenharmony_ci * Shorten the DID timeout so bus errors for PCIe 16538c2ecf20Sopenharmony_ci * config reads from non existent devices happen 16548c2ecf20Sopenharmony_ci * faster. This allows us to continue booting even if 16558c2ecf20Sopenharmony_ci * the above "if" checks are wrong. Once one of these 16568c2ecf20Sopenharmony_ci * errors happens, the PCIe port is dead. 16578c2ecf20Sopenharmony_ci */ 16588c2ecf20Sopenharmony_ci cvmmemctl_save.u64 = __read_64bit_c0_register($11, 7); 16598c2ecf20Sopenharmony_ci cvmmemctl.u64 = cvmmemctl_save.u64; 16608c2ecf20Sopenharmony_ci cvmmemctl.s.didtto = 2; 16618c2ecf20Sopenharmony_ci __write_64bit_c0_register($11, 7, cvmmemctl.u64); 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) 16658c2ecf20Sopenharmony_ci cfg_retry_cnt = disable_cfg_read_retry(); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x" 16688c2ecf20Sopenharmony_ci " size=%d ", pcie_port, bus_number, devfn, reg, size); 16698c2ecf20Sopenharmony_ci do { 16708c2ecf20Sopenharmony_ci switch (size) { 16718c2ecf20Sopenharmony_ci case 4: 16728c2ecf20Sopenharmony_ci *val = cvmx_pcie_config_read32(pcie_port, bus_number, 16738c2ecf20Sopenharmony_ci devfn >> 3, devfn & 0x7, reg); 16748c2ecf20Sopenharmony_ci break; 16758c2ecf20Sopenharmony_ci case 2: 16768c2ecf20Sopenharmony_ci *val = cvmx_pcie_config_read16(pcie_port, bus_number, 16778c2ecf20Sopenharmony_ci devfn >> 3, devfn & 0x7, reg); 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci case 1: 16808c2ecf20Sopenharmony_ci *val = cvmx_pcie_config_read8(pcie_port, bus_number, 16818c2ecf20Sopenharmony_ci devfn >> 3, devfn & 0x7, reg); 16828c2ecf20Sopenharmony_ci break; 16838c2ecf20Sopenharmony_ci default: 16848c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 16858c2ecf20Sopenharmony_ci set_cfg_read_retry(cfg_retry_cnt); 16868c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && 16898c2ecf20Sopenharmony_ci (enable_pcie_14459_war)) { 16908c2ecf20Sopenharmony_ci cfg_retry = is_cfg_retry(); 16918c2ecf20Sopenharmony_ci retry_cnt++; 16928c2ecf20Sopenharmony_ci if (retry_cnt > max_retry_cnt) { 16938c2ecf20Sopenharmony_ci pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n", 16948c2ecf20Sopenharmony_ci retry_cnt); 16958c2ecf20Sopenharmony_ci cfg_retry = 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci } while (cfg_retry); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) 17018c2ecf20Sopenharmony_ci set_cfg_read_retry(cfg_retry_cnt); 17028c2ecf20Sopenharmony_ci pr_debug("val=%08x : tries=%02d\n", *val, retry_cnt); 17038c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) || 17048c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) 17058c2ecf20Sopenharmony_ci write_c0_cvmmemctl(cvmmemctl_save.u64); 17068c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_cistatic int octeon_pcie0_read_config(struct pci_bus *bus, unsigned int devfn, 17108c2ecf20Sopenharmony_ci int reg, int size, u32 *val) 17118c2ecf20Sopenharmony_ci{ 17128c2ecf20Sopenharmony_ci return octeon_pcie_read_config(0, bus, devfn, reg, size, val); 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn, 17168c2ecf20Sopenharmony_ci int reg, int size, u32 *val) 17178c2ecf20Sopenharmony_ci{ 17188c2ecf20Sopenharmony_ci return octeon_pcie_read_config(1, bus, devfn, reg, size, val); 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_cistatic int octeon_dummy_read_config(struct pci_bus *bus, unsigned int devfn, 17228c2ecf20Sopenharmony_ci int reg, int size, u32 *val) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci/* 17288c2ecf20Sopenharmony_ci * Write a value to PCI configuration space 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_cistatic int octeon_pcie_write_config(unsigned int pcie_port, struct pci_bus *bus, 17318c2ecf20Sopenharmony_ci unsigned int devfn, int reg, 17328c2ecf20Sopenharmony_ci int size, u32 val) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci int bus_number = bus->number; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if ((bus->parent == NULL) && (enable_pcie_bus_num_war[pcie_port])) 17398c2ecf20Sopenharmony_ci bus_number = 0; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci pr_debug("pcie_cfg_wr port=%d b=%d devfn=0x%03x" 17428c2ecf20Sopenharmony_ci " reg=0x%03x size=%d val=%08x\n", pcie_port, bus_number, devfn, 17438c2ecf20Sopenharmony_ci reg, size, val); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci switch (size) { 17478c2ecf20Sopenharmony_ci case 4: 17488c2ecf20Sopenharmony_ci cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3, 17498c2ecf20Sopenharmony_ci devfn & 0x7, reg, val); 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci case 2: 17528c2ecf20Sopenharmony_ci cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3, 17538c2ecf20Sopenharmony_ci devfn & 0x7, reg, val); 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case 1: 17568c2ecf20Sopenharmony_ci cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3, 17578c2ecf20Sopenharmony_ci devfn & 0x7, reg, val); 17588c2ecf20Sopenharmony_ci break; 17598c2ecf20Sopenharmony_ci default: 17608c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn, 17668c2ecf20Sopenharmony_ci int reg, int size, u32 val) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci return octeon_pcie_write_config(0, bus, devfn, reg, size, val); 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn, 17728c2ecf20Sopenharmony_ci int reg, int size, u32 val) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci return octeon_pcie_write_config(1, bus, devfn, reg, size, val); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn, 17788c2ecf20Sopenharmony_ci int reg, int size, u32 val) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic struct pci_ops octeon_pcie0_ops = { 17848c2ecf20Sopenharmony_ci .read = octeon_pcie0_read_config, 17858c2ecf20Sopenharmony_ci .write = octeon_pcie0_write_config, 17868c2ecf20Sopenharmony_ci}; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic struct resource octeon_pcie0_mem_resource = { 17898c2ecf20Sopenharmony_ci .name = "Octeon PCIe0 MEM", 17908c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 17918c2ecf20Sopenharmony_ci}; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_cistatic struct resource octeon_pcie0_io_resource = { 17948c2ecf20Sopenharmony_ci .name = "Octeon PCIe0 IO", 17958c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 17968c2ecf20Sopenharmony_ci}; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic struct pci_controller octeon_pcie0_controller = { 17998c2ecf20Sopenharmony_ci .pci_ops = &octeon_pcie0_ops, 18008c2ecf20Sopenharmony_ci .mem_resource = &octeon_pcie0_mem_resource, 18018c2ecf20Sopenharmony_ci .io_resource = &octeon_pcie0_io_resource, 18028c2ecf20Sopenharmony_ci}; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_cistatic struct pci_ops octeon_pcie1_ops = { 18058c2ecf20Sopenharmony_ci .read = octeon_pcie1_read_config, 18068c2ecf20Sopenharmony_ci .write = octeon_pcie1_write_config, 18078c2ecf20Sopenharmony_ci}; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cistatic struct resource octeon_pcie1_mem_resource = { 18108c2ecf20Sopenharmony_ci .name = "Octeon PCIe1 MEM", 18118c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 18128c2ecf20Sopenharmony_ci}; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic struct resource octeon_pcie1_io_resource = { 18158c2ecf20Sopenharmony_ci .name = "Octeon PCIe1 IO", 18168c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 18178c2ecf20Sopenharmony_ci}; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_cistatic struct pci_controller octeon_pcie1_controller = { 18208c2ecf20Sopenharmony_ci .pci_ops = &octeon_pcie1_ops, 18218c2ecf20Sopenharmony_ci .mem_resource = &octeon_pcie1_mem_resource, 18228c2ecf20Sopenharmony_ci .io_resource = &octeon_pcie1_io_resource, 18238c2ecf20Sopenharmony_ci}; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_cistatic struct pci_ops octeon_dummy_ops = { 18268c2ecf20Sopenharmony_ci .read = octeon_dummy_read_config, 18278c2ecf20Sopenharmony_ci .write = octeon_dummy_write_config, 18288c2ecf20Sopenharmony_ci}; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cistatic struct resource octeon_dummy_mem_resource = { 18318c2ecf20Sopenharmony_ci .name = "Virtual PCIe MEM", 18328c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 18338c2ecf20Sopenharmony_ci}; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_cistatic struct resource octeon_dummy_io_resource = { 18368c2ecf20Sopenharmony_ci .name = "Virtual PCIe IO", 18378c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 18388c2ecf20Sopenharmony_ci}; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic struct pci_controller octeon_dummy_controller = { 18418c2ecf20Sopenharmony_ci .pci_ops = &octeon_dummy_ops, 18428c2ecf20Sopenharmony_ci .mem_resource = &octeon_dummy_mem_resource, 18438c2ecf20Sopenharmony_ci .io_resource = &octeon_dummy_io_resource, 18448c2ecf20Sopenharmony_ci}; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int device_needs_bus_num_war(uint32_t deviceid) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci#define IDT_VENDOR_ID 0x111d 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if ((deviceid & 0xffff) == IDT_VENDOR_ID) 18518c2ecf20Sopenharmony_ci return 1; 18528c2ecf20Sopenharmony_ci return 0; 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci/** 18568c2ecf20Sopenharmony_ci * Initialize the Octeon PCIe controllers 18578c2ecf20Sopenharmony_ci * 18588c2ecf20Sopenharmony_ci * Returns 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_cistatic int __init octeon_pcie_setup(void) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci int result; 18638c2ecf20Sopenharmony_ci int host_mode; 18648c2ecf20Sopenharmony_ci int srio_war15205 = 0, port; 18658c2ecf20Sopenharmony_ci union cvmx_sli_ctl_portx sli_ctl_portx; 18668c2ecf20Sopenharmony_ci union cvmx_sriox_status_reg sriox_status_reg; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* These chips don't have PCIe */ 18698c2ecf20Sopenharmony_ci if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) 18708c2ecf20Sopenharmony_ci return 0; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci /* No PCIe simulation */ 18738c2ecf20Sopenharmony_ci if (octeon_is_simulation()) 18748c2ecf20Sopenharmony_ci return 0; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci /* Disable PCI if instructed on the command line */ 18778c2ecf20Sopenharmony_ci if (pcie_disable) 18788c2ecf20Sopenharmony_ci return 0; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci /* Point pcibios_map_irq() to the PCIe version of it */ 18818c2ecf20Sopenharmony_ci octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* 18848c2ecf20Sopenharmony_ci * PCIe I/O range. It is based on port 0 but includes up until 18858c2ecf20Sopenharmony_ci * port 1's end. 18868c2ecf20Sopenharmony_ci */ 18878c2ecf20Sopenharmony_ci set_io_port_base(CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0))); 18888c2ecf20Sopenharmony_ci ioport_resource.start = 0; 18898c2ecf20Sopenharmony_ci ioport_resource.end = 18908c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(1) - 18918c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* 18948c2ecf20Sopenharmony_ci * Create a dummy PCIe controller to swallow up bus 0. IDT bridges 18958c2ecf20Sopenharmony_ci * don't work if the primary bus number is zero. Here we add a fake 18968c2ecf20Sopenharmony_ci * PCIe controller that the kernel will give bus 0. This allows 18978c2ecf20Sopenharmony_ci * us to not change the normal kernel bus enumeration 18988c2ecf20Sopenharmony_ci */ 18998c2ecf20Sopenharmony_ci octeon_dummy_controller.io_map_base = -1; 19008c2ecf20Sopenharmony_ci octeon_dummy_controller.mem_resource->start = (1ull<<48); 19018c2ecf20Sopenharmony_ci octeon_dummy_controller.mem_resource->end = (1ull<<48); 19028c2ecf20Sopenharmony_ci register_pci_controller(&octeon_dummy_controller); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { 19058c2ecf20Sopenharmony_ci union cvmx_npei_ctl_status npei_ctl_status; 19068c2ecf20Sopenharmony_ci npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); 19078c2ecf20Sopenharmony_ci host_mode = npei_ctl_status.s.host_mode; 19088c2ecf20Sopenharmony_ci octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; 19098c2ecf20Sopenharmony_ci } else { 19108c2ecf20Sopenharmony_ci union cvmx_mio_rst_ctlx mio_rst_ctl; 19118c2ecf20Sopenharmony_ci mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(0)); 19128c2ecf20Sopenharmony_ci host_mode = mio_rst_ctl.s.host_mode; 19138c2ecf20Sopenharmony_ci octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE2; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (host_mode) { 19178c2ecf20Sopenharmony_ci pr_notice("PCIe: Initializing port 0\n"); 19188c2ecf20Sopenharmony_ci /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ 19198c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || 19208c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { 19218c2ecf20Sopenharmony_ci sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0)); 19228c2ecf20Sopenharmony_ci if (sriox_status_reg.s.srio) { 19238c2ecf20Sopenharmony_ci srio_war15205 += 1; /* Port is SRIO */ 19248c2ecf20Sopenharmony_ci port = 0; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci result = cvmx_pcie_rc_initialize(0); 19288c2ecf20Sopenharmony_ci if (result == 0) { 19298c2ecf20Sopenharmony_ci uint32_t device0; 19308c2ecf20Sopenharmony_ci /* Memory offsets are physical addresses */ 19318c2ecf20Sopenharmony_ci octeon_pcie0_controller.mem_offset = 19328c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(0); 19338c2ecf20Sopenharmony_ci /* IO offsets are Mips virtual addresses */ 19348c2ecf20Sopenharmony_ci octeon_pcie0_controller.io_map_base = 19358c2ecf20Sopenharmony_ci CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address 19368c2ecf20Sopenharmony_ci (0)); 19378c2ecf20Sopenharmony_ci octeon_pcie0_controller.io_offset = 0; 19388c2ecf20Sopenharmony_ci /* 19398c2ecf20Sopenharmony_ci * To keep things similar to PCI, we start 19408c2ecf20Sopenharmony_ci * device addresses at the same place as PCI 19418c2ecf20Sopenharmony_ci * uisng big bar support. This normally 19428c2ecf20Sopenharmony_ci * translates to 4GB-256MB, which is the same 19438c2ecf20Sopenharmony_ci * as most x86 PCs. 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_ci octeon_pcie0_controller.mem_resource->start = 19468c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(0) + 19478c2ecf20Sopenharmony_ci (4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20); 19488c2ecf20Sopenharmony_ci octeon_pcie0_controller.mem_resource->end = 19498c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(0) + 19508c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_size(0) - 1; 19518c2ecf20Sopenharmony_ci /* 19528c2ecf20Sopenharmony_ci * Ports must be above 16KB for the ISA bus 19538c2ecf20Sopenharmony_ci * filtering in the PCI-X to PCI bridge. 19548c2ecf20Sopenharmony_ci */ 19558c2ecf20Sopenharmony_ci octeon_pcie0_controller.io_resource->start = 4 << 10; 19568c2ecf20Sopenharmony_ci octeon_pcie0_controller.io_resource->end = 19578c2ecf20Sopenharmony_ci cvmx_pcie_get_io_size(0) - 1; 19588c2ecf20Sopenharmony_ci msleep(100); /* Some devices need extra time */ 19598c2ecf20Sopenharmony_ci register_pci_controller(&octeon_pcie0_controller); 19608c2ecf20Sopenharmony_ci device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0); 19618c2ecf20Sopenharmony_ci enable_pcie_bus_num_war[0] = 19628c2ecf20Sopenharmony_ci device_needs_bus_num_war(device0); 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci } else { 19658c2ecf20Sopenharmony_ci pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n"); 19668c2ecf20Sopenharmony_ci /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ 19678c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || 19688c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { 19698c2ecf20Sopenharmony_ci srio_war15205 += 1; 19708c2ecf20Sopenharmony_ci port = 0; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { 19758c2ecf20Sopenharmony_ci host_mode = 1; 19768c2ecf20Sopenharmony_ci /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ 19778c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { 19788c2ecf20Sopenharmony_ci union cvmx_npei_dbg_data dbg_data; 19798c2ecf20Sopenharmony_ci dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 19808c2ecf20Sopenharmony_ci if (dbg_data.cn52xx.qlm0_link_width) 19818c2ecf20Sopenharmony_ci host_mode = 0; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci } else { 19848c2ecf20Sopenharmony_ci union cvmx_mio_rst_ctlx mio_rst_ctl; 19858c2ecf20Sopenharmony_ci mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1)); 19868c2ecf20Sopenharmony_ci host_mode = mio_rst_ctl.s.host_mode; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci if (host_mode) { 19908c2ecf20Sopenharmony_ci pr_notice("PCIe: Initializing port 1\n"); 19918c2ecf20Sopenharmony_ci /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ 19928c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || 19938c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { 19948c2ecf20Sopenharmony_ci sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1)); 19958c2ecf20Sopenharmony_ci if (sriox_status_reg.s.srio) { 19968c2ecf20Sopenharmony_ci srio_war15205 += 1; /* Port is SRIO */ 19978c2ecf20Sopenharmony_ci port = 1; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci result = cvmx_pcie_rc_initialize(1); 20018c2ecf20Sopenharmony_ci if (result == 0) { 20028c2ecf20Sopenharmony_ci uint32_t device0; 20038c2ecf20Sopenharmony_ci /* Memory offsets are physical addresses */ 20048c2ecf20Sopenharmony_ci octeon_pcie1_controller.mem_offset = 20058c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(1); 20068c2ecf20Sopenharmony_ci /* 20078c2ecf20Sopenharmony_ci * To calculate the address for accessing the 2nd PCIe device, 20088c2ecf20Sopenharmony_ci * either 'io_map_base' (pci_iomap()), or 'mips_io_port_base' 20098c2ecf20Sopenharmony_ci * (ioport_map()) value is added to 20108c2ecf20Sopenharmony_ci * pci_resource_start(dev,bar)). The 'mips_io_port_base' is set 20118c2ecf20Sopenharmony_ci * only once based on first PCIe. Also changing 'io_map_base' 20128c2ecf20Sopenharmony_ci * based on first slot's value so that both the routines will 20138c2ecf20Sopenharmony_ci * work properly. 20148c2ecf20Sopenharmony_ci */ 20158c2ecf20Sopenharmony_ci octeon_pcie1_controller.io_map_base = 20168c2ecf20Sopenharmony_ci CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)); 20178c2ecf20Sopenharmony_ci /* IO offsets are Mips virtual addresses */ 20188c2ecf20Sopenharmony_ci octeon_pcie1_controller.io_offset = 20198c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(1) - 20208c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(0); 20218c2ecf20Sopenharmony_ci /* 20228c2ecf20Sopenharmony_ci * To keep things similar to PCI, we start device 20238c2ecf20Sopenharmony_ci * addresses at the same place as PCI uisng big bar 20248c2ecf20Sopenharmony_ci * support. This normally translates to 4GB-256MB, 20258c2ecf20Sopenharmony_ci * which is the same as most x86 PCs. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_ci octeon_pcie1_controller.mem_resource->start = 20288c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - 20298c2ecf20Sopenharmony_ci (OCTEON_PCI_BAR1_HOLE_SIZE << 20); 20308c2ecf20Sopenharmony_ci octeon_pcie1_controller.mem_resource->end = 20318c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_base_address(1) + 20328c2ecf20Sopenharmony_ci cvmx_pcie_get_mem_size(1) - 1; 20338c2ecf20Sopenharmony_ci /* 20348c2ecf20Sopenharmony_ci * Ports must be above 16KB for the ISA bus filtering 20358c2ecf20Sopenharmony_ci * in the PCI-X to PCI bridge. 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci octeon_pcie1_controller.io_resource->start = 20388c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(1) - 20398c2ecf20Sopenharmony_ci cvmx_pcie_get_io_base_address(0); 20408c2ecf20Sopenharmony_ci octeon_pcie1_controller.io_resource->end = 20418c2ecf20Sopenharmony_ci octeon_pcie1_controller.io_resource->start + 20428c2ecf20Sopenharmony_ci cvmx_pcie_get_io_size(1) - 1; 20438c2ecf20Sopenharmony_ci msleep(100); /* Some devices need extra time */ 20448c2ecf20Sopenharmony_ci register_pci_controller(&octeon_pcie1_controller); 20458c2ecf20Sopenharmony_ci device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0); 20468c2ecf20Sopenharmony_ci enable_pcie_bus_num_war[1] = 20478c2ecf20Sopenharmony_ci device_needs_bus_num_war(device0); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci } else { 20508c2ecf20Sopenharmony_ci pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n"); 20518c2ecf20Sopenharmony_ci /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ 20528c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || 20538c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { 20548c2ecf20Sopenharmony_ci srio_war15205 += 1; 20558c2ecf20Sopenharmony_ci port = 1; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci /* 20608c2ecf20Sopenharmony_ci * CN63XX pass 1_x/2.0 errata PCIe-15205 requires setting all 20618c2ecf20Sopenharmony_ci * of SRIO MACs SLI_CTL_PORT*[INT*_MAP] to similar value and 20628c2ecf20Sopenharmony_ci * all of PCIe Macs SLI_CTL_PORT*[INT*_MAP] to different value 20638c2ecf20Sopenharmony_ci * from the previous set values 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || 20668c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { 20678c2ecf20Sopenharmony_ci if (srio_war15205 == 1) { 20688c2ecf20Sopenharmony_ci sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(port)); 20698c2ecf20Sopenharmony_ci sli_ctl_portx.s.inta_map = 1; 20708c2ecf20Sopenharmony_ci sli_ctl_portx.s.intb_map = 1; 20718c2ecf20Sopenharmony_ci sli_ctl_portx.s.intc_map = 1; 20728c2ecf20Sopenharmony_ci sli_ctl_portx.s.intd_map = 1; 20738c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(port), sli_ctl_portx.u64); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(!port)); 20768c2ecf20Sopenharmony_ci sli_ctl_portx.s.inta_map = 0; 20778c2ecf20Sopenharmony_ci sli_ctl_portx.s.intb_map = 0; 20788c2ecf20Sopenharmony_ci sli_ctl_portx.s.intc_map = 0; 20798c2ecf20Sopenharmony_ci sli_ctl_portx.s.intd_map = 0; 20808c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(!port), sli_ctl_portx.u64); 20818c2ecf20Sopenharmony_ci } 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci octeon_pci_dma_init(); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci return 0; 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ciarch_initcall(octeon_pcie_setup); 2089