cvmx-pcie.c revision 215990
1210284Sjmallett/***********************license start***************
2215990Sjmallett * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18215990Sjmallett *   * Neither the name of Cavium Networks nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Interface to PCIe as a host(RC) or target(EP)
50210284Sjmallett *
51215990Sjmallett * <hr>$Revision: 52004 $<hr>
52210284Sjmallett */
53215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54215990Sjmallett#include <asm/octeon/cvmx.h>
55215990Sjmallett#include <asm/octeon/cvmx-config.h>
56215990Sjmallett#include <asm/octeon/cvmx-clock.h>
57215990Sjmallett#include <asm/octeon/cvmx-ciu-defs.h>
58215990Sjmallett#include <asm/octeon/cvmx-dpi-defs.h>
59215990Sjmallett#include <asm/octeon/cvmx-npi-defs.h>
60215990Sjmallett#include <asm/octeon/cvmx-npei-defs.h>
61215990Sjmallett#include <asm/octeon/cvmx-pci-defs.h>
62215990Sjmallett#include <asm/octeon/cvmx-pcieepx-defs.h>
63215990Sjmallett#include <asm/octeon/cvmx-pciercx-defs.h>
64215990Sjmallett#include <asm/octeon/cvmx-pemx-defs.h>
65215990Sjmallett#include <asm/octeon/cvmx-pexp-defs.h>
66215990Sjmallett#include <asm/octeon/cvmx-pescx-defs.h>
67215990Sjmallett#include <asm/octeon/cvmx-sli-defs.h>
68215990Sjmallett#include <asm/octeon/cvmx-sriox-defs.h>
69215990Sjmallett
70215990Sjmallett#ifdef CONFIG_CAVIUM_DECODE_RSL
71215990Sjmallett#include <asm/octeon/cvmx-error.h>
72215990Sjmallett#endif
73215990Sjmallett#include <asm/octeon/cvmx-helper.h>
74215990Sjmallett#include <asm/octeon/cvmx-helper-board.h>
75215990Sjmallett#include <asm/octeon/cvmx-helper-errata.h>
76215990Sjmallett#include <asm/octeon/cvmx-pcie.h>
77215990Sjmallett#include <asm/octeon/cvmx-sysinfo.h>
78215990Sjmallett#include <asm/octeon/cvmx-swap.h>
79215990Sjmallett#include <asm/octeon/cvmx-wqe.h>
80215990Sjmallett#else
81210284Sjmallett#include "cvmx.h"
82210284Sjmallett#include "cvmx-csr-db.h"
83210284Sjmallett#include "cvmx-pcie.h"
84210284Sjmallett#include "cvmx-sysinfo.h"
85210284Sjmallett#include "cvmx-swap.h"
86210284Sjmallett#include "cvmx-wqe.h"
87215990Sjmallett#include "cvmx-error.h"
88210284Sjmallett#include "cvmx-helper-errata.h"
89215990Sjmallett#endif
90210284Sjmallett
91215990Sjmallett#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */
92215990Sjmallett#define MPS_CN5XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
93215990Sjmallett#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */
94215990Sjmallett#define MPS_CN6XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
95210284Sjmallett
96210284Sjmallett/**
97210284Sjmallett * Return the Core virtual base address for PCIe IO access. IOs are
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_io_base_address(int pcie_port)
105210284Sjmallett{
106210284Sjmallett    cvmx_pcie_address_t pcie_addr;
107210284Sjmallett    pcie_addr.u64 = 0;
108210284Sjmallett    pcie_addr.io.upper = 0;
109210284Sjmallett    pcie_addr.io.io = 1;
110210284Sjmallett    pcie_addr.io.did = 3;
111210284Sjmallett    pcie_addr.io.subdid = 2;
112210284Sjmallett    pcie_addr.io.es = 1;
113210284Sjmallett    pcie_addr.io.port = pcie_port;
114210284Sjmallett    return pcie_addr.u64;
115210284Sjmallett}
116210284Sjmallett
117210284Sjmallett
118210284Sjmallett/**
119210284Sjmallett * Size of the IO address region returned at address
120210284Sjmallett * cvmx_pcie_get_io_base_address()
121210284Sjmallett *
122210284Sjmallett * @param pcie_port PCIe port the IO is for
123210284Sjmallett *
124210284Sjmallett * @return Size of the IO window
125210284Sjmallett */
126210284Sjmallettuint64_t cvmx_pcie_get_io_size(int pcie_port)
127210284Sjmallett{
128210284Sjmallett    return 1ull<<32;
129210284Sjmallett}
130210284Sjmallett
131210284Sjmallett
132210284Sjmallett/**
133210284Sjmallett * Return the Core virtual base address for PCIe MEM access. Memory is
134210284Sjmallett * read/written as an offset from this address.
135210284Sjmallett *
136210284Sjmallett * @param pcie_port PCIe port the IO is for
137210284Sjmallett *
138210284Sjmallett * @return 64bit Octeon IO base address for read/write
139210284Sjmallett */
140210284Sjmallettuint64_t cvmx_pcie_get_mem_base_address(int pcie_port)
141210284Sjmallett{
142210284Sjmallett    cvmx_pcie_address_t pcie_addr;
143210284Sjmallett    pcie_addr.u64 = 0;
144210284Sjmallett    pcie_addr.mem.upper = 0;
145210284Sjmallett    pcie_addr.mem.io = 1;
146210284Sjmallett    pcie_addr.mem.did = 3;
147210284Sjmallett    pcie_addr.mem.subdid = 3 + pcie_port;
148210284Sjmallett    return pcie_addr.u64;
149210284Sjmallett}
150210284Sjmallett
151210284Sjmallett
152210284Sjmallett/**
153210284Sjmallett * Size of the Mem address region returned at address
154210284Sjmallett * cvmx_pcie_get_mem_base_address()
155210284Sjmallett *
156210284Sjmallett * @param pcie_port PCIe port the IO is for
157210284Sjmallett *
158210284Sjmallett * @return Size of the Mem window
159210284Sjmallett */
160210284Sjmallettuint64_t cvmx_pcie_get_mem_size(int pcie_port)
161210284Sjmallett{
162210284Sjmallett    return 1ull<<36;
163210284Sjmallett}
164210284Sjmallett
165210284Sjmallett
166210284Sjmallett/**
167210284Sjmallett * @INTERNAL
168210284Sjmallett * Initialize the RC config space CSRs
169210284Sjmallett *
170210284Sjmallett * @param pcie_port PCIe port to initialize
171210284Sjmallett */
172210284Sjmallettstatic void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
173210284Sjmallett{
174210284Sjmallett    /* Max Payload Size (PCIE*_CFG030[MPS]) */
175210284Sjmallett    /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
176210284Sjmallett    /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
177210284Sjmallett    /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
178210284Sjmallett    {
179210284Sjmallett        cvmx_pciercx_cfg030_t pciercx_cfg030;
180210284Sjmallett        pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port));
181215990Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
182215990Sjmallett        {
183215990Sjmallett            pciercx_cfg030.s.mps = MPS_CN5XXX;
184215990Sjmallett            pciercx_cfg030.s.mrrs = MRRS_CN5XXX;
185215990Sjmallett        }
186215990Sjmallett        else
187215990Sjmallett        {
188215990Sjmallett            pciercx_cfg030.s.mps = MPS_CN6XXX;
189215990Sjmallett            pciercx_cfg030.s.mrrs = MRRS_CN6XXX;
190215990Sjmallett        }
191210284Sjmallett        pciercx_cfg030.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */
192210284Sjmallett        pciercx_cfg030.s.ns_en = 1; /* Enable no snoop processing. Not used by Octeon */
193210284Sjmallett        pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */
194210284Sjmallett        pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */
195210284Sjmallett        pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */
196210284Sjmallett        pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */
197210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32);
198210284Sjmallett    }
199210284Sjmallett
200215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
201210284Sjmallett    {
202215990Sjmallett        /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */
203215990Sjmallett        /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
204210284Sjmallett        cvmx_npei_ctl_status2_t npei_ctl_status2;
205210284Sjmallett        npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
206215990Sjmallett        npei_ctl_status2.s.mps = MPS_CN5XXX; /* Max payload size = 128 bytes for best Octeon DMA performance */
207215990Sjmallett        npei_ctl_status2.s.mrrs = MRRS_CN5XXX; /* Max read request size = 128 bytes for best Octeon DMA performance */
208215990Sjmallett        if (pcie_port)
209215990Sjmallett            npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
210215990Sjmallett        else
211215990Sjmallett            npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
212215990Sjmallett
213210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
214210284Sjmallett    }
215215990Sjmallett    else
216215990Sjmallett    {
217215990Sjmallett        /* Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match PCIE*_CFG030[MPS] */
218215990Sjmallett        /* Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
219215990Sjmallett        cvmx_dpi_sli_prtx_cfg_t prt_cfg;
220215990Sjmallett        cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
221215990Sjmallett        prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port));
222215990Sjmallett        prt_cfg.s.mps = MPS_CN6XXX;
223215990Sjmallett        prt_cfg.s.mrrs = MRRS_CN6XXX;
224215990Sjmallett        cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);
225210284Sjmallett
226215990Sjmallett        sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));
227215990Sjmallett        sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX;
228215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);
229215990Sjmallett    }
230215990Sjmallett
231210284Sjmallett    /* ECRC Generation (PCIE*_CFG070[GE,CE]) */
232210284Sjmallett    {
233210284Sjmallett        cvmx_pciercx_cfg070_t pciercx_cfg070;
234210284Sjmallett        pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));
235210284Sjmallett        pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */
236210284Sjmallett        pciercx_cfg070.s.ce = 1; /* ECRC check enable. */
237210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32);
238210284Sjmallett    }
239210284Sjmallett
240210284Sjmallett    /* Access Enables (PCIE*_CFG001[MSAE,ME]) */
241210284Sjmallett        /* ME and MSAE should always be set. */
242210284Sjmallett    /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */
243210284Sjmallett    /* System Error Message Enable (PCIE*_CFG001[SEE]) */
244210284Sjmallett    {
245210284Sjmallett        cvmx_pciercx_cfg001_t pciercx_cfg001;
246210284Sjmallett        pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));
247210284Sjmallett        pciercx_cfg001.s.msae = 1; /* Memory space enable. */
248210284Sjmallett        pciercx_cfg001.s.me = 1; /* Bus master enable. */
249210284Sjmallett        pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */
250210284Sjmallett        pciercx_cfg001.s.see = 1; /* SERR# enable */
251210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32);
252210284Sjmallett    }
253210284Sjmallett
254210284Sjmallett
255210284Sjmallett    /* Advanced Error Recovery Message Enables */
256210284Sjmallett    /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */
257210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0);
258210284Sjmallett    /* Use CVMX_PCIERCX_CFG067 hardware default */
259210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0);
260210284Sjmallett
261210284Sjmallett
262210284Sjmallett    /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
263210284Sjmallett    {
264210284Sjmallett        cvmx_pciercx_cfg032_t pciercx_cfg032;
265210284Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
266210284Sjmallett        pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */
267210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32);
268210284Sjmallett    }
269210284Sjmallett
270210284Sjmallett    /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during cvmx_pcie_rc_initialize_link() */
271210284Sjmallett    /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */
272210284Sjmallett    {
273210284Sjmallett        /* We set the primary bus number to 1 so IDT bridges are happy. They don't like zero */
274210284Sjmallett        cvmx_pciercx_cfg006_t pciercx_cfg006;
275210284Sjmallett        pciercx_cfg006.u32 = 0;
276210284Sjmallett        pciercx_cfg006.s.pbnum = 1;
277210284Sjmallett        pciercx_cfg006.s.sbnum = 1;
278210284Sjmallett        pciercx_cfg006.s.subbnum = 1;
279210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32);
280210284Sjmallett    }
281210284Sjmallett
282210284Sjmallett    /* Memory-mapped I/O BAR (PCIERCn_CFG008) */
283210284Sjmallett    /* Most applications should disable the memory-mapped I/O BAR by */
284210284Sjmallett    /* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */
285210284Sjmallett    {
286210284Sjmallett        cvmx_pciercx_cfg008_t pciercx_cfg008;
287210284Sjmallett        pciercx_cfg008.u32 = 0;
288210284Sjmallett        pciercx_cfg008.s.mb_addr = 0x100;
289210284Sjmallett        pciercx_cfg008.s.ml_addr = 0;
290210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32);
291210284Sjmallett    }
292210284Sjmallett
293210284Sjmallett    /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */
294210284Sjmallett    /* Most applications should disable the prefetchable BAR by setting */
295210284Sjmallett    /* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */
296210284Sjmallett    /* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */
297210284Sjmallett    {
298210284Sjmallett        cvmx_pciercx_cfg009_t pciercx_cfg009;
299210284Sjmallett        cvmx_pciercx_cfg010_t pciercx_cfg010;
300210284Sjmallett        cvmx_pciercx_cfg011_t pciercx_cfg011;
301210284Sjmallett        pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));
302210284Sjmallett        pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));
303210284Sjmallett        pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));
304210284Sjmallett        pciercx_cfg009.s.lmem_base = 0x100;
305210284Sjmallett        pciercx_cfg009.s.lmem_limit = 0;
306210284Sjmallett        pciercx_cfg010.s.umem_base = 0x100;
307210284Sjmallett        pciercx_cfg011.s.umem_limit = 0;
308210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32);
309210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32);
310210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32);
311210284Sjmallett    }
312210284Sjmallett
313210284Sjmallett    /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */
314210284Sjmallett    /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */
315210284Sjmallett    {
316210284Sjmallett        cvmx_pciercx_cfg035_t pciercx_cfg035;
317210284Sjmallett        pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));
318210284Sjmallett        pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */
319210284Sjmallett        pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */
320210284Sjmallett        pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */
321210284Sjmallett        pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */
322210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32);
323210284Sjmallett    }
324210284Sjmallett
325210284Sjmallett    /* Advanced Error Recovery Interrupt Enables */
326210284Sjmallett    /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */
327210284Sjmallett    {
328210284Sjmallett        cvmx_pciercx_cfg075_t pciercx_cfg075;
329210284Sjmallett        pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));
330210284Sjmallett        pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */
331210284Sjmallett        pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */
332210284Sjmallett        pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */
333210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32);
334210284Sjmallett    }
335210284Sjmallett
336210284Sjmallett    /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */
337210284Sjmallett    /* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */
338210284Sjmallett    {
339210284Sjmallett        cvmx_pciercx_cfg034_t pciercx_cfg034;
340210284Sjmallett        pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));
341210284Sjmallett        pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */
342210284Sjmallett        pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */
343210284Sjmallett        pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */
344210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32);
345210284Sjmallett    }
346210284Sjmallett}
347210284Sjmallett
348210284Sjmallett/**
349210284Sjmallett * @INTERNAL
350215990Sjmallett * Initialize a host mode PCIe gen 1 link. This function takes a PCIe
351210284Sjmallett * port from reset to a link up state. Software can then begin
352210284Sjmallett * configuring the rest of the link.
353210284Sjmallett *
354210284Sjmallett * @param pcie_port PCIe port to initialize
355210284Sjmallett *
356210284Sjmallett * @return Zero on success
357210284Sjmallett */
358215990Sjmallettstatic int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port)
359210284Sjmallett{
360210284Sjmallett    uint64_t start_cycle;
361210284Sjmallett    cvmx_pescx_ctl_status_t pescx_ctl_status;
362210284Sjmallett    cvmx_pciercx_cfg452_t pciercx_cfg452;
363210284Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
364210284Sjmallett    cvmx_pciercx_cfg448_t pciercx_cfg448;
365210284Sjmallett
366210284Sjmallett    /* Set the lane width */
367210284Sjmallett    pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));
368210284Sjmallett    pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
369210284Sjmallett    if (pescx_ctl_status.s.qlm_cfg == 0)
370210284Sjmallett    {
371210284Sjmallett        /* We're in 8 lane (56XX) or 4 lane (54XX) mode */
372210284Sjmallett        pciercx_cfg452.s.lme = 0xf;
373210284Sjmallett    }
374210284Sjmallett    else
375210284Sjmallett    {
376210284Sjmallett        /* We're in 4 lane (56XX) or 2 lane (52XX) mode */
377210284Sjmallett        pciercx_cfg452.s.lme = 0x7;
378210284Sjmallett    }
379210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32);
380210284Sjmallett
381210284Sjmallett    /* CN52XX pass 1.x has an errata where length mismatches on UR responses can
382210284Sjmallett        cause bus errors on 64bit memory reads. Turning off length error
383210284Sjmallett        checking fixes this */
384210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
385210284Sjmallett    {
386210284Sjmallett        cvmx_pciercx_cfg455_t pciercx_cfg455;
387210284Sjmallett        pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port));
388210284Sjmallett        pciercx_cfg455.s.m_cpl_len_err = 1;
389210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32);
390210284Sjmallett    }
391210284Sjmallett
392210284Sjmallett    /* Lane swap needs to be manually enabled for CN52XX */
393210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1))
394210284Sjmallett    {
395210284Sjmallett      pescx_ctl_status.s.lane_swp = 1;
396210284Sjmallett      cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),pescx_ctl_status.u64);
397210284Sjmallett    }
398210284Sjmallett
399210284Sjmallett    /* Bring up the link */
400210284Sjmallett    pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
401210284Sjmallett    pescx_ctl_status.s.lnk_enb = 1;
402210284Sjmallett    cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64);
403210284Sjmallett
404210284Sjmallett    /* CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to be disabled */
405210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
406210284Sjmallett        __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0);
407210284Sjmallett
408210284Sjmallett    /* Wait for the link to come up */
409210284Sjmallett    start_cycle = cvmx_get_cycle();
410210284Sjmallett    do
411210284Sjmallett    {
412215990Sjmallett        if (cvmx_get_cycle() - start_cycle > 2*cvmx_clock_get_rate(CVMX_CLOCK_CORE))
413210284Sjmallett        {
414210284Sjmallett            cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port);
415210284Sjmallett            return -1;
416210284Sjmallett        }
417210284Sjmallett        cvmx_wait(10000);
418210284Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
419210284Sjmallett    } while (pciercx_cfg032.s.dlla == 0);
420210284Sjmallett
421215990Sjmallett    /* Clear all pending errors */
422215990Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM));
423215990Sjmallett
424210284Sjmallett    /* Update the Replay Time Limit. Empirically, some PCIe devices take a
425210284Sjmallett        little longer to respond than expected under load. As a workaround for
426210284Sjmallett        this we configure the Replay Time Limit to the value expected for a 512
427210284Sjmallett        byte MPS instead of our actual 256 byte MPS. The numbers below are
428210284Sjmallett        directly from the PCIe spec table 3-4 */
429210284Sjmallett    pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
430210284Sjmallett    switch (pciercx_cfg032.s.nlw)
431210284Sjmallett    {
432210284Sjmallett        case 1: /* 1 lane */
433210284Sjmallett            pciercx_cfg448.s.rtl = 1677;
434210284Sjmallett            break;
435210284Sjmallett        case 2: /* 2 lanes */
436210284Sjmallett            pciercx_cfg448.s.rtl = 867;
437210284Sjmallett            break;
438210284Sjmallett        case 4: /* 4 lanes */
439210284Sjmallett            pciercx_cfg448.s.rtl = 462;
440210284Sjmallett            break;
441210284Sjmallett        case 8: /* 8 lanes */
442210284Sjmallett            pciercx_cfg448.s.rtl = 258;
443210284Sjmallett            break;
444210284Sjmallett    }
445210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
446210284Sjmallett
447210284Sjmallett    return 0;
448210284Sjmallett}
449210284Sjmallett
450210284Sjmallett
451210284Sjmallett/**
452215990Sjmallett * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't enumerate
453215990Sjmallett * the bus.
454210284Sjmallett *
455210284Sjmallett * @param pcie_port PCIe port to initialize
456210284Sjmallett *
457210284Sjmallett * @return Zero on success
458210284Sjmallett */
459215990Sjmallettstatic int __cvmx_pcie_rc_initialize_gen1(int pcie_port)
460210284Sjmallett{
461210284Sjmallett    int i;
462215990Sjmallett    int base;
463215990Sjmallett    uint64_t addr_swizzle;
464210284Sjmallett    cvmx_ciu_soft_prst_t ciu_soft_prst;
465210284Sjmallett    cvmx_pescx_bist_status_t pescx_bist_status;
466210284Sjmallett    cvmx_pescx_bist_status2_t pescx_bist_status2;
467210284Sjmallett    cvmx_npei_ctl_status_t npei_ctl_status;
468210284Sjmallett    cvmx_npei_mem_access_ctl_t npei_mem_access_ctl;
469210284Sjmallett    cvmx_npei_mem_access_subidx_t mem_access_subid;
470210284Sjmallett    cvmx_npei_dbg_data_t npei_dbg_data;
471210284Sjmallett    cvmx_pescx_ctl_status2_t pescx_ctl_status2;
472210284Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
473215990Sjmallett    cvmx_npei_bar1_indexx_t bar1_index;
474210284Sjmallett
475210284Sjmallettretry:
476210284Sjmallett    /* Make sure we aren't trying to setup a target mode interface in host mode */
477210284Sjmallett    npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
478210284Sjmallett    if ((pcie_port==0) && !npei_ctl_status.s.host_mode)
479210284Sjmallett    {
480215990Sjmallett        cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port);
481210284Sjmallett        return -1;
482210284Sjmallett    }
483210284Sjmallett
484210284Sjmallett    /* Make sure a CN52XX isn't trying to bring up port 1 when it is disabled */
485210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX))
486210284Sjmallett    {
487210284Sjmallett        npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
488210284Sjmallett        if ((pcie_port==1) && npei_dbg_data.cn52xx.qlm0_link_width)
489210284Sjmallett        {
490210284Sjmallett            cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n");
491210284Sjmallett            return -1;
492210284Sjmallett        }
493210284Sjmallett    }
494210284Sjmallett
495210284Sjmallett    /* PCIe switch arbitration mode. '0' == fixed priority NPEI, PCIe0, then PCIe1. '1' == round robin. */
496210284Sjmallett    npei_ctl_status.s.arb = 1;
497210284Sjmallett    /* Allow up to 0x20 config retries */
498210284Sjmallett    npei_ctl_status.s.cfg_rtry = 0x20;
499210284Sjmallett    /* CN52XX pass1.x has an errata where P0_NTAGS and P1_NTAGS don't reset */
500210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
501210284Sjmallett    {
502210284Sjmallett        npei_ctl_status.s.p0_ntags = 0x20;
503210284Sjmallett        npei_ctl_status.s.p1_ntags = 0x20;
504210284Sjmallett    }
505210284Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS, npei_ctl_status.u64);
506210284Sjmallett
507210284Sjmallett    /* Bring the PCIe out of reset */
508210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200)
509210284Sjmallett    {
510210284Sjmallett        /* The EBH5200 board swapped the PCIe reset lines on the board. As a
511210284Sjmallett            workaround for this bug, we bring both PCIe ports out of reset at
512210284Sjmallett            the same time instead of on separate calls. So for port 0, we bring
513210284Sjmallett            both out of reset and do nothing on port 1 */
514210284Sjmallett        if (pcie_port == 0)
515210284Sjmallett        {
516210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
517210284Sjmallett            /* After a chip reset the PCIe will also be in reset. If it isn't,
518210284Sjmallett                most likely someone is trying to init it again without a proper
519210284Sjmallett                PCIe reset */
520210284Sjmallett            if (ciu_soft_prst.s.soft_prst == 0)
521210284Sjmallett            {
522210284Sjmallett		/* Reset the ports */
523210284Sjmallett		ciu_soft_prst.s.soft_prst = 1;
524210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
525210284Sjmallett		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
526210284Sjmallett		ciu_soft_prst.s.soft_prst = 1;
527210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
528210284Sjmallett		/* Wait until pcie resets the ports. */
529210284Sjmallett		cvmx_wait_usec(2000);
530210284Sjmallett            }
531210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
532210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
533210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
534210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
535210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
536210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
537210284Sjmallett        }
538210284Sjmallett    }
539210284Sjmallett    else
540210284Sjmallett    {
541210284Sjmallett        /* The normal case: The PCIe ports are completely separate and can be
542210284Sjmallett            brought out of reset independently */
543210284Sjmallett        if (pcie_port)
544210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
545210284Sjmallett        else
546210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
547210284Sjmallett        /* After a chip reset the PCIe will also be in reset. If it isn't,
548210284Sjmallett            most likely someone is trying to init it again without a proper
549210284Sjmallett            PCIe reset */
550210284Sjmallett        if (ciu_soft_prst.s.soft_prst == 0)
551210284Sjmallett        {
552210284Sjmallett	    /* Reset the port */
553210284Sjmallett	    ciu_soft_prst.s.soft_prst = 1;
554210284Sjmallett	    if (pcie_port)
555210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
556210284Sjmallett 	    else
557210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
558210284Sjmallett	    /* Wait until pcie resets the ports. */
559210284Sjmallett	    cvmx_wait_usec(2000);
560210284Sjmallett        }
561210284Sjmallett        if (pcie_port)
562210284Sjmallett        {
563210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
564210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
565210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
566210284Sjmallett        }
567210284Sjmallett        else
568210284Sjmallett        {
569210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
570210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
571210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
572210284Sjmallett        }
573210284Sjmallett    }
574210284Sjmallett
575210284Sjmallett    /* Wait for PCIe reset to complete. Due to errata PCIE-700, we don't poll
576210284Sjmallett       PESCX_CTL_STATUS2[PCIERST], but simply wait a fixed number of cycles */
577210284Sjmallett    cvmx_wait(400000);
578210284Sjmallett
579210284Sjmallett    /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and
580210284Sjmallett        CN52XX, so we only probe it on newer chips */
581210284Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
582210284Sjmallett    {
583210284Sjmallett        /* Clear PCLK_RUN so we can check if the clock is running */
584210284Sjmallett        pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
585210284Sjmallett        pescx_ctl_status2.s.pclk_run = 1;
586210284Sjmallett        cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64);
587210284Sjmallett        /* Now that we cleared PCLK_RUN, wait for it to be set again telling
588210284Sjmallett            us the clock is running */
589210284Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port),
590210284Sjmallett            cvmx_pescx_ctl_status2_t, pclk_run, ==, 1, 10000))
591210284Sjmallett        {
592210284Sjmallett            cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port);
593210284Sjmallett            return -1;
594210284Sjmallett        }
595210284Sjmallett    }
596210284Sjmallett
597210284Sjmallett    /* Check and make sure PCIe came out of reset. If it doesn't the board
598210284Sjmallett        probably hasn't wired the clocks up and the interface should be
599210284Sjmallett        skipped */
600210284Sjmallett    pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
601210284Sjmallett    if (pescx_ctl_status2.s.pcierst)
602210284Sjmallett    {
603210284Sjmallett        cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
604210284Sjmallett        return -1;
605210284Sjmallett    }
606210284Sjmallett
607210284Sjmallett    /* Check BIST2 status. If any bits are set skip this interface. This
608210284Sjmallett        is an attempt to catch PCIE-813 on pass 1 parts */
609210284Sjmallett    pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));
610210284Sjmallett    if (pescx_bist_status2.u64)
611210284Sjmallett    {
612210284Sjmallett        cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", pcie_port);
613210284Sjmallett        return -1;
614210284Sjmallett    }
615210284Sjmallett
616210284Sjmallett    /* Check BIST status */
617210284Sjmallett    pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));
618210284Sjmallett    if (pescx_bist_status.u64)
619210284Sjmallett        cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pescx_bist_status.u64));
620210284Sjmallett
621210284Sjmallett    /* Initialize the config space CSRs */
622210284Sjmallett    __cvmx_pcie_rc_initialize_config_space(pcie_port);
623210284Sjmallett
624210284Sjmallett    /* Bring the link up */
625215990Sjmallett    if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port))
626210284Sjmallett    {
627215990Sjmallett        cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", pcie_port);
628210284Sjmallett        return -1;
629210284Sjmallett    }
630210284Sjmallett
631210284Sjmallett    /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
632210284Sjmallett    npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL);
633210284Sjmallett    npei_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
634210284Sjmallett    npei_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
635210284Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);
636210284Sjmallett
637210284Sjmallett    /* Setup Mem access SubDIDs */
638210284Sjmallett    mem_access_subid.u64 = 0;
639210284Sjmallett    mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
640210284Sjmallett    mem_access_subid.s.nmerge = 1;  /* Due to an errata on pass 1 chips, no merging is allowed. */
641210284Sjmallett    mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
642210284Sjmallett    mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
643210284Sjmallett    mem_access_subid.s.nsr = 0;     /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
644210284Sjmallett    mem_access_subid.s.nsw = 0;     /* Enable Snoop for Writes. */
645210284Sjmallett    mem_access_subid.s.ror = 0;     /* Disable Relaxed Ordering for Reads. */
646210284Sjmallett    mem_access_subid.s.row = 0;     /* Disable Relaxed Ordering for Writes. */
647210284Sjmallett    mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
648210284Sjmallett
649210284Sjmallett    /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */
650210284Sjmallett    for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++)
651210284Sjmallett    {
652210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
653210284Sjmallett        mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */
654210284Sjmallett    }
655210284Sjmallett
656210284Sjmallett    /* Disable the peer to peer forwarding register. This must be setup
657210284Sjmallett        by the OS after it enumerates the bus and assigns addresses to the
658210284Sjmallett        PCIe busses */
659210284Sjmallett    for (i=0; i<4; i++)
660210284Sjmallett    {
661210284Sjmallett        cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1);
662210284Sjmallett        cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1);
663210284Sjmallett    }
664210284Sjmallett
665210284Sjmallett    /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
666210284Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
667210284Sjmallett
668215990Sjmallett    /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */
669215990Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
670210284Sjmallett
671215990Sjmallett    bar1_index.u32 = 0;
672215990Sjmallett    bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
673215990Sjmallett    bar1_index.s.ca = 1;       /* Not Cached */
674215990Sjmallett    bar1_index.s.end_swp = 1;  /* Endian Swap mode */
675215990Sjmallett    bar1_index.s.addr_v = 1;   /* Valid entry */
676215990Sjmallett
677215990Sjmallett    base = pcie_port ? 16 : 0;
678215990Sjmallett
679215990Sjmallett    /* Big endian swizzle for 32-bit PEXP_NCB register. */
680215990Sjmallett#ifdef __MIPSEB__
681215990Sjmallett    addr_swizzle = 4;
682215990Sjmallett#else
683215990Sjmallett    addr_swizzle = 0;
684215990Sjmallett#endif
685215990Sjmallett    for (i = 0; i < 16; i++) {
686215990Sjmallett        cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle), bar1_index.u32);
687215990Sjmallett        base++;
688215990Sjmallett        /* 256MB / 16 >> 22 == 4 */
689215990Sjmallett        bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
690215990Sjmallett    }
691215990Sjmallett
692210284Sjmallett    /* Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take precedence
693210284Sjmallett        where they overlap. It also overlaps with the device addresses, so
694210284Sjmallett        make sure the peer to peer forwarding is set right */
695210284Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR2_START(pcie_port), 0);
696210284Sjmallett
697210284Sjmallett    /* Setup BAR2 attributes */
698210284Sjmallett    /* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */
699210284Sjmallett    /* � PTLP_RO,CTLP_RO should normally be set (except for debug). */
700210284Sjmallett    /* � WAIT_COM=0 will likely work for all applications. */
701210284Sjmallett    /* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */
702210284Sjmallett    if (pcie_port)
703210284Sjmallett    {
704210284Sjmallett        cvmx_npei_ctl_port1_t npei_ctl_port;
705210284Sjmallett        npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT1);
706210284Sjmallett        npei_ctl_port.s.bar2_enb = 1;
707210284Sjmallett        npei_ctl_port.s.bar2_esx = 1;
708210284Sjmallett        npei_ctl_port.s.bar2_cax = 0;
709210284Sjmallett        npei_ctl_port.s.ptlp_ro = 1;
710210284Sjmallett        npei_ctl_port.s.ctlp_ro = 1;
711210284Sjmallett        npei_ctl_port.s.wait_com = 0;
712210284Sjmallett        npei_ctl_port.s.waitl_com = 0;
713210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT1, npei_ctl_port.u64);
714210284Sjmallett    }
715210284Sjmallett    else
716210284Sjmallett    {
717210284Sjmallett        cvmx_npei_ctl_port0_t npei_ctl_port;
718210284Sjmallett        npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT0);
719210284Sjmallett        npei_ctl_port.s.bar2_enb = 1;
720210284Sjmallett        npei_ctl_port.s.bar2_esx = 1;
721210284Sjmallett        npei_ctl_port.s.bar2_cax = 0;
722210284Sjmallett        npei_ctl_port.s.ptlp_ro = 1;
723210284Sjmallett        npei_ctl_port.s.ctlp_ro = 1;
724210284Sjmallett        npei_ctl_port.s.wait_com = 0;
725210284Sjmallett        npei_ctl_port.s.waitl_com = 0;
726210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64);
727210284Sjmallett    }
728210284Sjmallett
729210284Sjmallett    /* Both pass 1 and pass 2 of CN52XX and CN56XX have an errata that causes
730210284Sjmallett        TLP ordering to not be preserved after multiple PCIe port resets. This
731210284Sjmallett        code detects this fault and corrects it by aligning the TLP counters
732210284Sjmallett        properly. Another link reset is then performed. See PCIE-13340 */
733210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) ||
734210284Sjmallett        OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
735210284Sjmallett    {
736210284Sjmallett        cvmx_npei_dbg_data_t dbg_data;
737210284Sjmallett        int old_in_fif_p_count;
738210284Sjmallett        int in_fif_p_count;
739210284Sjmallett        int out_p_count;
740210284Sjmallett        int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1;
741210284Sjmallett        int i;
742210284Sjmallett
743210284Sjmallett        /* Choose a write address of 1MB. It should be harmless as all bars
744210284Sjmallett            haven't been setup */
745210284Sjmallett        uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63);
746210284Sjmallett
747210284Sjmallett        /* Make sure at least in_p_offset have been executed before we try and
748210284Sjmallett            read in_fif_p_count */
749210284Sjmallett        i = in_p_offset;
750210284Sjmallett        while (i--)
751210284Sjmallett        {
752210284Sjmallett            cvmx_write64_uint32(write_address, 0);
753210284Sjmallett            cvmx_wait(10000);
754210284Sjmallett        }
755210284Sjmallett
756210284Sjmallett        /* Read the IN_FIF_P_COUNT from the debug select. IN_FIF_P_COUNT can be
757210284Sjmallett            unstable sometimes so read it twice with a write between the reads.
758210284Sjmallett            This way we can tell the value is good as it will increment by one
759210284Sjmallett            due to the write */
760210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc);
761210284Sjmallett        cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
762210284Sjmallett        do
763210284Sjmallett        {
764210284Sjmallett            dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
765210284Sjmallett            old_in_fif_p_count = dbg_data.s.data & 0xff;
766210284Sjmallett            cvmx_write64_uint32(write_address, 0);
767210284Sjmallett            cvmx_wait(10000);
768210284Sjmallett            dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
769210284Sjmallett            in_fif_p_count = dbg_data.s.data & 0xff;
770210284Sjmallett        } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff));
771210284Sjmallett
772210284Sjmallett        /* Update in_fif_p_count for it's offset with respect to out_p_count */
773210284Sjmallett        in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff;
774210284Sjmallett
775210284Sjmallett        /* Read the OUT_P_COUNT from the debug select */
776210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f);
777210284Sjmallett        cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
778210284Sjmallett        dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
779210284Sjmallett        out_p_count = (dbg_data.s.data>>1) & 0xff;
780210284Sjmallett
781210284Sjmallett        /* Check that the two counters are aligned */
782210284Sjmallett        if (out_p_count != in_fif_p_count)
783210284Sjmallett        {
784210284Sjmallett            cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port);
785210284Sjmallett            while (in_fif_p_count != 0)
786210284Sjmallett            {
787210284Sjmallett                cvmx_write64_uint32(write_address, 0);
788210284Sjmallett                cvmx_wait(10000);
789210284Sjmallett                in_fif_p_count = (in_fif_p_count + 1) & 0xff;
790210284Sjmallett            }
791210284Sjmallett            /* The EBH5200 board swapped the PCIe reset lines on the board. This
792210284Sjmallett                means we must bring both links down and up, which will cause the
793210284Sjmallett                PCIe0 to need alignment again. Lots of messages will be displayed,
794210284Sjmallett                but everything should work */
795210284Sjmallett            if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) &&
796210284Sjmallett                (pcie_port == 1))
797210284Sjmallett                cvmx_pcie_rc_initialize(0);
798210284Sjmallett            /* Rety bringing this port up */
799210284Sjmallett            goto retry;
800210284Sjmallett        }
801210284Sjmallett    }
802210284Sjmallett
803210284Sjmallett    /* Display the link status */
804210284Sjmallett    pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
805210284Sjmallett    cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw);
806210284Sjmallett
807210284Sjmallett    return 0;
808210284Sjmallett}
809210284Sjmallett
810210284Sjmallett
811210284Sjmallett/**
812215990Sjmallett * @INTERNAL
813215990Sjmallett * Initialize a host mode PCIe gen 2 link. This function takes a PCIe
814215990Sjmallett * port from reset to a link up state. Software can then begin
815215990Sjmallett * configuring the rest of the link.
816215990Sjmallett *
817215990Sjmallett * @param pcie_port PCIe port to initialize
818215990Sjmallett *
819215990Sjmallett * @return Zero on success
820215990Sjmallett */
821215990Sjmallettstatic int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port)
822215990Sjmallett{
823215990Sjmallett    uint64_t start_cycle;
824215990Sjmallett    cvmx_pemx_ctl_status_t pem_ctl_status;
825215990Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
826215990Sjmallett    cvmx_pciercx_cfg448_t pciercx_cfg448;
827215990Sjmallett
828215990Sjmallett    /* Bring up the link */
829215990Sjmallett    pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
830215990Sjmallett    pem_ctl_status.s.lnk_enb = 1;
831215990Sjmallett    cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);
832215990Sjmallett
833215990Sjmallett    /* Wait for the link to come up */
834215990Sjmallett    start_cycle = cvmx_get_cycle();
835215990Sjmallett    do
836215990Sjmallett    {
837215990Sjmallett        if (cvmx_get_cycle() - start_cycle > cvmx_clock_get_rate(CVMX_CLOCK_CORE))
838215990Sjmallett            return -1;
839215990Sjmallett        cvmx_wait(10000);
840215990Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
841215990Sjmallett    } while (pciercx_cfg032.s.dlla == 0);
842215990Sjmallett
843215990Sjmallett    /* Update the Replay Time Limit. Empirically, some PCIe devices take a
844215990Sjmallett        little longer to respond than expected under load. As a workaround for
845215990Sjmallett        this we configure the Replay Time Limit to the value expected for a 512
846215990Sjmallett        byte MPS instead of our actual 256 byte MPS. The numbers below are
847215990Sjmallett        directly from the PCIe spec table 3-4 */
848215990Sjmallett    pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
849215990Sjmallett    switch (pciercx_cfg032.s.nlw)
850215990Sjmallett    {
851215990Sjmallett        case 1: /* 1 lane */
852215990Sjmallett            pciercx_cfg448.s.rtl = 1677;
853215990Sjmallett            break;
854215990Sjmallett        case 2: /* 2 lanes */
855215990Sjmallett            pciercx_cfg448.s.rtl = 867;
856215990Sjmallett            break;
857215990Sjmallett        case 4: /* 4 lanes */
858215990Sjmallett            pciercx_cfg448.s.rtl = 462;
859215990Sjmallett            break;
860215990Sjmallett        case 8: /* 8 lanes */
861215990Sjmallett            pciercx_cfg448.s.rtl = 258;
862215990Sjmallett            break;
863215990Sjmallett    }
864215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
865215990Sjmallett
866215990Sjmallett    return 0;
867215990Sjmallett}
868215990Sjmallett
869215990Sjmallett
870215990Sjmallett/**
871215990Sjmallett * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate
872215990Sjmallett * the bus.
873215990Sjmallett *
874215990Sjmallett * @param pcie_port PCIe port to initialize
875215990Sjmallett *
876215990Sjmallett * @return Zero on success
877215990Sjmallett */
878215990Sjmallettstatic int __cvmx_pcie_rc_initialize_gen2(int pcie_port)
879215990Sjmallett{
880215990Sjmallett    int i;
881215990Sjmallett    cvmx_ciu_soft_prst_t ciu_soft_prst;
882215990Sjmallett    cvmx_mio_rst_ctlx_t mio_rst_ctl;
883215990Sjmallett    cvmx_pemx_bar_ctl_t pemx_bar_ctl;
884215990Sjmallett    cvmx_pemx_ctl_status_t pemx_ctl_status;
885215990Sjmallett    cvmx_pemx_bist_status_t pemx_bist_status;
886215990Sjmallett    cvmx_pemx_bist_status2_t pemx_bist_status2;
887215990Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
888215990Sjmallett    cvmx_pciercx_cfg515_t pciercx_cfg515;
889215990Sjmallett    cvmx_sli_ctl_portx_t sli_ctl_portx;
890215990Sjmallett    cvmx_sli_mem_access_ctl_t sli_mem_access_ctl;
891215990Sjmallett    cvmx_sli_mem_access_subidx_t mem_access_subid;
892215990Sjmallett    cvmx_mio_rst_ctlx_t mio_rst_ctlx;
893215990Sjmallett    cvmx_sriox_status_reg_t sriox_status_reg;
894215990Sjmallett    cvmx_pemx_bar1_indexx_t bar1_index;
895215990Sjmallett
896215990Sjmallett    /* Make sure this interface isn't SRIO */
897215990Sjmallett    sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port));
898215990Sjmallett    if (sriox_status_reg.s.srio)
899215990Sjmallett    {
900215990Sjmallett        cvmx_dprintf("PCIe: Port %d is SRIO, skipping.\n", pcie_port);
901215990Sjmallett        return -1;
902215990Sjmallett    }
903215990Sjmallett
904215990Sjmallett    /* Make sure we aren't trying to setup a target mode interface in host mode */
905215990Sjmallett    mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
906215990Sjmallett    if (!mio_rst_ctl.s.host_mode)
907215990Sjmallett    {
908215990Sjmallett        cvmx_dprintf("PCIe: Port %d in endpoint mode.\n", pcie_port);
909215990Sjmallett        return -1;
910215990Sjmallett    }
911215990Sjmallett
912215990Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
913215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
914215990Sjmallett    {
915215990Sjmallett        if (pcie_port)
916215990Sjmallett        {
917215990Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
918215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
919215990Sjmallett            ciu_qlm.s.txbypass = 1;
920215990Sjmallett            ciu_qlm.s.txdeemph = 5;
921215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
922215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
923215990Sjmallett        }
924215990Sjmallett        else
925215990Sjmallett        {
926215990Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
927215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
928215990Sjmallett            ciu_qlm.s.txbypass = 1;
929215990Sjmallett            ciu_qlm.s.txdeemph = 5;
930215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
931215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
932215990Sjmallett        }
933215990Sjmallett    }
934215990Sjmallett
935215990Sjmallett    /* Bring the PCIe out of reset */
936215990Sjmallett    if (pcie_port)
937215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
938215990Sjmallett    else
939215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
940215990Sjmallett    /* After a chip reset the PCIe will also be in reset. If it isn't,
941215990Sjmallett        most likely someone is trying to init it again without a proper
942215990Sjmallett        PCIe reset */
943215990Sjmallett    if (ciu_soft_prst.s.soft_prst == 0)
944215990Sjmallett    {
945215990Sjmallett        /* Reset the port */
946215990Sjmallett        ciu_soft_prst.s.soft_prst = 1;
947215990Sjmallett        if (pcie_port)
948215990Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
949215990Sjmallett        else
950215990Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
951215990Sjmallett        /* Wait until pcie resets the ports. */
952215990Sjmallett        cvmx_wait_usec(2000);
953215990Sjmallett    }
954215990Sjmallett    if (pcie_port)
955215990Sjmallett    {
956215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
957215990Sjmallett        ciu_soft_prst.s.soft_prst = 0;
958215990Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
959215990Sjmallett    }
960215990Sjmallett    else
961215990Sjmallett    {
962215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
963215990Sjmallett        ciu_soft_prst.s.soft_prst = 0;
964215990Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
965215990Sjmallett    }
966215990Sjmallett
967215990Sjmallett    /* Wait for PCIe reset to complete */
968215990Sjmallett    cvmx_wait_usec(1000);
969215990Sjmallett
970215990Sjmallett    /* Check and make sure PCIe came out of reset. If it doesn't the board
971215990Sjmallett        probably hasn't wired the clocks up and the interface should be
972215990Sjmallett        skipped */
973215990Sjmallett    mio_rst_ctlx.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
974215990Sjmallett    if (!mio_rst_ctlx.s.rst_done)
975215990Sjmallett    {
976215990Sjmallett        cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
977215990Sjmallett        return -1;
978215990Sjmallett    }
979215990Sjmallett
980215990Sjmallett    /* Check BIST status */
981215990Sjmallett    pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port));
982215990Sjmallett    if (pemx_bist_status.u64)
983215990Sjmallett        cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64));
984215990Sjmallett    pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port));
985215990Sjmallett    if (pemx_bist_status2.u64)
986215990Sjmallett        cvmx_dprintf("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64));
987215990Sjmallett
988215990Sjmallett    /* Initialize the config space CSRs */
989215990Sjmallett    __cvmx_pcie_rc_initialize_config_space(pcie_port);
990215990Sjmallett
991215990Sjmallett    /* Enable gen2 speed selection */
992215990Sjmallett    pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port));
993215990Sjmallett    pciercx_cfg515.s.dsc = 1;
994215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32);
995215990Sjmallett
996215990Sjmallett    /* Bring the link up */
997215990Sjmallett    if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port))
998215990Sjmallett    {
999215990Sjmallett        /* Some gen1 devices don't handle the gen 2 training correctly. Disable
1000215990Sjmallett            gen2 and try again with only gen1 */
1001215990Sjmallett        cvmx_pciercx_cfg031_t pciercx_cfg031;
1002215990Sjmallett        pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));
1003215990Sjmallett        pciercx_cfg031.s.mls = 1;
1004215990Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg515.u32);
1005215990Sjmallett        if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port))
1006215990Sjmallett        {
1007215990Sjmallett            cvmx_dprintf("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port);
1008215990Sjmallett            return -1;
1009215990Sjmallett        }
1010215990Sjmallett    }
1011215990Sjmallett
1012215990Sjmallett    /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
1013215990Sjmallett    sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL);
1014215990Sjmallett    sli_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
1015215990Sjmallett    sli_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
1016215990Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);
1017215990Sjmallett
1018215990Sjmallett    /* Setup Mem access SubDIDs */
1019215990Sjmallett    mem_access_subid.u64 = 0;
1020215990Sjmallett    mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1021215990Sjmallett    mem_access_subid.s.nmerge = 0;  /* Allow merging as it works on CN6XXX. */
1022215990Sjmallett    mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
1023215990Sjmallett    mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
1024215990Sjmallett    mem_access_subid.s.wtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1025215990Sjmallett    mem_access_subid.s.rtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1026215990Sjmallett    mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
1027215990Sjmallett
1028215990Sjmallett    /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */
1029215990Sjmallett    for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++)
1030215990Sjmallett    {
1031215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
1032215990Sjmallett        mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */
1033215990Sjmallett    }
1034215990Sjmallett
1035215990Sjmallett    /* Disable the peer to peer forwarding register. This must be setup
1036215990Sjmallett        by the OS after it enumerates the bus and assigns addresses to the
1037215990Sjmallett        PCIe busses */
1038215990Sjmallett    for (i=0; i<4; i++)
1039215990Sjmallett    {
1040215990Sjmallett        cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1);
1041215990Sjmallett        cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1);
1042215990Sjmallett    }
1043215990Sjmallett
1044215990Sjmallett    /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
1045215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0);
1046215990Sjmallett
1047215990Sjmallett    /* Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take precedence
1048215990Sjmallett        where they overlap. It also overlaps with the device addresses, so
1049215990Sjmallett        make sure the peer to peer forwarding is set right */
1050215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0);
1051215990Sjmallett
1052215990Sjmallett    /* Setup BAR2 attributes */
1053215990Sjmallett    /* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */
1054215990Sjmallett    /* � PTLP_RO,CTLP_RO should normally be set (except for debug). */
1055215990Sjmallett    /* � WAIT_COM=0 will likely work for all applications. */
1056215990Sjmallett    /* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */
1057215990Sjmallett    pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port));
1058215990Sjmallett    pemx_bar_ctl.s.bar1_siz = 3;  /* 256MB BAR1*/
1059215990Sjmallett    pemx_bar_ctl.s.bar2_enb = 1;
1060215990Sjmallett    pemx_bar_ctl.s.bar2_esx = 1;
1061215990Sjmallett    pemx_bar_ctl.s.bar2_cax = 0;
1062215990Sjmallett    cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64);
1063215990Sjmallett    sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port));
1064215990Sjmallett    sli_ctl_portx.s.ptlp_ro = 1;
1065215990Sjmallett    sli_ctl_portx.s.ctlp_ro = 1;
1066215990Sjmallett    sli_ctl_portx.s.wait_com = 0;
1067215990Sjmallett    sli_ctl_portx.s.waitl_com = 0;
1068215990Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64);
1069215990Sjmallett
1070215990Sjmallett    /* BAR1 follows BAR2 */
1071215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
1072215990Sjmallett
1073215990Sjmallett    bar1_index.u64 = 0;
1074215990Sjmallett    bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
1075215990Sjmallett    bar1_index.s.ca = 1;       /* Not Cached */
1076215990Sjmallett    bar1_index.s.end_swp = 1;  /* Endian Swap mode */
1077215990Sjmallett    bar1_index.s.addr_v = 1;   /* Valid entry */
1078215990Sjmallett
1079215990Sjmallett    for (i = 0; i < 16; i++) {
1080215990Sjmallett        cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64);
1081215990Sjmallett        /* 256MB / 16 >> 22 == 4 */
1082215990Sjmallett        bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
1083215990Sjmallett    }
1084215990Sjmallett
1085215990Sjmallett    /* Allow config retries for 250ms. Count is based off the 5Ghz SERDES
1086215990Sjmallett        clock */
1087215990Sjmallett    pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
1088215990Sjmallett    pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000;
1089215990Sjmallett    cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64);
1090215990Sjmallett
1091215990Sjmallett    /* Display the link status */
1092215990Sjmallett    pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
1093215990Sjmallett    cvmx_dprintf("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);
1094215990Sjmallett
1095215990Sjmallett    return 0;
1096215990Sjmallett}
1097215990Sjmallett
1098215990Sjmallett/**
1099215990Sjmallett * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus.
1100215990Sjmallett *
1101215990Sjmallett * @param pcie_port PCIe port to initialize
1102215990Sjmallett *
1103215990Sjmallett * @return Zero on success
1104215990Sjmallett */
1105215990Sjmallettint cvmx_pcie_rc_initialize(int pcie_port)
1106215990Sjmallett{
1107215990Sjmallett    int result;
1108215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1109215990Sjmallett        result = __cvmx_pcie_rc_initialize_gen1(pcie_port);
1110215990Sjmallett    else
1111215990Sjmallett        result = __cvmx_pcie_rc_initialize_gen2(pcie_port);
1112215990Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) || defined(CONFIG_CAVIUM_DECODE_RSL)
1113215990Sjmallett    if (result == 0)
1114215990Sjmallett        cvmx_error_enable_group(CVMX_ERROR_GROUP_PCI, pcie_port);
1115215990Sjmallett#endif
1116215990Sjmallett    return result;
1117215990Sjmallett}
1118215990Sjmallett
1119215990Sjmallett
1120215990Sjmallett/**
1121210284Sjmallett * Shutdown a PCIe port and put it in reset
1122210284Sjmallett *
1123210284Sjmallett * @param pcie_port PCIe port to shutdown
1124210284Sjmallett *
1125210284Sjmallett * @return Zero on success
1126210284Sjmallett */
1127210284Sjmallettint cvmx_pcie_rc_shutdown(int pcie_port)
1128210284Sjmallett{
1129215990Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) || defined(CONFIG_CAVIUM_DECODE_RSL)
1130215990Sjmallett    cvmx_error_disable_group(CVMX_ERROR_GROUP_PCI, pcie_port);
1131215990Sjmallett#endif
1132210284Sjmallett    /* Wait for all pending operations to complete */
1133215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1134215990Sjmallett    {
1135215990Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CPL_LUT_VALID(pcie_port), cvmx_pescx_cpl_lut_valid_t, tag, ==, 0, 2000))
1136215990Sjmallett            cvmx_dprintf("PCIe: Port %d shutdown timeout\n", pcie_port);
1137215990Sjmallett    }
1138215990Sjmallett    else
1139215990Sjmallett    {
1140215990Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PEMX_CPL_LUT_VALID(pcie_port), cvmx_pemx_cpl_lut_valid_t, tag, ==, 0, 2000))
1141215990Sjmallett            cvmx_dprintf("PCIe: Port %d shutdown timeout\n", pcie_port);
1142215990Sjmallett    }
1143210284Sjmallett
1144210284Sjmallett    /* Force reset */
1145210284Sjmallett    if (pcie_port)
1146210284Sjmallett    {
1147210284Sjmallett        cvmx_ciu_soft_prst_t ciu_soft_prst;
1148210284Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
1149210284Sjmallett        ciu_soft_prst.s.soft_prst = 1;
1150210284Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
1151210284Sjmallett    }
1152210284Sjmallett    else
1153210284Sjmallett    {
1154210284Sjmallett        cvmx_ciu_soft_prst_t ciu_soft_prst;
1155210284Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
1156210284Sjmallett        ciu_soft_prst.s.soft_prst = 1;
1157210284Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
1158210284Sjmallett    }
1159210284Sjmallett    return 0;
1160210284Sjmallett}
1161210284Sjmallett
1162210284Sjmallett
1163210284Sjmallett/**
1164210284Sjmallett * @INTERNAL
1165210284Sjmallett * Build a PCIe config space request address for a device
1166210284Sjmallett *
1167210284Sjmallett * @param pcie_port PCIe port to access
1168210284Sjmallett * @param bus       Sub bus
1169210284Sjmallett * @param dev       Device ID
1170210284Sjmallett * @param fn        Device sub function
1171210284Sjmallett * @param reg       Register to access
1172210284Sjmallett *
1173210284Sjmallett * @return 64bit Octeon IO address
1174210284Sjmallett */
1175210284Sjmallettstatic inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, int dev, int fn, int reg)
1176210284Sjmallett{
1177210284Sjmallett    cvmx_pcie_address_t pcie_addr;
1178210284Sjmallett    cvmx_pciercx_cfg006_t pciercx_cfg006;
1179210284Sjmallett
1180210284Sjmallett    pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port));
1181210284Sjmallett    if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0))
1182210284Sjmallett        return 0;
1183210284Sjmallett
1184210284Sjmallett    pcie_addr.u64 = 0;
1185210284Sjmallett    pcie_addr.config.upper = 2;
1186210284Sjmallett    pcie_addr.config.io = 1;
1187210284Sjmallett    pcie_addr.config.did = 3;
1188210284Sjmallett    pcie_addr.config.subdid = 1;
1189210284Sjmallett    pcie_addr.config.es = 1;
1190210284Sjmallett    pcie_addr.config.port = pcie_port;
1191210284Sjmallett    pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum);
1192210284Sjmallett    pcie_addr.config.bus = bus;
1193210284Sjmallett    pcie_addr.config.dev = dev;
1194210284Sjmallett    pcie_addr.config.func = fn;
1195210284Sjmallett    pcie_addr.config.reg = reg;
1196210284Sjmallett    return pcie_addr.u64;
1197210284Sjmallett}
1198210284Sjmallett
1199210284Sjmallett
1200210284Sjmallett/**
1201210284Sjmallett * Read 8bits from a Device's config space
1202210284Sjmallett *
1203210284Sjmallett * @param pcie_port PCIe port the device is on
1204210284Sjmallett * @param bus       Sub bus
1205210284Sjmallett * @param dev       Device ID
1206210284Sjmallett * @param fn        Device sub function
1207210284Sjmallett * @param reg       Register to access
1208210284Sjmallett *
1209210284Sjmallett * @return Result of the read
1210210284Sjmallett */
1211210284Sjmallettuint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg)
1212210284Sjmallett{
1213210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1214210284Sjmallett    if (address)
1215210284Sjmallett        return cvmx_read64_uint8(address);
1216210284Sjmallett    else
1217210284Sjmallett        return 0xff;
1218210284Sjmallett}
1219210284Sjmallett
1220210284Sjmallett
1221210284Sjmallett/**
1222210284Sjmallett * Read 16bits from a Device's config space
1223210284Sjmallett *
1224210284Sjmallett * @param pcie_port PCIe port the device is on
1225210284Sjmallett * @param bus       Sub bus
1226210284Sjmallett * @param dev       Device ID
1227210284Sjmallett * @param fn        Device sub function
1228210284Sjmallett * @param reg       Register to access
1229210284Sjmallett *
1230210284Sjmallett * @return Result of the read
1231210284Sjmallett */
1232210284Sjmallettuint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg)
1233210284Sjmallett{
1234210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1235210284Sjmallett    if (address)
1236210284Sjmallett        return cvmx_le16_to_cpu(cvmx_read64_uint16(address));
1237210284Sjmallett    else
1238210284Sjmallett        return 0xffff;
1239210284Sjmallett}
1240210284Sjmallett
1241210284Sjmallett
1242210284Sjmallett/**
1243210284Sjmallett * Read 32bits from a Device's config space
1244210284Sjmallett *
1245210284Sjmallett * @param pcie_port PCIe port the device is on
1246210284Sjmallett * @param bus       Sub bus
1247210284Sjmallett * @param dev       Device ID
1248210284Sjmallett * @param fn        Device sub function
1249210284Sjmallett * @param reg       Register to access
1250210284Sjmallett *
1251210284Sjmallett * @return Result of the read
1252210284Sjmallett */
1253210284Sjmallettuint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg)
1254210284Sjmallett{
1255210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1256210284Sjmallett    if (address)
1257210284Sjmallett        return cvmx_le32_to_cpu(cvmx_read64_uint32(address));
1258210284Sjmallett    else
1259210284Sjmallett        return 0xffffffff;
1260210284Sjmallett}
1261210284Sjmallett
1262210284Sjmallett
1263210284Sjmallett/**
1264210284Sjmallett * Write 8bits to a Device's config space
1265210284Sjmallett *
1266210284Sjmallett * @param pcie_port PCIe port the device is on
1267210284Sjmallett * @param bus       Sub bus
1268210284Sjmallett * @param dev       Device ID
1269210284Sjmallett * @param fn        Device sub function
1270210284Sjmallett * @param reg       Register to access
1271210284Sjmallett * @param val       Value to write
1272210284Sjmallett */
1273210284Sjmallettvoid cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, uint8_t val)
1274210284Sjmallett{
1275210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1276210284Sjmallett    if (address)
1277210284Sjmallett        cvmx_write64_uint8(address, val);
1278210284Sjmallett}
1279210284Sjmallett
1280210284Sjmallett
1281210284Sjmallett/**
1282210284Sjmallett * Write 16bits to a Device's config space
1283210284Sjmallett *
1284210284Sjmallett * @param pcie_port PCIe port the device is on
1285210284Sjmallett * @param bus       Sub bus
1286210284Sjmallett * @param dev       Device ID
1287210284Sjmallett * @param fn        Device sub function
1288210284Sjmallett * @param reg       Register to access
1289210284Sjmallett * @param val       Value to write
1290210284Sjmallett */
1291210284Sjmallettvoid cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, uint16_t val)
1292210284Sjmallett{
1293210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1294210284Sjmallett    if (address)
1295210284Sjmallett        cvmx_write64_uint16(address, cvmx_cpu_to_le16(val));
1296210284Sjmallett}
1297210284Sjmallett
1298210284Sjmallett
1299210284Sjmallett/**
1300210284Sjmallett * Write 32bits to a Device's config space
1301210284Sjmallett *
1302210284Sjmallett * @param pcie_port PCIe port the device is on
1303210284Sjmallett * @param bus       Sub bus
1304210284Sjmallett * @param dev       Device ID
1305210284Sjmallett * @param fn        Device sub function
1306210284Sjmallett * @param reg       Register to access
1307210284Sjmallett * @param val       Value to write
1308210284Sjmallett */
1309210284Sjmallettvoid cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, uint32_t val)
1310210284Sjmallett{
1311210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1312210284Sjmallett    if (address)
1313210284Sjmallett        cvmx_write64_uint32(address, cvmx_cpu_to_le32(val));
1314210284Sjmallett}
1315210284Sjmallett
1316210284Sjmallett
1317210284Sjmallett/**
1318210284Sjmallett * Read a PCIe config space register indirectly. This is used for
1319210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
1320210284Sjmallett *
1321210284Sjmallett * @param pcie_port  PCIe port to read from
1322210284Sjmallett * @param cfg_offset Address to read
1323210284Sjmallett *
1324210284Sjmallett * @return Value read
1325210284Sjmallett */
1326210284Sjmallettuint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)
1327210284Sjmallett{
1328215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1329215990Sjmallett    {
1330215990Sjmallett        cvmx_pescx_cfg_rd_t pescx_cfg_rd;
1331215990Sjmallett        pescx_cfg_rd.u64 = 0;
1332215990Sjmallett        pescx_cfg_rd.s.addr = cfg_offset;
1333215990Sjmallett        cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64);
1334215990Sjmallett        pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port));
1335215990Sjmallett        return pescx_cfg_rd.s.data;
1336215990Sjmallett    }
1337215990Sjmallett    else
1338215990Sjmallett    {
1339215990Sjmallett        cvmx_pemx_cfg_rd_t pemx_cfg_rd;
1340215990Sjmallett        pemx_cfg_rd.u64 = 0;
1341215990Sjmallett        pemx_cfg_rd.s.addr = cfg_offset;
1342215990Sjmallett        cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64);
1343215990Sjmallett        pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port));
1344215990Sjmallett        return pemx_cfg_rd.s.data;
1345215990Sjmallett    }
1346210284Sjmallett}
1347210284Sjmallett
1348210284Sjmallett
1349210284Sjmallett/**
1350210284Sjmallett * Write a PCIe config space register indirectly. This is used for
1351210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
1352210284Sjmallett *
1353210284Sjmallett * @param pcie_port  PCIe port to write to
1354210284Sjmallett * @param cfg_offset Address to write
1355210284Sjmallett * @param val        Value to write
1356210284Sjmallett */
1357210284Sjmallettvoid cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val)
1358210284Sjmallett{
1359215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1360215990Sjmallett    {
1361215990Sjmallett        cvmx_pescx_cfg_wr_t pescx_cfg_wr;
1362215990Sjmallett        pescx_cfg_wr.u64 = 0;
1363215990Sjmallett        pescx_cfg_wr.s.addr = cfg_offset;
1364215990Sjmallett        pescx_cfg_wr.s.data = val;
1365215990Sjmallett        cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64);
1366215990Sjmallett    }
1367215990Sjmallett    else
1368215990Sjmallett    {
1369215990Sjmallett        cvmx_pemx_cfg_wr_t pemx_cfg_wr;
1370215990Sjmallett        pemx_cfg_wr.u64 = 0;
1371215990Sjmallett        pemx_cfg_wr.s.addr = cfg_offset;
1372215990Sjmallett        pemx_cfg_wr.s.data = val;
1373215990Sjmallett        cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64);
1374215990Sjmallett    }
1375210284Sjmallett}
1376210284Sjmallett
1377210284Sjmallett
1378210284Sjmallett/**
1379210284Sjmallett * Initialize a PCIe port for use in target(EP) mode.
1380210284Sjmallett *
1381215990Sjmallett * @param pcie_port PCIe port to initialize
1382215990Sjmallett *
1383210284Sjmallett * @return Zero on success
1384210284Sjmallett */
1385215990Sjmallettint cvmx_pcie_ep_initialize(int pcie_port)
1386210284Sjmallett{
1387215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1388215990Sjmallett    {
1389215990Sjmallett        cvmx_npei_ctl_status_t npei_ctl_status;
1390215990Sjmallett        npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
1391215990Sjmallett        if (npei_ctl_status.s.host_mode)
1392215990Sjmallett            return -1;
1393215990Sjmallett    }
1394215990Sjmallett    else
1395215990Sjmallett    {
1396215990Sjmallett        cvmx_mio_rst_ctlx_t mio_rst_ctl;
1397215990Sjmallett        mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
1398215990Sjmallett        if (mio_rst_ctl.s.host_mode)
1399215990Sjmallett            return -1;
1400215990Sjmallett    }
1401210284Sjmallett
1402215990Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
1403215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
1404215990Sjmallett    {
1405215990Sjmallett        if (pcie_port)
1406215990Sjmallett        {
1407215990Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
1408215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
1409215990Sjmallett            ciu_qlm.s.txbypass = 1;
1410215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1411215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1412215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
1413215990Sjmallett        }
1414215990Sjmallett        else
1415215990Sjmallett        {
1416215990Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
1417215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
1418215990Sjmallett            ciu_qlm.s.txbypass = 1;
1419215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1420215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1421215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
1422215990Sjmallett        }
1423215990Sjmallett    }
1424210284Sjmallett
1425210284Sjmallett    /* Enable bus master and memory */
1426215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIEEPX_CFG001(pcie_port), 0x6);
1427210284Sjmallett
1428210284Sjmallett    /* Max Payload Size (PCIE*_CFG030[MPS]) */
1429210284Sjmallett    /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
1430210284Sjmallett    /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
1431210284Sjmallett    /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
1432210284Sjmallett    {
1433215990Sjmallett        cvmx_pcieepx_cfg030_t pcieepx_cfg030;
1434215990Sjmallett        pcieepx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port));
1435215990Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
1436215990Sjmallett        {
1437215990Sjmallett            pcieepx_cfg030.s.mps = MPS_CN5XXX;
1438215990Sjmallett            pcieepx_cfg030.s.mrrs = MRRS_CN5XXX;
1439215990Sjmallett        }
1440215990Sjmallett        else
1441215990Sjmallett        {
1442215990Sjmallett            pcieepx_cfg030.s.mps = MPS_CN6XXX;
1443215990Sjmallett            pcieepx_cfg030.s.mrrs = MRRS_CN6XXX;
1444215990Sjmallett        }
1445215990Sjmallett        pcieepx_cfg030.s.ro_en = 1; /* Enable relaxed ordering. */
1446215990Sjmallett        pcieepx_cfg030.s.ns_en = 1; /* Enable no snoop. */
1447215990Sjmallett        pcieepx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */
1448215990Sjmallett        pcieepx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */
1449215990Sjmallett        pcieepx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */
1450215990Sjmallett        pcieepx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */
1451215990Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port), pcieepx_cfg030.u32);
1452210284Sjmallett    }
1453210284Sjmallett
1454215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1455210284Sjmallett    {
1456215990Sjmallett        /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */
1457215990Sjmallett        /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
1458210284Sjmallett        cvmx_npei_ctl_status2_t npei_ctl_status2;
1459210284Sjmallett        npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
1460215990Sjmallett        npei_ctl_status2.s.mps = MPS_CN5XXX; /* Max payload size = 128 bytes (Limit of most PCs) */
1461215990Sjmallett        npei_ctl_status2.s.mrrs = MRRS_CN5XXX; /* Max read request size = 128 bytes for best Octeon DMA performance */
1462210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
1463210284Sjmallett    }
1464215990Sjmallett    else
1465215990Sjmallett    {
1466215990Sjmallett        /* Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match PCIE*_CFG030[MPS] */
1467215990Sjmallett        /* Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
1468215990Sjmallett        cvmx_dpi_sli_prtx_cfg_t prt_cfg;
1469215990Sjmallett        cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
1470215990Sjmallett        prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port));
1471215990Sjmallett        prt_cfg.s.mps = MPS_CN6XXX;
1472215990Sjmallett        prt_cfg.s.mrrs = MRRS_CN6XXX;
1473215990Sjmallett        cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);
1474210284Sjmallett
1475215990Sjmallett        sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));
1476215990Sjmallett        sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX;
1477215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);
1478215990Sjmallett    }
1479215990Sjmallett
1480210284Sjmallett    /* Setup Mem access SubDID 12 to access Host memory */
1481215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1482210284Sjmallett    {
1483210284Sjmallett        cvmx_npei_mem_access_subidx_t mem_access_subid;
1484210284Sjmallett        mem_access_subid.u64 = 0;
1485210284Sjmallett        mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1486215990Sjmallett        mem_access_subid.s.nmerge = 1;  /* Merging is not allowed in this window. */
1487210284Sjmallett        mem_access_subid.s.esr = 0;     /* Endian-swap for Reads. */
1488210284Sjmallett        mem_access_subid.s.esw = 0;     /* Endian-swap for Writes. */
1489210284Sjmallett        mem_access_subid.s.nsr = 0;     /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
1490210284Sjmallett        mem_access_subid.s.nsw = 0;     /* Enable Snoop for Writes. */
1491210284Sjmallett        mem_access_subid.s.ror = 0;     /* Disable Relaxed Ordering for Reads. */
1492210284Sjmallett        mem_access_subid.s.row = 0;     /* Disable Relaxed Ordering for Writes. */
1493210284Sjmallett        mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
1494210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(12), mem_access_subid.u64);
1495210284Sjmallett    }
1496215990Sjmallett    else
1497215990Sjmallett    {
1498215990Sjmallett        cvmx_sli_mem_access_subidx_t mem_access_subid;
1499215990Sjmallett        mem_access_subid.u64 = 0;
1500215990Sjmallett        mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1501215990Sjmallett        mem_access_subid.s.nmerge = 0;  /* Merging is allowed in this window. */
1502215990Sjmallett        mem_access_subid.s.esr = 0;     /* Endian-swap for Reads. */
1503215990Sjmallett        mem_access_subid.s.esw = 0;     /* Endian-swap for Writes. */
1504215990Sjmallett        mem_access_subid.s.wtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1505215990Sjmallett        mem_access_subid.s.rtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1506215990Sjmallett        mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
1507215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(12 + pcie_port*4), mem_access_subid.u64);
1508215990Sjmallett    }
1509210284Sjmallett    return 0;
1510210284Sjmallett}
1511210284Sjmallett
1512210284Sjmallett
1513210284Sjmallett/**
1514210284Sjmallett * Wait for posted PCIe read/writes to reach the other side of
1515210284Sjmallett * the internal PCIe switch. This will insure that core
1516210284Sjmallett * read/writes are posted before anything after this function
1517210284Sjmallett * is called. This may be necessary when writing to memory that
1518210284Sjmallett * will later be read using the DMA/PKT engines.
1519210284Sjmallett *
1520210284Sjmallett * @param pcie_port PCIe port to wait for
1521210284Sjmallett */
1522210284Sjmallettvoid cvmx_pcie_wait_for_pending(int pcie_port)
1523210284Sjmallett{
1524215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1525215990Sjmallett    {
1526215990Sjmallett        cvmx_npei_data_out_cnt_t npei_data_out_cnt;
1527215990Sjmallett        int a;
1528215990Sjmallett        int b;
1529215990Sjmallett        int c;
1530210284Sjmallett
1531215990Sjmallett        /* See section 9.8, PCIe Core-initiated Requests, in the manual for a
1532215990Sjmallett            description of how this code works */
1533215990Sjmallett        npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT);
1534215990Sjmallett        if (pcie_port)
1535215990Sjmallett        {
1536215990Sjmallett            if (!npei_data_out_cnt.s.p1_fcnt)
1537215990Sjmallett                return;
1538215990Sjmallett            a = npei_data_out_cnt.s.p1_ucnt;
1539215990Sjmallett            b = (a + npei_data_out_cnt.s.p1_fcnt-1) & 0xffff;
1540215990Sjmallett        }
1541215990Sjmallett        else
1542215990Sjmallett        {
1543215990Sjmallett            if (!npei_data_out_cnt.s.p0_fcnt)
1544215990Sjmallett                return;
1545215990Sjmallett            a = npei_data_out_cnt.s.p0_ucnt;
1546215990Sjmallett            b = (a + npei_data_out_cnt.s.p0_fcnt-1) & 0xffff;
1547215990Sjmallett        }
1548215990Sjmallett
1549215990Sjmallett        while (1)
1550215990Sjmallett        {
1551215990Sjmallett            npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT);
1552215990Sjmallett            c = (pcie_port) ? npei_data_out_cnt.s.p1_ucnt : npei_data_out_cnt.s.p0_ucnt;
1553215990Sjmallett            if (a<=b)
1554215990Sjmallett            {
1555215990Sjmallett                if ((c<a) || (c>b))
1556215990Sjmallett                    return;
1557215990Sjmallett            }
1558215990Sjmallett            else
1559215990Sjmallett            {
1560215990Sjmallett                if ((c>b) && (c<a))
1561215990Sjmallett                    return;
1562215990Sjmallett            }
1563215990Sjmallett        }
1564210284Sjmallett    }
1565210284Sjmallett    else
1566210284Sjmallett    {
1567215990Sjmallett        cvmx_sli_data_out_cnt_t sli_data_out_cnt;
1568215990Sjmallett        int a;
1569215990Sjmallett        int b;
1570215990Sjmallett        int c;
1571210284Sjmallett
1572215990Sjmallett        sli_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_SLI_DATA_OUT_CNT);
1573215990Sjmallett        if (pcie_port)
1574210284Sjmallett        {
1575215990Sjmallett            if (!sli_data_out_cnt.s.p1_fcnt)
1576210284Sjmallett                return;
1577215990Sjmallett            a = sli_data_out_cnt.s.p1_ucnt;
1578215990Sjmallett            b = (a + sli_data_out_cnt.s.p1_fcnt-1) & 0xffff;
1579210284Sjmallett        }
1580210284Sjmallett        else
1581210284Sjmallett        {
1582215990Sjmallett            if (!sli_data_out_cnt.s.p0_fcnt)
1583210284Sjmallett                return;
1584215990Sjmallett            a = sli_data_out_cnt.s.p0_ucnt;
1585215990Sjmallett            b = (a + sli_data_out_cnt.s.p0_fcnt-1) & 0xffff;
1586210284Sjmallett        }
1587215990Sjmallett
1588215990Sjmallett        while (1)
1589215990Sjmallett        {
1590215990Sjmallett            sli_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_SLI_DATA_OUT_CNT);
1591215990Sjmallett            c = (pcie_port) ? sli_data_out_cnt.s.p1_ucnt : sli_data_out_cnt.s.p0_ucnt;
1592215990Sjmallett            if (a<=b)
1593215990Sjmallett            {
1594215990Sjmallett                if ((c<a) || (c>b))
1595215990Sjmallett                    return;
1596215990Sjmallett            }
1597215990Sjmallett            else
1598215990Sjmallett            {
1599215990Sjmallett                if ((c>b) && (c<a))
1600215990Sjmallett                    return;
1601215990Sjmallett            }
1602215990Sjmallett        }
1603210284Sjmallett    }
1604210284Sjmallett}
1605