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