cvmx-pcie.c revision 210284
1210284Sjmallett/***********************license start*************** 2210284Sjmallett * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3210284Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6210284Sjmallett * Redistribution and use in source and binary forms, with or without 7210284Sjmallett * modification, are permitted provided that the following conditions are 8210284Sjmallett * met: 9210284Sjmallett * 10210284Sjmallett * * Redistributions of source code must retain the above copyright 11210284Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13210284Sjmallett * * Redistributions in binary form must reproduce the above 14210284Sjmallett * copyright notice, this list of conditions and the following 15210284Sjmallett * disclaimer in the documentation and/or other materials provided 16210284Sjmallett * with the distribution. 17210284Sjmallett * 18210284Sjmallett * * Neither the name of Cavium Networks nor the names of 19210284Sjmallett * its contributors may be used to endorse or promote products 20210284Sjmallett * derived from this software without specific prior written 21210284Sjmallett * permission. 22210284Sjmallett * 23210284Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24210284Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25210284Sjmallett * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26210284Sjmallett * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27210284Sjmallett * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28210284Sjmallett * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29210284Sjmallett * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30210284Sjmallett * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31210284Sjmallett * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32210284Sjmallett * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33210284Sjmallett * 34210284Sjmallett * 35210284Sjmallett * For any questions regarding licensing please contact marketing@caviumnetworks.com 36210284Sjmallett * 37210284Sjmallett ***********************license end**************************************/ 38210284Sjmallett 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett/** 45210284Sjmallett * @file 46210284Sjmallett * 47210284Sjmallett * Interface to PCIe as a host(RC) or target(EP) 48210284Sjmallett * 49210284Sjmallett * <hr>$Revision: 41586 $<hr> 50210284Sjmallett */ 51210284Sjmallett#include "cvmx.h" 52210284Sjmallett#include "cvmx-csr-db.h" 53210284Sjmallett#include "cvmx-pcie.h" 54210284Sjmallett#include "cvmx-sysinfo.h" 55210284Sjmallett#include "cvmx-swap.h" 56210284Sjmallett#include "cvmx-wqe.h" 57210284Sjmallett#include "cvmx-helper-errata.h" 58210284Sjmallett 59210284Sjmallett 60210284Sjmallett/** 61210284Sjmallett * Return the Core virtual base address for PCIe IO access. IOs are 62210284Sjmallett * read/written as an offset from this address. 63210284Sjmallett * 64210284Sjmallett * @param pcie_port PCIe port the IO is for 65210284Sjmallett * 66210284Sjmallett * @return 64bit Octeon IO base address for read/write 67210284Sjmallett */ 68210284Sjmallettuint64_t cvmx_pcie_get_io_base_address(int pcie_port) 69210284Sjmallett{ 70210284Sjmallett cvmx_pcie_address_t pcie_addr; 71210284Sjmallett pcie_addr.u64 = 0; 72210284Sjmallett pcie_addr.io.upper = 0; 73210284Sjmallett pcie_addr.io.io = 1; 74210284Sjmallett pcie_addr.io.did = 3; 75210284Sjmallett pcie_addr.io.subdid = 2; 76210284Sjmallett pcie_addr.io.es = 1; 77210284Sjmallett pcie_addr.io.port = pcie_port; 78210284Sjmallett return pcie_addr.u64; 79210284Sjmallett} 80210284Sjmallett 81210284Sjmallett 82210284Sjmallett/** 83210284Sjmallett * Size of the IO address region returned at address 84210284Sjmallett * cvmx_pcie_get_io_base_address() 85210284Sjmallett * 86210284Sjmallett * @param pcie_port PCIe port the IO is for 87210284Sjmallett * 88210284Sjmallett * @return Size of the IO window 89210284Sjmallett */ 90210284Sjmallettuint64_t cvmx_pcie_get_io_size(int pcie_port) 91210284Sjmallett{ 92210284Sjmallett return 1ull<<32; 93210284Sjmallett} 94210284Sjmallett 95210284Sjmallett 96210284Sjmallett/** 97210284Sjmallett * Return the Core virtual base address for PCIe MEM access. Memory is 98210284Sjmallett * read/written as an offset from this address. 99210284Sjmallett * 100210284Sjmallett * @param pcie_port PCIe port the IO is for 101210284Sjmallett * 102210284Sjmallett * @return 64bit Octeon IO base address for read/write 103210284Sjmallett */ 104210284Sjmallettuint64_t cvmx_pcie_get_mem_base_address(int pcie_port) 105210284Sjmallett{ 106210284Sjmallett cvmx_pcie_address_t pcie_addr; 107210284Sjmallett pcie_addr.u64 = 0; 108210284Sjmallett pcie_addr.mem.upper = 0; 109210284Sjmallett pcie_addr.mem.io = 1; 110210284Sjmallett pcie_addr.mem.did = 3; 111210284Sjmallett pcie_addr.mem.subdid = 3 + pcie_port; 112210284Sjmallett return pcie_addr.u64; 113210284Sjmallett} 114210284Sjmallett 115210284Sjmallett 116210284Sjmallett/** 117210284Sjmallett * Size of the Mem address region returned at address 118210284Sjmallett * cvmx_pcie_get_mem_base_address() 119210284Sjmallett * 120210284Sjmallett * @param pcie_port PCIe port the IO is for 121210284Sjmallett * 122210284Sjmallett * @return Size of the Mem window 123210284Sjmallett */ 124210284Sjmallettuint64_t cvmx_pcie_get_mem_size(int pcie_port) 125210284Sjmallett{ 126210284Sjmallett return 1ull<<36; 127210284Sjmallett} 128210284Sjmallett 129210284Sjmallett 130210284Sjmallett/** 131210284Sjmallett * @INTERNAL 132210284Sjmallett * Initialize the RC config space CSRs 133210284Sjmallett * 134210284Sjmallett * @param pcie_port PCIe port to initialize 135210284Sjmallett */ 136210284Sjmallettstatic void __cvmx_pcie_rc_initialize_config_space(int pcie_port) 137210284Sjmallett{ 138210284Sjmallett /* Max Payload Size (PCIE*_CFG030[MPS]) */ 139210284Sjmallett /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ 140210284Sjmallett /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ 141210284Sjmallett /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ 142210284Sjmallett { 143210284Sjmallett cvmx_pciercx_cfg030_t pciercx_cfg030; 144210284Sjmallett pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); 145210284Sjmallett pciercx_cfg030.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ 146210284Sjmallett pciercx_cfg030.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ 147210284Sjmallett pciercx_cfg030.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */ 148210284Sjmallett pciercx_cfg030.s.ns_en = 1; /* Enable no snoop processing. Not used by Octeon */ 149210284Sjmallett pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */ 150210284Sjmallett pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */ 151210284Sjmallett pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */ 152210284Sjmallett pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */ 153210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); 154210284Sjmallett } 155210284Sjmallett 156210284Sjmallett /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */ 157210284Sjmallett /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */ 158210284Sjmallett { 159210284Sjmallett cvmx_npei_ctl_status2_t npei_ctl_status2; 160210284Sjmallett npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); 161210284Sjmallett npei_ctl_status2.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ 162210284Sjmallett npei_ctl_status2.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ 163210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); 164210284Sjmallett } 165210284Sjmallett 166210284Sjmallett /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ 167210284Sjmallett { 168210284Sjmallett cvmx_pciercx_cfg070_t pciercx_cfg070; 169210284Sjmallett pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); 170210284Sjmallett pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ 171210284Sjmallett pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ 172210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); 173210284Sjmallett } 174210284Sjmallett 175210284Sjmallett /* Access Enables (PCIE*_CFG001[MSAE,ME]) */ 176210284Sjmallett /* ME and MSAE should always be set. */ 177210284Sjmallett /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */ 178210284Sjmallett /* System Error Message Enable (PCIE*_CFG001[SEE]) */ 179210284Sjmallett { 180210284Sjmallett cvmx_pciercx_cfg001_t pciercx_cfg001; 181210284Sjmallett pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); 182210284Sjmallett pciercx_cfg001.s.msae = 1; /* Memory space enable. */ 183210284Sjmallett pciercx_cfg001.s.me = 1; /* Bus master enable. */ 184210284Sjmallett pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ 185210284Sjmallett pciercx_cfg001.s.see = 1; /* SERR# enable */ 186210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); 187210284Sjmallett } 188210284Sjmallett 189210284Sjmallett 190210284Sjmallett /* Advanced Error Recovery Message Enables */ 191210284Sjmallett /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ 192210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0); 193210284Sjmallett /* Use CVMX_PCIERCX_CFG067 hardware default */ 194210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); 195210284Sjmallett 196210284Sjmallett 197210284Sjmallett /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ 198210284Sjmallett { 199210284Sjmallett cvmx_pciercx_cfg032_t pciercx_cfg032; 200210284Sjmallett pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 201210284Sjmallett pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ 202210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); 203210284Sjmallett } 204210284Sjmallett 205210284Sjmallett /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ 206210284Sjmallett // FIXME: Anything needed here? 207210284Sjmallett 208210284Sjmallett /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during cvmx_pcie_rc_initialize_link() */ 209210284Sjmallett /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */ 210210284Sjmallett { 211210284Sjmallett /* We set the primary bus number to 1 so IDT bridges are happy. They don't like zero */ 212210284Sjmallett cvmx_pciercx_cfg006_t pciercx_cfg006; 213210284Sjmallett pciercx_cfg006.u32 = 0; 214210284Sjmallett pciercx_cfg006.s.pbnum = 1; 215210284Sjmallett pciercx_cfg006.s.sbnum = 1; 216210284Sjmallett pciercx_cfg006.s.subbnum = 1; 217210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); 218210284Sjmallett } 219210284Sjmallett 220210284Sjmallett /* Memory-mapped I/O BAR (PCIERCn_CFG008) */ 221210284Sjmallett /* Most applications should disable the memory-mapped I/O BAR by */ 222210284Sjmallett /* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */ 223210284Sjmallett { 224210284Sjmallett cvmx_pciercx_cfg008_t pciercx_cfg008; 225210284Sjmallett pciercx_cfg008.u32 = 0; 226210284Sjmallett pciercx_cfg008.s.mb_addr = 0x100; 227210284Sjmallett pciercx_cfg008.s.ml_addr = 0; 228210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); 229210284Sjmallett } 230210284Sjmallett 231210284Sjmallett /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */ 232210284Sjmallett /* Most applications should disable the prefetchable BAR by setting */ 233210284Sjmallett /* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */ 234210284Sjmallett /* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */ 235210284Sjmallett { 236210284Sjmallett cvmx_pciercx_cfg009_t pciercx_cfg009; 237210284Sjmallett cvmx_pciercx_cfg010_t pciercx_cfg010; 238210284Sjmallett cvmx_pciercx_cfg011_t pciercx_cfg011; 239210284Sjmallett pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); 240210284Sjmallett pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); 241210284Sjmallett pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); 242210284Sjmallett pciercx_cfg009.s.lmem_base = 0x100; 243210284Sjmallett pciercx_cfg009.s.lmem_limit = 0; 244210284Sjmallett pciercx_cfg010.s.umem_base = 0x100; 245210284Sjmallett pciercx_cfg011.s.umem_limit = 0; 246210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); 247210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); 248210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); 249210284Sjmallett } 250210284Sjmallett 251210284Sjmallett /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */ 252210284Sjmallett /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */ 253210284Sjmallett { 254210284Sjmallett cvmx_pciercx_cfg035_t pciercx_cfg035; 255210284Sjmallett pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); 256210284Sjmallett pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ 257210284Sjmallett pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ 258210284Sjmallett pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ 259210284Sjmallett pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ 260210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); 261210284Sjmallett } 262210284Sjmallett 263210284Sjmallett /* Advanced Error Recovery Interrupt Enables */ 264210284Sjmallett /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */ 265210284Sjmallett { 266210284Sjmallett cvmx_pciercx_cfg075_t pciercx_cfg075; 267210284Sjmallett pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); 268210284Sjmallett pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ 269210284Sjmallett pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ 270210284Sjmallett pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ 271210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); 272210284Sjmallett } 273210284Sjmallett 274210284Sjmallett /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */ 275210284Sjmallett /* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */ 276210284Sjmallett { 277210284Sjmallett cvmx_pciercx_cfg034_t pciercx_cfg034; 278210284Sjmallett pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); 279210284Sjmallett pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ 280210284Sjmallett pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ 281210284Sjmallett pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ 282210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); 283210284Sjmallett } 284210284Sjmallett} 285210284Sjmallett 286210284Sjmallett 287210284Sjmallett/** 288210284Sjmallett * @INTERNAL 289210284Sjmallett * Initialize a host mode PCIe link. This function takes a PCIe 290210284Sjmallett * port from reset to a link up state. Software can then begin 291210284Sjmallett * configuring the rest of the link. 292210284Sjmallett * 293210284Sjmallett * @param pcie_port PCIe port to initialize 294210284Sjmallett * 295210284Sjmallett * @return Zero on success 296210284Sjmallett */ 297210284Sjmallettstatic int __cvmx_pcie_rc_initialize_link(int pcie_port) 298210284Sjmallett{ 299210284Sjmallett uint64_t start_cycle; 300210284Sjmallett cvmx_pescx_ctl_status_t pescx_ctl_status; 301210284Sjmallett cvmx_pciercx_cfg452_t pciercx_cfg452; 302210284Sjmallett cvmx_pciercx_cfg032_t pciercx_cfg032; 303210284Sjmallett cvmx_pciercx_cfg448_t pciercx_cfg448; 304210284Sjmallett 305210284Sjmallett /* Set the lane width */ 306210284Sjmallett pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); 307210284Sjmallett pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); 308210284Sjmallett if (pescx_ctl_status.s.qlm_cfg == 0) 309210284Sjmallett { 310210284Sjmallett /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ 311210284Sjmallett pciercx_cfg452.s.lme = 0xf; 312210284Sjmallett } 313210284Sjmallett else 314210284Sjmallett { 315210284Sjmallett /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ 316210284Sjmallett pciercx_cfg452.s.lme = 0x7; 317210284Sjmallett } 318210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); 319210284Sjmallett 320210284Sjmallett /* CN52XX pass 1.x has an errata where length mismatches on UR responses can 321210284Sjmallett cause bus errors on 64bit memory reads. Turning off length error 322210284Sjmallett checking fixes this */ 323210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 324210284Sjmallett { 325210284Sjmallett cvmx_pciercx_cfg455_t pciercx_cfg455; 326210284Sjmallett pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); 327210284Sjmallett pciercx_cfg455.s.m_cpl_len_err = 1; 328210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); 329210284Sjmallett } 330210284Sjmallett 331210284Sjmallett /* Lane swap needs to be manually enabled for CN52XX */ 332210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) 333210284Sjmallett { 334210284Sjmallett pescx_ctl_status.s.lane_swp = 1; 335210284Sjmallett cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),pescx_ctl_status.u64); 336210284Sjmallett } 337210284Sjmallett 338210284Sjmallett /* Bring up the link */ 339210284Sjmallett pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); 340210284Sjmallett pescx_ctl_status.s.lnk_enb = 1; 341210284Sjmallett cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); 342210284Sjmallett 343210284Sjmallett /* CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to be disabled */ 344210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) 345210284Sjmallett __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); 346210284Sjmallett 347210284Sjmallett /* Wait for the link to come up */ 348210284Sjmallett start_cycle = cvmx_get_cycle(); 349210284Sjmallett do 350210284Sjmallett { 351210284Sjmallett if (cvmx_get_cycle() - start_cycle > 2*cvmx_sysinfo_get()->cpu_clock_hz) 352210284Sjmallett { 353210284Sjmallett cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); 354210284Sjmallett return -1; 355210284Sjmallett } 356210284Sjmallett cvmx_wait(10000); 357210284Sjmallett pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 358210284Sjmallett } while (pciercx_cfg032.s.dlla == 0); 359210284Sjmallett 360210284Sjmallett /* Update the Replay Time Limit. Empirically, some PCIe devices take a 361210284Sjmallett little longer to respond than expected under load. As a workaround for 362210284Sjmallett this we configure the Replay Time Limit to the value expected for a 512 363210284Sjmallett byte MPS instead of our actual 256 byte MPS. The numbers below are 364210284Sjmallett directly from the PCIe spec table 3-4 */ 365210284Sjmallett pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); 366210284Sjmallett switch (pciercx_cfg032.s.nlw) 367210284Sjmallett { 368210284Sjmallett case 1: /* 1 lane */ 369210284Sjmallett pciercx_cfg448.s.rtl = 1677; 370210284Sjmallett break; 371210284Sjmallett case 2: /* 2 lanes */ 372210284Sjmallett pciercx_cfg448.s.rtl = 867; 373210284Sjmallett break; 374210284Sjmallett case 4: /* 4 lanes */ 375210284Sjmallett pciercx_cfg448.s.rtl = 462; 376210284Sjmallett break; 377210284Sjmallett case 8: /* 8 lanes */ 378210284Sjmallett pciercx_cfg448.s.rtl = 258; 379210284Sjmallett break; 380210284Sjmallett } 381210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); 382210284Sjmallett 383210284Sjmallett return 0; 384210284Sjmallett} 385210284Sjmallett 386210284Sjmallett 387210284Sjmallett/** 388210284Sjmallett * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. 389210284Sjmallett * 390210284Sjmallett * @param pcie_port PCIe port to initialize 391210284Sjmallett * 392210284Sjmallett * @return Zero on success 393210284Sjmallett */ 394210284Sjmallettint cvmx_pcie_rc_initialize(int pcie_port) 395210284Sjmallett{ 396210284Sjmallett int i; 397210284Sjmallett cvmx_ciu_soft_prst_t ciu_soft_prst; 398210284Sjmallett cvmx_pescx_bist_status_t pescx_bist_status; 399210284Sjmallett cvmx_pescx_bist_status2_t pescx_bist_status2; 400210284Sjmallett cvmx_npei_ctl_status_t npei_ctl_status; 401210284Sjmallett cvmx_npei_mem_access_ctl_t npei_mem_access_ctl; 402210284Sjmallett cvmx_npei_mem_access_subidx_t mem_access_subid; 403210284Sjmallett cvmx_npei_dbg_data_t npei_dbg_data; 404210284Sjmallett cvmx_pescx_ctl_status2_t pescx_ctl_status2; 405210284Sjmallett cvmx_pciercx_cfg032_t pciercx_cfg032; 406210284Sjmallett 407210284Sjmallettretry: 408210284Sjmallett /* Make sure we aren't trying to setup a target mode interface in host mode */ 409210284Sjmallett npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); 410210284Sjmallett if ((pcie_port==0) && !npei_ctl_status.s.host_mode) 411210284Sjmallett { 412210284Sjmallett cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port0, but port0 is not in host mode\n"); 413210284Sjmallett return -1; 414210284Sjmallett } 415210284Sjmallett 416210284Sjmallett /* Make sure a CN52XX isn't trying to bring up port 1 when it is disabled */ 417210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 418210284Sjmallett { 419210284Sjmallett npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 420210284Sjmallett if ((pcie_port==1) && npei_dbg_data.cn52xx.qlm0_link_width) 421210284Sjmallett { 422210284Sjmallett cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n"); 423210284Sjmallett return -1; 424210284Sjmallett } 425210284Sjmallett } 426210284Sjmallett 427210284Sjmallett /* PCIe switch arbitration mode. '0' == fixed priority NPEI, PCIe0, then PCIe1. '1' == round robin. */ 428210284Sjmallett npei_ctl_status.s.arb = 1; 429210284Sjmallett /* Allow up to 0x20 config retries */ 430210284Sjmallett npei_ctl_status.s.cfg_rtry = 0x20; 431210284Sjmallett /* CN52XX pass1.x has an errata where P0_NTAGS and P1_NTAGS don't reset */ 432210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 433210284Sjmallett { 434210284Sjmallett npei_ctl_status.s.p0_ntags = 0x20; 435210284Sjmallett npei_ctl_status.s.p1_ntags = 0x20; 436210284Sjmallett } 437210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS, npei_ctl_status.u64); 438210284Sjmallett 439210284Sjmallett /* Bring the PCIe out of reset */ 440210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) 441210284Sjmallett { 442210284Sjmallett /* The EBH5200 board swapped the PCIe reset lines on the board. As a 443210284Sjmallett workaround for this bug, we bring both PCIe ports out of reset at 444210284Sjmallett the same time instead of on separate calls. So for port 0, we bring 445210284Sjmallett both out of reset and do nothing on port 1 */ 446210284Sjmallett if (pcie_port == 0) 447210284Sjmallett { 448210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 449210284Sjmallett /* After a chip reset the PCIe will also be in reset. If it isn't, 450210284Sjmallett most likely someone is trying to init it again without a proper 451210284Sjmallett PCIe reset */ 452210284Sjmallett if (ciu_soft_prst.s.soft_prst == 0) 453210284Sjmallett { 454210284Sjmallett /* Reset the ports */ 455210284Sjmallett ciu_soft_prst.s.soft_prst = 1; 456210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 457210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 458210284Sjmallett ciu_soft_prst.s.soft_prst = 1; 459210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 460210284Sjmallett /* Wait until pcie resets the ports. */ 461210284Sjmallett cvmx_wait_usec(2000); 462210284Sjmallett } 463210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 464210284Sjmallett ciu_soft_prst.s.soft_prst = 0; 465210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 466210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 467210284Sjmallett ciu_soft_prst.s.soft_prst = 0; 468210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 469210284Sjmallett } 470210284Sjmallett } 471210284Sjmallett else 472210284Sjmallett { 473210284Sjmallett /* The normal case: The PCIe ports are completely separate and can be 474210284Sjmallett brought out of reset independently */ 475210284Sjmallett if (pcie_port) 476210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 477210284Sjmallett else 478210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 479210284Sjmallett /* After a chip reset the PCIe will also be in reset. If it isn't, 480210284Sjmallett most likely someone is trying to init it again without a proper 481210284Sjmallett PCIe reset */ 482210284Sjmallett if (ciu_soft_prst.s.soft_prst == 0) 483210284Sjmallett { 484210284Sjmallett /* Reset the port */ 485210284Sjmallett ciu_soft_prst.s.soft_prst = 1; 486210284Sjmallett if (pcie_port) 487210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 488210284Sjmallett else 489210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 490210284Sjmallett /* Wait until pcie resets the ports. */ 491210284Sjmallett cvmx_wait_usec(2000); 492210284Sjmallett } 493210284Sjmallett if (pcie_port) 494210284Sjmallett { 495210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 496210284Sjmallett ciu_soft_prst.s.soft_prst = 0; 497210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 498210284Sjmallett } 499210284Sjmallett else 500210284Sjmallett { 501210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 502210284Sjmallett ciu_soft_prst.s.soft_prst = 0; 503210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 504210284Sjmallett } 505210284Sjmallett } 506210284Sjmallett 507210284Sjmallett /* Wait for PCIe reset to complete. Due to errata PCIE-700, we don't poll 508210284Sjmallett PESCX_CTL_STATUS2[PCIERST], but simply wait a fixed number of cycles */ 509210284Sjmallett cvmx_wait(400000); 510210284Sjmallett 511210284Sjmallett /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and 512210284Sjmallett CN52XX, so we only probe it on newer chips */ 513210284Sjmallett if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 514210284Sjmallett { 515210284Sjmallett /* Clear PCLK_RUN so we can check if the clock is running */ 516210284Sjmallett pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); 517210284Sjmallett pescx_ctl_status2.s.pclk_run = 1; 518210284Sjmallett cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); 519210284Sjmallett /* Now that we cleared PCLK_RUN, wait for it to be set again telling 520210284Sjmallett us the clock is running */ 521210284Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), 522210284Sjmallett cvmx_pescx_ctl_status2_t, pclk_run, ==, 1, 10000)) 523210284Sjmallett { 524210284Sjmallett cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port); 525210284Sjmallett return -1; 526210284Sjmallett } 527210284Sjmallett } 528210284Sjmallett 529210284Sjmallett /* Check and make sure PCIe came out of reset. If it doesn't the board 530210284Sjmallett probably hasn't wired the clocks up and the interface should be 531210284Sjmallett skipped */ 532210284Sjmallett pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); 533210284Sjmallett if (pescx_ctl_status2.s.pcierst) 534210284Sjmallett { 535210284Sjmallett cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); 536210284Sjmallett return -1; 537210284Sjmallett } 538210284Sjmallett 539210284Sjmallett /* Check BIST2 status. If any bits are set skip this interface. This 540210284Sjmallett is an attempt to catch PCIE-813 on pass 1 parts */ 541210284Sjmallett pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); 542210284Sjmallett if (pescx_bist_status2.u64) 543210284Sjmallett { 544210284Sjmallett cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", pcie_port); 545210284Sjmallett return -1; 546210284Sjmallett } 547210284Sjmallett 548210284Sjmallett /* Check BIST status */ 549210284Sjmallett pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); 550210284Sjmallett if (pescx_bist_status.u64) 551210284Sjmallett cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pescx_bist_status.u64)); 552210284Sjmallett 553210284Sjmallett /* Initialize the config space CSRs */ 554210284Sjmallett __cvmx_pcie_rc_initialize_config_space(pcie_port); 555210284Sjmallett 556210284Sjmallett /* Bring the link up */ 557210284Sjmallett if (__cvmx_pcie_rc_initialize_link(pcie_port)) 558210284Sjmallett { 559210284Sjmallett cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n"); 560210284Sjmallett return -1; 561210284Sjmallett } 562210284Sjmallett 563210284Sjmallett /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ 564210284Sjmallett npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL); 565210284Sjmallett npei_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ 566210284Sjmallett npei_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ 567210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64); 568210284Sjmallett 569210284Sjmallett /* Setup Mem access SubDIDs */ 570210284Sjmallett mem_access_subid.u64 = 0; 571210284Sjmallett mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ 572210284Sjmallett mem_access_subid.s.nmerge = 1; /* Due to an errata on pass 1 chips, no merging is allowed. */ 573210284Sjmallett mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ 574210284Sjmallett mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ 575210284Sjmallett mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ 576210284Sjmallett mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */ 577210284Sjmallett mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */ 578210284Sjmallett mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */ 579210284Sjmallett mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ 580210284Sjmallett 581210284Sjmallett /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */ 582210284Sjmallett for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++) 583210284Sjmallett { 584210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); 585210284Sjmallett mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */ 586210284Sjmallett } 587210284Sjmallett 588210284Sjmallett /* Disable the peer to peer forwarding register. This must be setup 589210284Sjmallett by the OS after it enumerates the bus and assigns addresses to the 590210284Sjmallett PCIe busses */ 591210284Sjmallett for (i=0; i<4; i++) 592210284Sjmallett { 593210284Sjmallett cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1); 594210284Sjmallett cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1); 595210284Sjmallett } 596210284Sjmallett 597210284Sjmallett /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ 598210284Sjmallett cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); 599210284Sjmallett 600210284Sjmallett /* Disable Octeon's BAR1. It isn't needed in RC mode since BAR2 601210284Sjmallett maps all of memory. BAR2 also maps 256MB-512MB into the 2nd 602210284Sjmallett 256MB of memory */ 603210284Sjmallett cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), -1); 604210284Sjmallett 605210284Sjmallett /* Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take precedence 606210284Sjmallett where they overlap. It also overlaps with the device addresses, so 607210284Sjmallett make sure the peer to peer forwarding is set right */ 608210284Sjmallett cvmx_write_csr(CVMX_PESCX_P2N_BAR2_START(pcie_port), 0); 609210284Sjmallett 610210284Sjmallett /* Setup BAR2 attributes */ 611210284Sjmallett /* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */ 612210284Sjmallett /* � PTLP_RO,CTLP_RO should normally be set (except for debug). */ 613210284Sjmallett /* � WAIT_COM=0 will likely work for all applications. */ 614210284Sjmallett /* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */ 615210284Sjmallett if (pcie_port) 616210284Sjmallett { 617210284Sjmallett cvmx_npei_ctl_port1_t npei_ctl_port; 618210284Sjmallett npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT1); 619210284Sjmallett npei_ctl_port.s.bar2_enb = 1; 620210284Sjmallett npei_ctl_port.s.bar2_esx = 1; 621210284Sjmallett npei_ctl_port.s.bar2_cax = 0; 622210284Sjmallett npei_ctl_port.s.ptlp_ro = 1; 623210284Sjmallett npei_ctl_port.s.ctlp_ro = 1; 624210284Sjmallett npei_ctl_port.s.wait_com = 0; 625210284Sjmallett npei_ctl_port.s.waitl_com = 0; 626210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT1, npei_ctl_port.u64); 627210284Sjmallett } 628210284Sjmallett else 629210284Sjmallett { 630210284Sjmallett cvmx_npei_ctl_port0_t npei_ctl_port; 631210284Sjmallett npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT0); 632210284Sjmallett npei_ctl_port.s.bar2_enb = 1; 633210284Sjmallett npei_ctl_port.s.bar2_esx = 1; 634210284Sjmallett npei_ctl_port.s.bar2_cax = 0; 635210284Sjmallett npei_ctl_port.s.ptlp_ro = 1; 636210284Sjmallett npei_ctl_port.s.ctlp_ro = 1; 637210284Sjmallett npei_ctl_port.s.wait_com = 0; 638210284Sjmallett npei_ctl_port.s.waitl_com = 0; 639210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64); 640210284Sjmallett } 641210284Sjmallett 642210284Sjmallett /* Both pass 1 and pass 2 of CN52XX and CN56XX have an errata that causes 643210284Sjmallett TLP ordering to not be preserved after multiple PCIe port resets. This 644210284Sjmallett code detects this fault and corrects it by aligning the TLP counters 645210284Sjmallett properly. Another link reset is then performed. See PCIE-13340 */ 646210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) || 647210284Sjmallett OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 648210284Sjmallett { 649210284Sjmallett cvmx_npei_dbg_data_t dbg_data; 650210284Sjmallett int old_in_fif_p_count; 651210284Sjmallett int in_fif_p_count; 652210284Sjmallett int out_p_count; 653210284Sjmallett int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1; 654210284Sjmallett int i; 655210284Sjmallett 656210284Sjmallett /* Choose a write address of 1MB. It should be harmless as all bars 657210284Sjmallett haven't been setup */ 658210284Sjmallett uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63); 659210284Sjmallett 660210284Sjmallett /* Make sure at least in_p_offset have been executed before we try and 661210284Sjmallett read in_fif_p_count */ 662210284Sjmallett i = in_p_offset; 663210284Sjmallett while (i--) 664210284Sjmallett { 665210284Sjmallett cvmx_write64_uint32(write_address, 0); 666210284Sjmallett cvmx_wait(10000); 667210284Sjmallett } 668210284Sjmallett 669210284Sjmallett /* Read the IN_FIF_P_COUNT from the debug select. IN_FIF_P_COUNT can be 670210284Sjmallett unstable sometimes so read it twice with a write between the reads. 671210284Sjmallett This way we can tell the value is good as it will increment by one 672210284Sjmallett due to the write */ 673210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc); 674210284Sjmallett cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); 675210284Sjmallett do 676210284Sjmallett { 677210284Sjmallett dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 678210284Sjmallett old_in_fif_p_count = dbg_data.s.data & 0xff; 679210284Sjmallett cvmx_write64_uint32(write_address, 0); 680210284Sjmallett cvmx_wait(10000); 681210284Sjmallett dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 682210284Sjmallett in_fif_p_count = dbg_data.s.data & 0xff; 683210284Sjmallett } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); 684210284Sjmallett 685210284Sjmallett /* Update in_fif_p_count for it's offset with respect to out_p_count */ 686210284Sjmallett in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; 687210284Sjmallett 688210284Sjmallett /* Read the OUT_P_COUNT from the debug select */ 689210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f); 690210284Sjmallett cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); 691210284Sjmallett dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); 692210284Sjmallett out_p_count = (dbg_data.s.data>>1) & 0xff; 693210284Sjmallett 694210284Sjmallett /* Check that the two counters are aligned */ 695210284Sjmallett if (out_p_count != in_fif_p_count) 696210284Sjmallett { 697210284Sjmallett cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); 698210284Sjmallett while (in_fif_p_count != 0) 699210284Sjmallett { 700210284Sjmallett cvmx_write64_uint32(write_address, 0); 701210284Sjmallett cvmx_wait(10000); 702210284Sjmallett in_fif_p_count = (in_fif_p_count + 1) & 0xff; 703210284Sjmallett } 704210284Sjmallett /* The EBH5200 board swapped the PCIe reset lines on the board. This 705210284Sjmallett means we must bring both links down and up, which will cause the 706210284Sjmallett PCIe0 to need alignment again. Lots of messages will be displayed, 707210284Sjmallett but everything should work */ 708210284Sjmallett if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) && 709210284Sjmallett (pcie_port == 1)) 710210284Sjmallett cvmx_pcie_rc_initialize(0); 711210284Sjmallett /* Rety bringing this port up */ 712210284Sjmallett goto retry; 713210284Sjmallett } 714210284Sjmallett } 715210284Sjmallett 716210284Sjmallett /* Display the link status */ 717210284Sjmallett pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); 718210284Sjmallett cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); 719210284Sjmallett 720210284Sjmallett return 0; 721210284Sjmallett} 722210284Sjmallett 723210284Sjmallett 724210284Sjmallett/** 725210284Sjmallett * Shutdown a PCIe port and put it in reset 726210284Sjmallett * 727210284Sjmallett * @param pcie_port PCIe port to shutdown 728210284Sjmallett * 729210284Sjmallett * @return Zero on success 730210284Sjmallett */ 731210284Sjmallettint cvmx_pcie_rc_shutdown(int pcie_port) 732210284Sjmallett{ 733210284Sjmallett /* Wait for all pending operations to complete */ 734210284Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CPL_LUT_VALID(pcie_port), cvmx_pescx_cpl_lut_valid_t, tag, ==, 0, 2000)) 735210284Sjmallett cvmx_dprintf("PCIe: Port %d shutdown timeout\n", pcie_port); 736210284Sjmallett 737210284Sjmallett /* Force reset */ 738210284Sjmallett if (pcie_port) 739210284Sjmallett { 740210284Sjmallett cvmx_ciu_soft_prst_t ciu_soft_prst; 741210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); 742210284Sjmallett ciu_soft_prst.s.soft_prst = 1; 743210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); 744210284Sjmallett } 745210284Sjmallett else 746210284Sjmallett { 747210284Sjmallett cvmx_ciu_soft_prst_t ciu_soft_prst; 748210284Sjmallett ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); 749210284Sjmallett ciu_soft_prst.s.soft_prst = 1; 750210284Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); 751210284Sjmallett } 752210284Sjmallett return 0; 753210284Sjmallett} 754210284Sjmallett 755210284Sjmallett 756210284Sjmallett/** 757210284Sjmallett * @INTERNAL 758210284Sjmallett * Build a PCIe config space request address for a device 759210284Sjmallett * 760210284Sjmallett * @param pcie_port PCIe port to access 761210284Sjmallett * @param bus Sub bus 762210284Sjmallett * @param dev Device ID 763210284Sjmallett * @param fn Device sub function 764210284Sjmallett * @param reg Register to access 765210284Sjmallett * 766210284Sjmallett * @return 64bit Octeon IO address 767210284Sjmallett */ 768210284Sjmallettstatic inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, int dev, int fn, int reg) 769210284Sjmallett{ 770210284Sjmallett cvmx_pcie_address_t pcie_addr; 771210284Sjmallett cvmx_pciercx_cfg006_t pciercx_cfg006; 772210284Sjmallett 773210284Sjmallett pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port)); 774210284Sjmallett if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0)) 775210284Sjmallett return 0; 776210284Sjmallett 777210284Sjmallett pcie_addr.u64 = 0; 778210284Sjmallett pcie_addr.config.upper = 2; 779210284Sjmallett pcie_addr.config.io = 1; 780210284Sjmallett pcie_addr.config.did = 3; 781210284Sjmallett pcie_addr.config.subdid = 1; 782210284Sjmallett pcie_addr.config.es = 1; 783210284Sjmallett pcie_addr.config.port = pcie_port; 784210284Sjmallett pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum); 785210284Sjmallett pcie_addr.config.bus = bus; 786210284Sjmallett pcie_addr.config.dev = dev; 787210284Sjmallett pcie_addr.config.func = fn; 788210284Sjmallett pcie_addr.config.reg = reg; 789210284Sjmallett return pcie_addr.u64; 790210284Sjmallett} 791210284Sjmallett 792210284Sjmallett 793210284Sjmallett/** 794210284Sjmallett * Read 8bits from a Device's config space 795210284Sjmallett * 796210284Sjmallett * @param pcie_port PCIe port the device is on 797210284Sjmallett * @param bus Sub bus 798210284Sjmallett * @param dev Device ID 799210284Sjmallett * @param fn Device sub function 800210284Sjmallett * @param reg Register to access 801210284Sjmallett * 802210284Sjmallett * @return Result of the read 803210284Sjmallett */ 804210284Sjmallettuint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg) 805210284Sjmallett{ 806210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 807210284Sjmallett if (address) 808210284Sjmallett return cvmx_read64_uint8(address); 809210284Sjmallett else 810210284Sjmallett return 0xff; 811210284Sjmallett} 812210284Sjmallett 813210284Sjmallett 814210284Sjmallett/** 815210284Sjmallett * Read 16bits from a Device's config space 816210284Sjmallett * 817210284Sjmallett * @param pcie_port PCIe port the device is on 818210284Sjmallett * @param bus Sub bus 819210284Sjmallett * @param dev Device ID 820210284Sjmallett * @param fn Device sub function 821210284Sjmallett * @param reg Register to access 822210284Sjmallett * 823210284Sjmallett * @return Result of the read 824210284Sjmallett */ 825210284Sjmallettuint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg) 826210284Sjmallett{ 827210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 828210284Sjmallett if (address) 829210284Sjmallett return cvmx_le16_to_cpu(cvmx_read64_uint16(address)); 830210284Sjmallett else 831210284Sjmallett return 0xffff; 832210284Sjmallett} 833210284Sjmallett 834210284Sjmallett 835210284Sjmallett/** 836210284Sjmallett * Read 32bits from a Device's config space 837210284Sjmallett * 838210284Sjmallett * @param pcie_port PCIe port the device is on 839210284Sjmallett * @param bus Sub bus 840210284Sjmallett * @param dev Device ID 841210284Sjmallett * @param fn Device sub function 842210284Sjmallett * @param reg Register to access 843210284Sjmallett * 844210284Sjmallett * @return Result of the read 845210284Sjmallett */ 846210284Sjmallettuint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg) 847210284Sjmallett{ 848210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 849210284Sjmallett if (address) 850210284Sjmallett return cvmx_le32_to_cpu(cvmx_read64_uint32(address)); 851210284Sjmallett else 852210284Sjmallett return 0xffffffff; 853210284Sjmallett} 854210284Sjmallett 855210284Sjmallett 856210284Sjmallett/** 857210284Sjmallett * Write 8bits to a Device's config space 858210284Sjmallett * 859210284Sjmallett * @param pcie_port PCIe port the device is on 860210284Sjmallett * @param bus Sub bus 861210284Sjmallett * @param dev Device ID 862210284Sjmallett * @param fn Device sub function 863210284Sjmallett * @param reg Register to access 864210284Sjmallett * @param val Value to write 865210284Sjmallett */ 866210284Sjmallettvoid cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, uint8_t val) 867210284Sjmallett{ 868210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 869210284Sjmallett if (address) 870210284Sjmallett cvmx_write64_uint8(address, val); 871210284Sjmallett} 872210284Sjmallett 873210284Sjmallett 874210284Sjmallett/** 875210284Sjmallett * Write 16bits to a Device's config space 876210284Sjmallett * 877210284Sjmallett * @param pcie_port PCIe port the device is on 878210284Sjmallett * @param bus Sub bus 879210284Sjmallett * @param dev Device ID 880210284Sjmallett * @param fn Device sub function 881210284Sjmallett * @param reg Register to access 882210284Sjmallett * @param val Value to write 883210284Sjmallett */ 884210284Sjmallettvoid cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, uint16_t val) 885210284Sjmallett{ 886210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 887210284Sjmallett if (address) 888210284Sjmallett cvmx_write64_uint16(address, cvmx_cpu_to_le16(val)); 889210284Sjmallett} 890210284Sjmallett 891210284Sjmallett 892210284Sjmallett/** 893210284Sjmallett * Write 32bits to a Device's config space 894210284Sjmallett * 895210284Sjmallett * @param pcie_port PCIe port the device is on 896210284Sjmallett * @param bus Sub bus 897210284Sjmallett * @param dev Device ID 898210284Sjmallett * @param fn Device sub function 899210284Sjmallett * @param reg Register to access 900210284Sjmallett * @param val Value to write 901210284Sjmallett */ 902210284Sjmallettvoid cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, uint32_t val) 903210284Sjmallett{ 904210284Sjmallett uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg); 905210284Sjmallett if (address) 906210284Sjmallett cvmx_write64_uint32(address, cvmx_cpu_to_le32(val)); 907210284Sjmallett} 908210284Sjmallett 909210284Sjmallett 910210284Sjmallett/** 911210284Sjmallett * Read a PCIe config space register indirectly. This is used for 912210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. 913210284Sjmallett * 914210284Sjmallett * @param pcie_port PCIe port to read from 915210284Sjmallett * @param cfg_offset Address to read 916210284Sjmallett * 917210284Sjmallett * @return Value read 918210284Sjmallett */ 919210284Sjmallettuint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) 920210284Sjmallett{ 921210284Sjmallett cvmx_pescx_cfg_rd_t pescx_cfg_rd; 922210284Sjmallett pescx_cfg_rd.u64 = 0; 923210284Sjmallett pescx_cfg_rd.s.addr = cfg_offset; 924210284Sjmallett cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); 925210284Sjmallett pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); 926210284Sjmallett return pescx_cfg_rd.s.data; 927210284Sjmallett} 928210284Sjmallett 929210284Sjmallett 930210284Sjmallett/** 931210284Sjmallett * Write a PCIe config space register indirectly. This is used for 932210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. 933210284Sjmallett * 934210284Sjmallett * @param pcie_port PCIe port to write to 935210284Sjmallett * @param cfg_offset Address to write 936210284Sjmallett * @param val Value to write 937210284Sjmallett */ 938210284Sjmallettvoid cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val) 939210284Sjmallett{ 940210284Sjmallett cvmx_pescx_cfg_wr_t pescx_cfg_wr; 941210284Sjmallett pescx_cfg_wr.u64 = 0; 942210284Sjmallett pescx_cfg_wr.s.addr = cfg_offset; 943210284Sjmallett pescx_cfg_wr.s.data = val; 944210284Sjmallett cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); 945210284Sjmallett} 946210284Sjmallett 947210284Sjmallett 948210284Sjmallett/** 949210284Sjmallett * Initialize a PCIe port for use in target(EP) mode. 950210284Sjmallett * 951210284Sjmallett * @return Zero on success 952210284Sjmallett */ 953210284Sjmallettint cvmx_pcie_ep_initialize(void) 954210284Sjmallett{ 955210284Sjmallett int pcie_port = 0; 956210284Sjmallett cvmx_npei_ctl_status_t npei_ctl_status; 957210284Sjmallett 958210284Sjmallett npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); 959210284Sjmallett if (npei_ctl_status.s.host_mode) 960210284Sjmallett return -1; 961210284Sjmallett 962210284Sjmallett /* Enable bus master and memory */ 963210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIEEP_CFG001, 0x6); 964210284Sjmallett 965210284Sjmallett /* Max Payload Size (PCIE*_CFG030[MPS]) */ 966210284Sjmallett /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ 967210284Sjmallett /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ 968210284Sjmallett /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ 969210284Sjmallett { 970210284Sjmallett cvmx_pciercx_cfg030_t pciercx_cfg030; 971210284Sjmallett pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); 972210284Sjmallett pciercx_cfg030.s.mps = 0; /* Max payload size = 128 bytes (Limit of most PCs) */ 973210284Sjmallett pciercx_cfg030.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ 974210284Sjmallett pciercx_cfg030.s.ro_en = 1; /* Enable relaxed ordering. */ 975210284Sjmallett pciercx_cfg030.s.ns_en = 1; /* Enable no snoop. */ 976210284Sjmallett pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */ 977210284Sjmallett pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */ 978210284Sjmallett pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */ 979210284Sjmallett pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */ 980210284Sjmallett cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); 981210284Sjmallett } 982210284Sjmallett 983210284Sjmallett /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */ 984210284Sjmallett /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */ 985210284Sjmallett { 986210284Sjmallett cvmx_npei_ctl_status2_t npei_ctl_status2; 987210284Sjmallett npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); 988210284Sjmallett npei_ctl_status2.s.mps = 0; /* Max payload size = 128 bytes (Limit of most PCs) */ 989210284Sjmallett npei_ctl_status2.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ 990210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); 991210284Sjmallett } 992210284Sjmallett 993210284Sjmallett /* Setup Mem access SubDID 12 to access Host memory */ 994210284Sjmallett { 995210284Sjmallett cvmx_npei_mem_access_subidx_t mem_access_subid; 996210284Sjmallett mem_access_subid.u64 = 0; 997210284Sjmallett mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ 998210284Sjmallett mem_access_subid.s.nmerge = 1; /* Merging is allowed in this window. */ 999210284Sjmallett mem_access_subid.s.esr = 0; /* Endian-swap for Reads. */ 1000210284Sjmallett mem_access_subid.s.esw = 0; /* Endian-swap for Writes. */ 1001210284Sjmallett mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ 1002210284Sjmallett mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */ 1003210284Sjmallett mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */ 1004210284Sjmallett mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */ 1005210284Sjmallett mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ 1006210284Sjmallett cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(12), mem_access_subid.u64); 1007210284Sjmallett } 1008210284Sjmallett return 0; 1009210284Sjmallett} 1010210284Sjmallett 1011210284Sjmallett 1012210284Sjmallett/** 1013210284Sjmallett * Wait for posted PCIe read/writes to reach the other side of 1014210284Sjmallett * the internal PCIe switch. This will insure that core 1015210284Sjmallett * read/writes are posted before anything after this function 1016210284Sjmallett * is called. This may be necessary when writing to memory that 1017210284Sjmallett * will later be read using the DMA/PKT engines. 1018210284Sjmallett * 1019210284Sjmallett * @param pcie_port PCIe port to wait for 1020210284Sjmallett */ 1021210284Sjmallettvoid cvmx_pcie_wait_for_pending(int pcie_port) 1022210284Sjmallett{ 1023210284Sjmallett cvmx_npei_data_out_cnt_t npei_data_out_cnt; 1024210284Sjmallett int a; 1025210284Sjmallett int b; 1026210284Sjmallett int c; 1027210284Sjmallett 1028210284Sjmallett /* See section 9.8, PCIe Core-initiated Requests, in the manual for a 1029210284Sjmallett description of how this code works */ 1030210284Sjmallett npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT); 1031210284Sjmallett if (pcie_port) 1032210284Sjmallett { 1033210284Sjmallett if (!npei_data_out_cnt.s.p1_fcnt) 1034210284Sjmallett return; 1035210284Sjmallett a = npei_data_out_cnt.s.p1_ucnt; 1036210284Sjmallett b = (a + npei_data_out_cnt.s.p1_fcnt-1) & 0xffff; 1037210284Sjmallett } 1038210284Sjmallett else 1039210284Sjmallett { 1040210284Sjmallett if (!npei_data_out_cnt.s.p0_fcnt) 1041210284Sjmallett return; 1042210284Sjmallett a = npei_data_out_cnt.s.p0_ucnt; 1043210284Sjmallett b = (a + npei_data_out_cnt.s.p0_fcnt-1) & 0xffff; 1044210284Sjmallett } 1045210284Sjmallett 1046210284Sjmallett while (1) 1047210284Sjmallett { 1048210284Sjmallett npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT); 1049210284Sjmallett c = (pcie_port) ? npei_data_out_cnt.s.p1_ucnt : npei_data_out_cnt.s.p0_ucnt; 1050210284Sjmallett if (a<=b) 1051210284Sjmallett { 1052210284Sjmallett if ((c<a) || (c>b)) 1053210284Sjmallett return; 1054210284Sjmallett } 1055210284Sjmallett else 1056210284Sjmallett { 1057210284Sjmallett if ((c>b) && (c<a)) 1058210284Sjmallett return; 1059210284Sjmallett } 1060210284Sjmallett } 1061210284Sjmallett} 1062210284Sjmallett 1063