1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2011  Cavium, Inc. <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
18232812Sjmallett *   * Neither the name of Cavium Inc. 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"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. 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 * @file
42210284Sjmallett *
43210284Sjmallett * Interface to PCIe as a host(RC) or target(EP)
44210284Sjmallett *
45232812Sjmallett * <hr>$Revision: 70030 $<hr>
46210284Sjmallett */
47215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
48215990Sjmallett#include <asm/octeon/cvmx.h>
49215990Sjmallett#include <asm/octeon/cvmx-config.h>
50215990Sjmallett#include <asm/octeon/cvmx-clock.h>
51215990Sjmallett#include <asm/octeon/cvmx-ciu-defs.h>
52215990Sjmallett#include <asm/octeon/cvmx-dpi-defs.h>
53232812Sjmallett#include <asm/octeon/cvmx-mio-defs.h>
54215990Sjmallett#include <asm/octeon/cvmx-npi-defs.h>
55215990Sjmallett#include <asm/octeon/cvmx-npei-defs.h>
56215990Sjmallett#include <asm/octeon/cvmx-pci-defs.h>
57215990Sjmallett#include <asm/octeon/cvmx-pcieepx-defs.h>
58215990Sjmallett#include <asm/octeon/cvmx-pciercx-defs.h>
59215990Sjmallett#include <asm/octeon/cvmx-pemx-defs.h>
60215990Sjmallett#include <asm/octeon/cvmx-pexp-defs.h>
61215990Sjmallett#include <asm/octeon/cvmx-pescx-defs.h>
62215990Sjmallett#include <asm/octeon/cvmx-sli-defs.h>
63215990Sjmallett#include <asm/octeon/cvmx-sriox-defs.h>
64232812Sjmallett#include <asm/octeon/cvmx-helper-jtag.h>
65215990Sjmallett
66215990Sjmallett#ifdef CONFIG_CAVIUM_DECODE_RSL
67215990Sjmallett#include <asm/octeon/cvmx-error.h>
68215990Sjmallett#endif
69215990Sjmallett#include <asm/octeon/cvmx-helper.h>
70215990Sjmallett#include <asm/octeon/cvmx-helper-board.h>
71215990Sjmallett#include <asm/octeon/cvmx-helper-errata.h>
72232812Sjmallett#include <asm/octeon/cvmx-qlm.h>
73215990Sjmallett#include <asm/octeon/cvmx-pcie.h>
74215990Sjmallett#include <asm/octeon/cvmx-sysinfo.h>
75215990Sjmallett#include <asm/octeon/cvmx-swap.h>
76215990Sjmallett#include <asm/octeon/cvmx-wqe.h>
77215990Sjmallett#else
78210284Sjmallett#include "cvmx.h"
79232915Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
80210284Sjmallett#include "cvmx-csr-db.h"
81232915Sjmallett#endif
82210284Sjmallett#include "cvmx-pcie.h"
83210284Sjmallett#include "cvmx-sysinfo.h"
84210284Sjmallett#include "cvmx-swap.h"
85210284Sjmallett#include "cvmx-wqe.h"
86232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
87215990Sjmallett#include "cvmx-error.h"
88232816Sjmallett#endif
89210284Sjmallett#include "cvmx-helper-errata.h"
90232812Sjmallett#include "cvmx-qlm.h"
91215990Sjmallett#endif
92210284Sjmallett
93215990Sjmallett#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */
94215990Sjmallett#define MPS_CN5XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
95215990Sjmallett#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */
96215990Sjmallett#define MPS_CN6XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
97210284Sjmallett
98210284Sjmallett/**
99210284Sjmallett * Return the Core virtual base address for PCIe IO access. IOs are
100210284Sjmallett * read/written as an offset from this address.
101210284Sjmallett *
102210284Sjmallett * @param pcie_port PCIe port the IO is for
103210284Sjmallett *
104210284Sjmallett * @return 64bit Octeon IO base address for read/write
105210284Sjmallett */
106210284Sjmallettuint64_t cvmx_pcie_get_io_base_address(int pcie_port)
107210284Sjmallett{
108210284Sjmallett    cvmx_pcie_address_t pcie_addr;
109210284Sjmallett    pcie_addr.u64 = 0;
110210284Sjmallett    pcie_addr.io.upper = 0;
111210284Sjmallett    pcie_addr.io.io = 1;
112210284Sjmallett    pcie_addr.io.did = 3;
113210284Sjmallett    pcie_addr.io.subdid = 2;
114210284Sjmallett    pcie_addr.io.es = 1;
115210284Sjmallett    pcie_addr.io.port = pcie_port;
116210284Sjmallett    return pcie_addr.u64;
117210284Sjmallett}
118210284Sjmallett
119210284Sjmallett
120210284Sjmallett/**
121210284Sjmallett * Size of the IO address region returned at address
122210284Sjmallett * cvmx_pcie_get_io_base_address()
123210284Sjmallett *
124210284Sjmallett * @param pcie_port PCIe port the IO is for
125210284Sjmallett *
126210284Sjmallett * @return Size of the IO window
127210284Sjmallett */
128210284Sjmallettuint64_t cvmx_pcie_get_io_size(int pcie_port)
129210284Sjmallett{
130210284Sjmallett    return 1ull<<32;
131210284Sjmallett}
132210284Sjmallett
133210284Sjmallett
134210284Sjmallett/**
135210284Sjmallett * Return the Core virtual base address for PCIe MEM access. Memory is
136210284Sjmallett * read/written as an offset from this address.
137210284Sjmallett *
138210284Sjmallett * @param pcie_port PCIe port the IO is for
139210284Sjmallett *
140210284Sjmallett * @return 64bit Octeon IO base address for read/write
141210284Sjmallett */
142210284Sjmallettuint64_t cvmx_pcie_get_mem_base_address(int pcie_port)
143210284Sjmallett{
144210284Sjmallett    cvmx_pcie_address_t pcie_addr;
145210284Sjmallett    pcie_addr.u64 = 0;
146210284Sjmallett    pcie_addr.mem.upper = 0;
147210284Sjmallett    pcie_addr.mem.io = 1;
148210284Sjmallett    pcie_addr.mem.did = 3;
149210284Sjmallett    pcie_addr.mem.subdid = 3 + pcie_port;
150210284Sjmallett    return pcie_addr.u64;
151210284Sjmallett}
152210284Sjmallett
153210284Sjmallett
154210284Sjmallett/**
155210284Sjmallett * Size of the Mem address region returned at address
156210284Sjmallett * cvmx_pcie_get_mem_base_address()
157210284Sjmallett *
158210284Sjmallett * @param pcie_port PCIe port the IO is for
159210284Sjmallett *
160210284Sjmallett * @return Size of the Mem window
161210284Sjmallett */
162210284Sjmallettuint64_t cvmx_pcie_get_mem_size(int pcie_port)
163210284Sjmallett{
164210284Sjmallett    return 1ull<<36;
165210284Sjmallett}
166210284Sjmallett
167210284Sjmallett
168210284Sjmallett/**
169210284Sjmallett * @INTERNAL
170210284Sjmallett * Initialize the RC config space CSRs
171210284Sjmallett *
172210284Sjmallett * @param pcie_port PCIe port to initialize
173210284Sjmallett */
174210284Sjmallettstatic void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
175210284Sjmallett{
176210284Sjmallett    /* Max Payload Size (PCIE*_CFG030[MPS]) */
177210284Sjmallett    /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
178210284Sjmallett    /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
179210284Sjmallett    /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
180210284Sjmallett    {
181210284Sjmallett        cvmx_pciercx_cfg030_t pciercx_cfg030;
182210284Sjmallett        pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port));
183215990Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
184215990Sjmallett        {
185215990Sjmallett            pciercx_cfg030.s.mps = MPS_CN5XXX;
186215990Sjmallett            pciercx_cfg030.s.mrrs = MRRS_CN5XXX;
187215990Sjmallett        }
188215990Sjmallett        else
189215990Sjmallett        {
190215990Sjmallett            pciercx_cfg030.s.mps = MPS_CN6XXX;
191215990Sjmallett            pciercx_cfg030.s.mrrs = MRRS_CN6XXX;
192215990Sjmallett        }
193210284Sjmallett        pciercx_cfg030.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */
194210284Sjmallett        pciercx_cfg030.s.ns_en = 1; /* Enable no snoop processing. Not used by Octeon */
195210284Sjmallett        pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */
196210284Sjmallett        pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */
197210284Sjmallett        pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */
198210284Sjmallett        pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */
199210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32);
200210284Sjmallett    }
201210284Sjmallett
202215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
203210284Sjmallett    {
204215990Sjmallett        /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */
205215990Sjmallett        /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
206210284Sjmallett        cvmx_npei_ctl_status2_t npei_ctl_status2;
207210284Sjmallett        npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
208215990Sjmallett        npei_ctl_status2.s.mps = MPS_CN5XXX; /* Max payload size = 128 bytes for best Octeon DMA performance */
209215990Sjmallett        npei_ctl_status2.s.mrrs = MRRS_CN5XXX; /* Max read request size = 128 bytes for best Octeon DMA performance */
210215990Sjmallett        if (pcie_port)
211215990Sjmallett            npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
212215990Sjmallett        else
213215990Sjmallett            npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
214215990Sjmallett
215210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
216210284Sjmallett    }
217215990Sjmallett    else
218215990Sjmallett    {
219215990Sjmallett        /* Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match PCIE*_CFG030[MPS] */
220215990Sjmallett        /* Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
221215990Sjmallett        cvmx_dpi_sli_prtx_cfg_t prt_cfg;
222215990Sjmallett        cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
223215990Sjmallett        prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port));
224215990Sjmallett        prt_cfg.s.mps = MPS_CN6XXX;
225215990Sjmallett        prt_cfg.s.mrrs = MRRS_CN6XXX;
226232812Sjmallett        /* Max outstanding load request. */
227232812Sjmallett        prt_cfg.s.molr = 32;
228215990Sjmallett        cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);
229210284Sjmallett
230215990Sjmallett        sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));
231215990Sjmallett        sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX;
232215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);
233215990Sjmallett    }
234215990Sjmallett
235210284Sjmallett    /* ECRC Generation (PCIE*_CFG070[GE,CE]) */
236210284Sjmallett    {
237210284Sjmallett        cvmx_pciercx_cfg070_t pciercx_cfg070;
238210284Sjmallett        pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));
239210284Sjmallett        pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */
240210284Sjmallett        pciercx_cfg070.s.ce = 1; /* ECRC check enable. */
241210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32);
242210284Sjmallett    }
243210284Sjmallett
244210284Sjmallett    /* Access Enables (PCIE*_CFG001[MSAE,ME]) */
245210284Sjmallett        /* ME and MSAE should always be set. */
246210284Sjmallett    /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */
247210284Sjmallett    /* System Error Message Enable (PCIE*_CFG001[SEE]) */
248210284Sjmallett    {
249210284Sjmallett        cvmx_pciercx_cfg001_t pciercx_cfg001;
250210284Sjmallett        pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));
251210284Sjmallett        pciercx_cfg001.s.msae = 1; /* Memory space enable. */
252210284Sjmallett        pciercx_cfg001.s.me = 1; /* Bus master enable. */
253210284Sjmallett        pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */
254210284Sjmallett        pciercx_cfg001.s.see = 1; /* SERR# enable */
255210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32);
256210284Sjmallett    }
257210284Sjmallett
258210284Sjmallett
259210284Sjmallett    /* Advanced Error Recovery Message Enables */
260210284Sjmallett    /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */
261210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0);
262210284Sjmallett    /* Use CVMX_PCIERCX_CFG067 hardware default */
263210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0);
264210284Sjmallett
265210284Sjmallett
266210284Sjmallett    /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
267210284Sjmallett    {
268210284Sjmallett        cvmx_pciercx_cfg032_t pciercx_cfg032;
269210284Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
270210284Sjmallett        pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */
271210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32);
272210284Sjmallett    }
273210284Sjmallett
274210284Sjmallett    /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during cvmx_pcie_rc_initialize_link() */
275210284Sjmallett    /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */
276210284Sjmallett    {
277210284Sjmallett        /* We set the primary bus number to 1 so IDT bridges are happy. They don't like zero */
278210284Sjmallett        cvmx_pciercx_cfg006_t pciercx_cfg006;
279210284Sjmallett        pciercx_cfg006.u32 = 0;
280210284Sjmallett        pciercx_cfg006.s.pbnum = 1;
281210284Sjmallett        pciercx_cfg006.s.sbnum = 1;
282210284Sjmallett        pciercx_cfg006.s.subbnum = 1;
283210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32);
284210284Sjmallett    }
285210284Sjmallett
286210284Sjmallett    /* Memory-mapped I/O BAR (PCIERCn_CFG008) */
287210284Sjmallett    /* Most applications should disable the memory-mapped I/O BAR by */
288210284Sjmallett    /* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */
289210284Sjmallett    {
290210284Sjmallett        cvmx_pciercx_cfg008_t pciercx_cfg008;
291210284Sjmallett        pciercx_cfg008.u32 = 0;
292210284Sjmallett        pciercx_cfg008.s.mb_addr = 0x100;
293210284Sjmallett        pciercx_cfg008.s.ml_addr = 0;
294210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32);
295210284Sjmallett    }
296210284Sjmallett
297210284Sjmallett    /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */
298210284Sjmallett    /* Most applications should disable the prefetchable BAR by setting */
299210284Sjmallett    /* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */
300210284Sjmallett    /* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */
301210284Sjmallett    {
302210284Sjmallett        cvmx_pciercx_cfg009_t pciercx_cfg009;
303210284Sjmallett        cvmx_pciercx_cfg010_t pciercx_cfg010;
304210284Sjmallett        cvmx_pciercx_cfg011_t pciercx_cfg011;
305210284Sjmallett        pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));
306210284Sjmallett        pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));
307210284Sjmallett        pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));
308210284Sjmallett        pciercx_cfg009.s.lmem_base = 0x100;
309210284Sjmallett        pciercx_cfg009.s.lmem_limit = 0;
310210284Sjmallett        pciercx_cfg010.s.umem_base = 0x100;
311210284Sjmallett        pciercx_cfg011.s.umem_limit = 0;
312210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32);
313210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32);
314210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32);
315210284Sjmallett    }
316210284Sjmallett
317210284Sjmallett    /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */
318210284Sjmallett    /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */
319210284Sjmallett    {
320210284Sjmallett        cvmx_pciercx_cfg035_t pciercx_cfg035;
321210284Sjmallett        pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));
322210284Sjmallett        pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */
323210284Sjmallett        pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */
324210284Sjmallett        pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */
325210284Sjmallett        pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */
326210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32);
327210284Sjmallett    }
328210284Sjmallett
329210284Sjmallett    /* Advanced Error Recovery Interrupt Enables */
330210284Sjmallett    /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */
331210284Sjmallett    {
332210284Sjmallett        cvmx_pciercx_cfg075_t pciercx_cfg075;
333210284Sjmallett        pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));
334210284Sjmallett        pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */
335210284Sjmallett        pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */
336210284Sjmallett        pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */
337210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32);
338210284Sjmallett    }
339210284Sjmallett
340210284Sjmallett    /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */
341210284Sjmallett    /* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */
342210284Sjmallett    {
343210284Sjmallett        cvmx_pciercx_cfg034_t pciercx_cfg034;
344210284Sjmallett        pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));
345210284Sjmallett        pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */
346210284Sjmallett        pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */
347210284Sjmallett        pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */
348210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32);
349210284Sjmallett    }
350210284Sjmallett}
351210284Sjmallett
352210284Sjmallett/**
353210284Sjmallett * @INTERNAL
354215990Sjmallett * Initialize a host mode PCIe gen 1 link. This function takes a PCIe
355210284Sjmallett * port from reset to a link up state. Software can then begin
356210284Sjmallett * configuring the rest of the link.
357210284Sjmallett *
358210284Sjmallett * @param pcie_port PCIe port to initialize
359210284Sjmallett *
360210284Sjmallett * @return Zero on success
361210284Sjmallett */
362215990Sjmallettstatic int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port)
363210284Sjmallett{
364210284Sjmallett    uint64_t start_cycle;
365210284Sjmallett    cvmx_pescx_ctl_status_t pescx_ctl_status;
366210284Sjmallett    cvmx_pciercx_cfg452_t pciercx_cfg452;
367210284Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
368210284Sjmallett    cvmx_pciercx_cfg448_t pciercx_cfg448;
369210284Sjmallett
370210284Sjmallett    /* Set the lane width */
371210284Sjmallett    pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));
372210284Sjmallett    pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
373210284Sjmallett    if (pescx_ctl_status.s.qlm_cfg == 0)
374210284Sjmallett    {
375210284Sjmallett        /* We're in 8 lane (56XX) or 4 lane (54XX) mode */
376210284Sjmallett        pciercx_cfg452.s.lme = 0xf;
377210284Sjmallett    }
378210284Sjmallett    else
379210284Sjmallett    {
380210284Sjmallett        /* We're in 4 lane (56XX) or 2 lane (52XX) mode */
381210284Sjmallett        pciercx_cfg452.s.lme = 0x7;
382210284Sjmallett    }
383210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32);
384210284Sjmallett
385210284Sjmallett    /* CN52XX pass 1.x has an errata where length mismatches on UR responses can
386210284Sjmallett        cause bus errors on 64bit memory reads. Turning off length error
387210284Sjmallett        checking fixes this */
388210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
389210284Sjmallett    {
390210284Sjmallett        cvmx_pciercx_cfg455_t pciercx_cfg455;
391210284Sjmallett        pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port));
392210284Sjmallett        pciercx_cfg455.s.m_cpl_len_err = 1;
393210284Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32);
394210284Sjmallett    }
395210284Sjmallett
396210284Sjmallett    /* Lane swap needs to be manually enabled for CN52XX */
397210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1))
398210284Sjmallett    {
399216476Sjmallett      switch (cvmx_sysinfo_get()->board_type)
400216476Sjmallett      {
401216476Sjmallett#if defined(OCTEON_VENDOR_LANNER)
402216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
403216476Sjmallett	  break;
404216476Sjmallett#endif
405216476Sjmallett	default:
406216476Sjmallett	  pescx_ctl_status.s.lane_swp = 1;
407216476Sjmallett	  break;
408216476Sjmallett      }
409210284Sjmallett      cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),pescx_ctl_status.u64);
410210284Sjmallett    }
411210284Sjmallett
412210284Sjmallett    /* Bring up the link */
413210284Sjmallett    pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
414210284Sjmallett    pescx_ctl_status.s.lnk_enb = 1;
415210284Sjmallett    cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64);
416210284Sjmallett
417210284Sjmallett    /* CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to be disabled */
418210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
419210284Sjmallett        __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0);
420210284Sjmallett
421210284Sjmallett    /* Wait for the link to come up */
422210284Sjmallett    start_cycle = cvmx_get_cycle();
423210284Sjmallett    do
424210284Sjmallett    {
425250428Simp        if (cvmx_get_cycle() - start_cycle > 100*cvmx_clock_get_rate(CVMX_CLOCK_CORE))
426210284Sjmallett        {
427210284Sjmallett            cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port);
428210284Sjmallett            return -1;
429210284Sjmallett        }
430250428Simp        cvmx_wait(50000);
431210284Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
432210284Sjmallett    } while (pciercx_cfg032.s.dlla == 0);
433210284Sjmallett
434215990Sjmallett    /* Clear all pending errors */
435215990Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM));
436215990Sjmallett
437210284Sjmallett    /* Update the Replay Time Limit. Empirically, some PCIe devices take a
438210284Sjmallett        little longer to respond than expected under load. As a workaround for
439210284Sjmallett        this we configure the Replay Time Limit to the value expected for a 512
440210284Sjmallett        byte MPS instead of our actual 256 byte MPS. The numbers below are
441210284Sjmallett        directly from the PCIe spec table 3-4 */
442210284Sjmallett    pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
443210284Sjmallett    switch (pciercx_cfg032.s.nlw)
444210284Sjmallett    {
445210284Sjmallett        case 1: /* 1 lane */
446210284Sjmallett            pciercx_cfg448.s.rtl = 1677;
447210284Sjmallett            break;
448210284Sjmallett        case 2: /* 2 lanes */
449210284Sjmallett            pciercx_cfg448.s.rtl = 867;
450210284Sjmallett            break;
451210284Sjmallett        case 4: /* 4 lanes */
452210284Sjmallett            pciercx_cfg448.s.rtl = 462;
453210284Sjmallett            break;
454210284Sjmallett        case 8: /* 8 lanes */
455210284Sjmallett            pciercx_cfg448.s.rtl = 258;
456210284Sjmallett            break;
457210284Sjmallett    }
458210284Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
459210284Sjmallett
460210284Sjmallett    return 0;
461210284Sjmallett}
462210284Sjmallett
463232812Sjmallettstatic inline void __cvmx_increment_ba(cvmx_sli_mem_access_subidx_t *pmas)
464232812Sjmallett{
465232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
466232812Sjmallett        pmas->cn68xx.ba++;
467232812Sjmallett    else
468232812Sjmallett        pmas->cn63xx.ba++;
469232812Sjmallett}
470210284Sjmallett
471210284Sjmallett/**
472215990Sjmallett * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't enumerate
473215990Sjmallett * the bus.
474210284Sjmallett *
475210284Sjmallett * @param pcie_port PCIe port to initialize
476210284Sjmallett *
477210284Sjmallett * @return Zero on success
478210284Sjmallett */
479215990Sjmallettstatic int __cvmx_pcie_rc_initialize_gen1(int pcie_port)
480210284Sjmallett{
481210284Sjmallett    int i;
482215990Sjmallett    int base;
483215990Sjmallett    uint64_t addr_swizzle;
484210284Sjmallett    cvmx_ciu_soft_prst_t ciu_soft_prst;
485210284Sjmallett    cvmx_pescx_bist_status_t pescx_bist_status;
486210284Sjmallett    cvmx_pescx_bist_status2_t pescx_bist_status2;
487210284Sjmallett    cvmx_npei_ctl_status_t npei_ctl_status;
488210284Sjmallett    cvmx_npei_mem_access_ctl_t npei_mem_access_ctl;
489210284Sjmallett    cvmx_npei_mem_access_subidx_t mem_access_subid;
490210284Sjmallett    cvmx_npei_dbg_data_t npei_dbg_data;
491210284Sjmallett    cvmx_pescx_ctl_status2_t pescx_ctl_status2;
492210284Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
493215990Sjmallett    cvmx_npei_bar1_indexx_t bar1_index;
494210284Sjmallett
495210284Sjmallettretry:
496210284Sjmallett    /* Make sure we aren't trying to setup a target mode interface in host mode */
497210284Sjmallett    npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
498210284Sjmallett    if ((pcie_port==0) && !npei_ctl_status.s.host_mode)
499210284Sjmallett    {
500215990Sjmallett        cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port);
501210284Sjmallett        return -1;
502210284Sjmallett    }
503210284Sjmallett
504210284Sjmallett    /* Make sure a CN52XX isn't trying to bring up port 1 when it is disabled */
505210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX))
506210284Sjmallett    {
507210284Sjmallett        npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
508210284Sjmallett        if ((pcie_port==1) && npei_dbg_data.cn52xx.qlm0_link_width)
509210284Sjmallett        {
510210284Sjmallett            cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n");
511210284Sjmallett            return -1;
512210284Sjmallett        }
513210284Sjmallett    }
514210284Sjmallett
515230040Sgonzo    /* Make sure a CN56XX pass 1 isn't trying to do anything; errata for PASS 1 */
516230040Sgonzo    if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) {
517230040Sgonzo        cvmx_dprintf ("PCIe port %d: CN56XX_PASS_1, skipping\n", pcie_port);
518230040Sgonzo        return -1;
519230040Sgonzo    }
520230040Sgonzo
521210284Sjmallett    /* PCIe switch arbitration mode. '0' == fixed priority NPEI, PCIe0, then PCIe1. '1' == round robin. */
522210284Sjmallett    npei_ctl_status.s.arb = 1;
523210284Sjmallett    /* Allow up to 0x20 config retries */
524210284Sjmallett    npei_ctl_status.s.cfg_rtry = 0x20;
525210284Sjmallett    /* CN52XX pass1.x has an errata where P0_NTAGS and P1_NTAGS don't reset */
526210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
527210284Sjmallett    {
528210284Sjmallett        npei_ctl_status.s.p0_ntags = 0x20;
529210284Sjmallett        npei_ctl_status.s.p1_ntags = 0x20;
530210284Sjmallett    }
531210284Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS, npei_ctl_status.u64);
532210284Sjmallett
533210284Sjmallett    /* Bring the PCIe out of reset */
534210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200)
535210284Sjmallett    {
536210284Sjmallett        /* The EBH5200 board swapped the PCIe reset lines on the board. As a
537210284Sjmallett            workaround for this bug, we bring both PCIe ports out of reset at
538210284Sjmallett            the same time instead of on separate calls. So for port 0, we bring
539210284Sjmallett            both out of reset and do nothing on port 1 */
540210284Sjmallett        if (pcie_port == 0)
541210284Sjmallett        {
542210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
543210284Sjmallett            /* After a chip reset the PCIe will also be in reset. If it isn't,
544210284Sjmallett                most likely someone is trying to init it again without a proper
545210284Sjmallett                PCIe reset */
546210284Sjmallett            if (ciu_soft_prst.s.soft_prst == 0)
547210284Sjmallett            {
548210284Sjmallett		/* Reset the ports */
549210284Sjmallett		ciu_soft_prst.s.soft_prst = 1;
550210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
551210284Sjmallett		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
552210284Sjmallett		ciu_soft_prst.s.soft_prst = 1;
553210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
554210284Sjmallett		/* Wait until pcie resets the ports. */
555210284Sjmallett		cvmx_wait_usec(2000);
556210284Sjmallett            }
557210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
558210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
559210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
560210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
561210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
562210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
563210284Sjmallett        }
564210284Sjmallett    }
565210284Sjmallett    else
566210284Sjmallett    {
567210284Sjmallett        /* The normal case: The PCIe ports are completely separate and can be
568210284Sjmallett            brought out of reset independently */
569210284Sjmallett        if (pcie_port)
570210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
571210284Sjmallett        else
572210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
573210284Sjmallett        /* After a chip reset the PCIe will also be in reset. If it isn't,
574210284Sjmallett            most likely someone is trying to init it again without a proper
575210284Sjmallett            PCIe reset */
576210284Sjmallett        if (ciu_soft_prst.s.soft_prst == 0)
577210284Sjmallett        {
578210284Sjmallett	    /* Reset the port */
579210284Sjmallett	    ciu_soft_prst.s.soft_prst = 1;
580210284Sjmallett	    if (pcie_port)
581210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
582210284Sjmallett 	    else
583210284Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
584210284Sjmallett	    /* Wait until pcie resets the ports. */
585210284Sjmallett	    cvmx_wait_usec(2000);
586210284Sjmallett        }
587210284Sjmallett        if (pcie_port)
588210284Sjmallett        {
589210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
590210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
591210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
592210284Sjmallett        }
593210284Sjmallett        else
594210284Sjmallett        {
595210284Sjmallett            ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
596210284Sjmallett            ciu_soft_prst.s.soft_prst = 0;
597210284Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
598210284Sjmallett        }
599210284Sjmallett    }
600210284Sjmallett
601210284Sjmallett    /* Wait for PCIe reset to complete. Due to errata PCIE-700, we don't poll
602210284Sjmallett       PESCX_CTL_STATUS2[PCIERST], but simply wait a fixed number of cycles */
603210284Sjmallett    cvmx_wait(400000);
604210284Sjmallett
605210284Sjmallett    /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and
606210284Sjmallett        CN52XX, so we only probe it on newer chips */
607210284Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
608210284Sjmallett    {
609210284Sjmallett        /* Clear PCLK_RUN so we can check if the clock is running */
610210284Sjmallett        pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
611210284Sjmallett        pescx_ctl_status2.s.pclk_run = 1;
612210284Sjmallett        cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64);
613210284Sjmallett        /* Now that we cleared PCLK_RUN, wait for it to be set again telling
614210284Sjmallett            us the clock is running */
615210284Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port),
616210284Sjmallett            cvmx_pescx_ctl_status2_t, pclk_run, ==, 1, 10000))
617210284Sjmallett        {
618210284Sjmallett            cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port);
619210284Sjmallett            return -1;
620210284Sjmallett        }
621210284Sjmallett    }
622210284Sjmallett
623210284Sjmallett    /* Check and make sure PCIe came out of reset. If it doesn't the board
624210284Sjmallett        probably hasn't wired the clocks up and the interface should be
625210284Sjmallett        skipped */
626210284Sjmallett    pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
627210284Sjmallett    if (pescx_ctl_status2.s.pcierst)
628210284Sjmallett    {
629210284Sjmallett        cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
630210284Sjmallett        return -1;
631210284Sjmallett    }
632210284Sjmallett
633210284Sjmallett    /* Check BIST2 status. If any bits are set skip this interface. This
634210284Sjmallett        is an attempt to catch PCIE-813 on pass 1 parts */
635210284Sjmallett    pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));
636210284Sjmallett    if (pescx_bist_status2.u64)
637210284Sjmallett    {
638210284Sjmallett        cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", pcie_port);
639210284Sjmallett        return -1;
640210284Sjmallett    }
641210284Sjmallett
642210284Sjmallett    /* Check BIST status */
643210284Sjmallett    pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));
644210284Sjmallett    if (pescx_bist_status.u64)
645210284Sjmallett        cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pescx_bist_status.u64));
646210284Sjmallett
647210284Sjmallett    /* Initialize the config space CSRs */
648210284Sjmallett    __cvmx_pcie_rc_initialize_config_space(pcie_port);
649210284Sjmallett
650210284Sjmallett    /* Bring the link up */
651215990Sjmallett    if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port))
652210284Sjmallett    {
653215990Sjmallett        cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", pcie_port);
654210284Sjmallett        return -1;
655210284Sjmallett    }
656210284Sjmallett
657210284Sjmallett    /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
658210284Sjmallett    npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL);
659210284Sjmallett    npei_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
660210284Sjmallett    npei_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
661210284Sjmallett    cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);
662210284Sjmallett
663210284Sjmallett    /* Setup Mem access SubDIDs */
664210284Sjmallett    mem_access_subid.u64 = 0;
665210284Sjmallett    mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
666210284Sjmallett    mem_access_subid.s.nmerge = 1;  /* Due to an errata on pass 1 chips, no merging is allowed. */
667210284Sjmallett    mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
668210284Sjmallett    mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
669210284Sjmallett    mem_access_subid.s.nsr = 0;     /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
670210284Sjmallett    mem_access_subid.s.nsw = 0;     /* Enable Snoop for Writes. */
671210284Sjmallett    mem_access_subid.s.ror = 0;     /* Disable Relaxed Ordering for Reads. */
672210284Sjmallett    mem_access_subid.s.row = 0;     /* Disable Relaxed Ordering for Writes. */
673210284Sjmallett    mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
674210284Sjmallett
675210284Sjmallett    /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */
676210284Sjmallett    for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++)
677210284Sjmallett    {
678210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
679210284Sjmallett        mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */
680210284Sjmallett    }
681210284Sjmallett
682210284Sjmallett    /* Disable the peer to peer forwarding register. This must be setup
683210284Sjmallett        by the OS after it enumerates the bus and assigns addresses to the
684210284Sjmallett        PCIe busses */
685210284Sjmallett    for (i=0; i<4; i++)
686210284Sjmallett    {
687210284Sjmallett        cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1);
688210284Sjmallett        cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1);
689210284Sjmallett    }
690210284Sjmallett
691210284Sjmallett    /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
692210284Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
693210284Sjmallett
694215990Sjmallett    /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */
695215990Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
696210284Sjmallett
697215990Sjmallett    bar1_index.u32 = 0;
698215990Sjmallett    bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
699215990Sjmallett    bar1_index.s.ca = 1;       /* Not Cached */
700215990Sjmallett    bar1_index.s.end_swp = 1;  /* Endian Swap mode */
701215990Sjmallett    bar1_index.s.addr_v = 1;   /* Valid entry */
702215990Sjmallett
703215990Sjmallett    base = pcie_port ? 16 : 0;
704215990Sjmallett
705215990Sjmallett    /* Big endian swizzle for 32-bit PEXP_NCB register. */
706215990Sjmallett#ifdef __MIPSEB__
707215990Sjmallett    addr_swizzle = 4;
708215990Sjmallett#else
709215990Sjmallett    addr_swizzle = 0;
710215990Sjmallett#endif
711215990Sjmallett    for (i = 0; i < 16; i++) {
712215990Sjmallett        cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle), bar1_index.u32);
713215990Sjmallett        base++;
714215990Sjmallett        /* 256MB / 16 >> 22 == 4 */
715215990Sjmallett        bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
716215990Sjmallett    }
717215990Sjmallett
718210284Sjmallett    /* Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take precedence
719210284Sjmallett        where they overlap. It also overlaps with the device addresses, so
720210284Sjmallett        make sure the peer to peer forwarding is set right */
721210284Sjmallett    cvmx_write_csr(CVMX_PESCX_P2N_BAR2_START(pcie_port), 0);
722210284Sjmallett
723210284Sjmallett    /* Setup BAR2 attributes */
724210284Sjmallett    /* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */
725210284Sjmallett    /* � PTLP_RO,CTLP_RO should normally be set (except for debug). */
726210284Sjmallett    /* � WAIT_COM=0 will likely work for all applications. */
727210284Sjmallett    /* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */
728210284Sjmallett    if (pcie_port)
729210284Sjmallett    {
730210284Sjmallett        cvmx_npei_ctl_port1_t npei_ctl_port;
731210284Sjmallett        npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT1);
732210284Sjmallett        npei_ctl_port.s.bar2_enb = 1;
733210284Sjmallett        npei_ctl_port.s.bar2_esx = 1;
734210284Sjmallett        npei_ctl_port.s.bar2_cax = 0;
735210284Sjmallett        npei_ctl_port.s.ptlp_ro = 1;
736210284Sjmallett        npei_ctl_port.s.ctlp_ro = 1;
737210284Sjmallett        npei_ctl_port.s.wait_com = 0;
738210284Sjmallett        npei_ctl_port.s.waitl_com = 0;
739210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT1, npei_ctl_port.u64);
740210284Sjmallett    }
741210284Sjmallett    else
742210284Sjmallett    {
743210284Sjmallett        cvmx_npei_ctl_port0_t npei_ctl_port;
744210284Sjmallett        npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT0);
745210284Sjmallett        npei_ctl_port.s.bar2_enb = 1;
746210284Sjmallett        npei_ctl_port.s.bar2_esx = 1;
747210284Sjmallett        npei_ctl_port.s.bar2_cax = 0;
748210284Sjmallett        npei_ctl_port.s.ptlp_ro = 1;
749210284Sjmallett        npei_ctl_port.s.ctlp_ro = 1;
750210284Sjmallett        npei_ctl_port.s.wait_com = 0;
751210284Sjmallett        npei_ctl_port.s.waitl_com = 0;
752210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64);
753210284Sjmallett    }
754210284Sjmallett
755210284Sjmallett    /* Both pass 1 and pass 2 of CN52XX and CN56XX have an errata that causes
756210284Sjmallett        TLP ordering to not be preserved after multiple PCIe port resets. This
757210284Sjmallett        code detects this fault and corrects it by aligning the TLP counters
758210284Sjmallett        properly. Another link reset is then performed. See PCIE-13340 */
759210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) ||
760210284Sjmallett        OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
761210284Sjmallett    {
762210284Sjmallett        cvmx_npei_dbg_data_t dbg_data;
763210284Sjmallett        int old_in_fif_p_count;
764210284Sjmallett        int in_fif_p_count;
765210284Sjmallett        int out_p_count;
766210284Sjmallett        int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1;
767210284Sjmallett        int i;
768210284Sjmallett
769210284Sjmallett        /* Choose a write address of 1MB. It should be harmless as all bars
770210284Sjmallett            haven't been setup */
771210284Sjmallett        uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63);
772210284Sjmallett
773210284Sjmallett        /* Make sure at least in_p_offset have been executed before we try and
774210284Sjmallett            read in_fif_p_count */
775210284Sjmallett        i = in_p_offset;
776210284Sjmallett        while (i--)
777210284Sjmallett        {
778210284Sjmallett            cvmx_write64_uint32(write_address, 0);
779210284Sjmallett            cvmx_wait(10000);
780210284Sjmallett        }
781210284Sjmallett
782210284Sjmallett        /* Read the IN_FIF_P_COUNT from the debug select. IN_FIF_P_COUNT can be
783210284Sjmallett            unstable sometimes so read it twice with a write between the reads.
784210284Sjmallett            This way we can tell the value is good as it will increment by one
785210284Sjmallett            due to the write */
786210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc);
787210284Sjmallett        cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
788210284Sjmallett        do
789210284Sjmallett        {
790210284Sjmallett            dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
791210284Sjmallett            old_in_fif_p_count = dbg_data.s.data & 0xff;
792210284Sjmallett            cvmx_write64_uint32(write_address, 0);
793210284Sjmallett            cvmx_wait(10000);
794210284Sjmallett            dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
795210284Sjmallett            in_fif_p_count = dbg_data.s.data & 0xff;
796210284Sjmallett        } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff));
797210284Sjmallett
798210284Sjmallett        /* Update in_fif_p_count for it's offset with respect to out_p_count */
799210284Sjmallett        in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff;
800210284Sjmallett
801210284Sjmallett        /* Read the OUT_P_COUNT from the debug select */
802210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f);
803210284Sjmallett        cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
804210284Sjmallett        dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
805210284Sjmallett        out_p_count = (dbg_data.s.data>>1) & 0xff;
806210284Sjmallett
807210284Sjmallett        /* Check that the two counters are aligned */
808210284Sjmallett        if (out_p_count != in_fif_p_count)
809210284Sjmallett        {
810210284Sjmallett            cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port);
811210284Sjmallett            while (in_fif_p_count != 0)
812210284Sjmallett            {
813210284Sjmallett                cvmx_write64_uint32(write_address, 0);
814210284Sjmallett                cvmx_wait(10000);
815210284Sjmallett                in_fif_p_count = (in_fif_p_count + 1) & 0xff;
816210284Sjmallett            }
817210284Sjmallett            /* The EBH5200 board swapped the PCIe reset lines on the board. This
818210284Sjmallett                means we must bring both links down and up, which will cause the
819210284Sjmallett                PCIe0 to need alignment again. Lots of messages will be displayed,
820210284Sjmallett                but everything should work */
821210284Sjmallett            if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) &&
822210284Sjmallett                (pcie_port == 1))
823210284Sjmallett                cvmx_pcie_rc_initialize(0);
824210284Sjmallett            /* Rety bringing this port up */
825210284Sjmallett            goto retry;
826210284Sjmallett        }
827210284Sjmallett    }
828210284Sjmallett
829210284Sjmallett    /* Display the link status */
830210284Sjmallett    pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
831210284Sjmallett    cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw);
832210284Sjmallett
833210284Sjmallett    return 0;
834210284Sjmallett}
835210284Sjmallett
836210284Sjmallett/**
837215990Sjmallett * @INTERNAL
838215990Sjmallett * Initialize a host mode PCIe gen 2 link. This function takes a PCIe
839215990Sjmallett * port from reset to a link up state. Software can then begin
840215990Sjmallett * configuring the rest of the link.
841215990Sjmallett *
842215990Sjmallett * @param pcie_port PCIe port to initialize
843215990Sjmallett *
844215990Sjmallett * @return Zero on success
845215990Sjmallett */
846215990Sjmallettstatic int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port)
847215990Sjmallett{
848215990Sjmallett    uint64_t start_cycle;
849215990Sjmallett    cvmx_pemx_ctl_status_t pem_ctl_status;
850215990Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
851215990Sjmallett    cvmx_pciercx_cfg448_t pciercx_cfg448;
852215990Sjmallett
853215990Sjmallett    /* Bring up the link */
854215990Sjmallett    pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
855215990Sjmallett    pem_ctl_status.s.lnk_enb = 1;
856215990Sjmallett    cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);
857215990Sjmallett
858215990Sjmallett    /* Wait for the link to come up */
859215990Sjmallett    start_cycle = cvmx_get_cycle();
860215990Sjmallett    do
861215990Sjmallett    {
862215990Sjmallett        if (cvmx_get_cycle() - start_cycle > cvmx_clock_get_rate(CVMX_CLOCK_CORE))
863215990Sjmallett            return -1;
864215990Sjmallett        cvmx_wait(10000);
865215990Sjmallett        pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
866232812Sjmallett    } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1));
867215990Sjmallett
868215990Sjmallett    /* Update the Replay Time Limit. Empirically, some PCIe devices take a
869215990Sjmallett        little longer to respond than expected under load. As a workaround for
870215990Sjmallett        this we configure the Replay Time Limit to the value expected for a 512
871215990Sjmallett        byte MPS instead of our actual 256 byte MPS. The numbers below are
872215990Sjmallett        directly from the PCIe spec table 3-4 */
873215990Sjmallett    pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
874215990Sjmallett    switch (pciercx_cfg032.s.nlw)
875215990Sjmallett    {
876215990Sjmallett        case 1: /* 1 lane */
877215990Sjmallett            pciercx_cfg448.s.rtl = 1677;
878215990Sjmallett            break;
879215990Sjmallett        case 2: /* 2 lanes */
880215990Sjmallett            pciercx_cfg448.s.rtl = 867;
881215990Sjmallett            break;
882215990Sjmallett        case 4: /* 4 lanes */
883215990Sjmallett            pciercx_cfg448.s.rtl = 462;
884215990Sjmallett            break;
885215990Sjmallett        case 8: /* 8 lanes */
886215990Sjmallett            pciercx_cfg448.s.rtl = 258;
887215990Sjmallett            break;
888215990Sjmallett    }
889215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
890215990Sjmallett
891215990Sjmallett    return 0;
892215990Sjmallett}
893215990Sjmallett
894215990Sjmallett
895215990Sjmallett/**
896215990Sjmallett * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate
897215990Sjmallett * the bus.
898215990Sjmallett *
899215990Sjmallett * @param pcie_port PCIe port to initialize
900215990Sjmallett *
901215990Sjmallett * @return Zero on success
902215990Sjmallett */
903215990Sjmallettstatic int __cvmx_pcie_rc_initialize_gen2(int pcie_port)
904215990Sjmallett{
905215990Sjmallett    int i;
906215990Sjmallett    cvmx_ciu_soft_prst_t ciu_soft_prst;
907215990Sjmallett    cvmx_mio_rst_ctlx_t mio_rst_ctl;
908215990Sjmallett    cvmx_pemx_bar_ctl_t pemx_bar_ctl;
909215990Sjmallett    cvmx_pemx_ctl_status_t pemx_ctl_status;
910215990Sjmallett    cvmx_pemx_bist_status_t pemx_bist_status;
911215990Sjmallett    cvmx_pemx_bist_status2_t pemx_bist_status2;
912215990Sjmallett    cvmx_pciercx_cfg032_t pciercx_cfg032;
913215990Sjmallett    cvmx_pciercx_cfg515_t pciercx_cfg515;
914215990Sjmallett    cvmx_sli_ctl_portx_t sli_ctl_portx;
915215990Sjmallett    cvmx_sli_mem_access_ctl_t sli_mem_access_ctl;
916215990Sjmallett    cvmx_sli_mem_access_subidx_t mem_access_subid;
917215990Sjmallett    cvmx_pemx_bar1_indexx_t bar1_index;
918232812Sjmallett    int ep_mode;
919215990Sjmallett
920232812Sjmallett    /* Make sure this interface is PCIe */
921232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
922215990Sjmallett    {
923232812Sjmallett        /* Requires reading the MIO_QLMX_CFG register to figure
924232812Sjmallett           out the port type. */
925232812Sjmallett        int qlm = pcie_port;
926232812Sjmallett        int status;
927232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
928232812Sjmallett            qlm = 3 - (pcie_port * 2);
929232812Sjmallett        else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
930232812Sjmallett        {
931232812Sjmallett            cvmx_mio_qlmx_cfg_t qlm_cfg;
932232812Sjmallett            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1));
933232812Sjmallett            if (qlm_cfg.s.qlm_cfg == 1)
934232812Sjmallett                qlm = 1;
935232812Sjmallett        }
936232812Sjmallett        /* PCIe is allowed only in QLM1, 1 PCIe port in x2 or
937232812Sjmallett           2 PCIe ports in x1 */
938232812Sjmallett        else if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
939232812Sjmallett            qlm = 1;
940232812Sjmallett        status = cvmx_qlm_get_status(qlm);
941232812Sjmallett        if (status == 4 || status == 5)
942232812Sjmallett        {
943232812Sjmallett            cvmx_dprintf("PCIe: Port %d is SRIO, skipping.\n", pcie_port);
944232812Sjmallett            return -1;
945232812Sjmallett        }
946232812Sjmallett        if (status == 1)
947232812Sjmallett        {
948232812Sjmallett            cvmx_dprintf("PCIe: Port %d is SGMII, skipping.\n", pcie_port);
949232812Sjmallett            return -1;
950232812Sjmallett        }
951232812Sjmallett        if (status == 2)
952232812Sjmallett        {
953232812Sjmallett            cvmx_dprintf("PCIe: Port %d is XAUI, skipping.\n", pcie_port);
954232812Sjmallett            return -1;
955232812Sjmallett        }
956232812Sjmallett        if (status == -1)
957232812Sjmallett        {
958232812Sjmallett            cvmx_dprintf("PCIe: Port %d is unknown, skipping.\n", pcie_port);
959232812Sjmallett            return -1;
960232812Sjmallett        }
961215990Sjmallett    }
962215990Sjmallett
963232812Sjmallett#if 0
964232812Sjmallett    /* This code is so that the PCIe analyzer is able to see 63XX traffic */
965232812Sjmallett    cvmx_dprintf("PCIE : init for pcie analyzer.\n");
966232812Sjmallett    cvmx_helper_qlm_jtag_init();
967232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
968232812Sjmallett    cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
969232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
970232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
971232812Sjmallett    cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
972232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
973232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
974232812Sjmallett    cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
975232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
976232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
977232812Sjmallett    cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
978232812Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
979232812Sjmallett    cvmx_helper_qlm_jtag_update(pcie_port);
980232812Sjmallett#endif
981232812Sjmallett
982215990Sjmallett    /* Make sure we aren't trying to setup a target mode interface in host mode */
983215990Sjmallett    mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
984232812Sjmallett    ep_mode = (OCTEON_IS_MODEL(OCTEON_CN61XX || OCTEON_IS_MODEL(OCTEON_CNF71XX)) ? (mio_rst_ctl.s.prtmode != 1) : (!mio_rst_ctl.s.host_mode));
985232812Sjmallett    if (ep_mode)
986215990Sjmallett    {
987215990Sjmallett        cvmx_dprintf("PCIe: Port %d in endpoint mode.\n", pcie_port);
988215990Sjmallett        return -1;
989215990Sjmallett    }
990215990Sjmallett
991215990Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
992215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
993215990Sjmallett    {
994215990Sjmallett        if (pcie_port)
995215990Sjmallett        {
996215990Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
997215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
998215990Sjmallett            ciu_qlm.s.txbypass = 1;
999215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1000215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1001215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
1002215990Sjmallett        }
1003215990Sjmallett        else
1004215990Sjmallett        {
1005215990Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
1006215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
1007215990Sjmallett            ciu_qlm.s.txbypass = 1;
1008215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1009215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1010215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
1011215990Sjmallett        }
1012215990Sjmallett    }
1013215990Sjmallett    /* Bring the PCIe out of reset */
1014215990Sjmallett    if (pcie_port)
1015215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
1016215990Sjmallett    else
1017215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
1018215990Sjmallett    /* After a chip reset the PCIe will also be in reset. If it isn't,
1019215990Sjmallett        most likely someone is trying to init it again without a proper
1020215990Sjmallett        PCIe reset */
1021215990Sjmallett    if (ciu_soft_prst.s.soft_prst == 0)
1022215990Sjmallett    {
1023215990Sjmallett        /* Reset the port */
1024215990Sjmallett        ciu_soft_prst.s.soft_prst = 1;
1025215990Sjmallett        if (pcie_port)
1026215990Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
1027215990Sjmallett        else
1028215990Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
1029215990Sjmallett        /* Wait until pcie resets the ports. */
1030215990Sjmallett        cvmx_wait_usec(2000);
1031215990Sjmallett    }
1032215990Sjmallett    if (pcie_port)
1033215990Sjmallett    {
1034215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
1035215990Sjmallett        ciu_soft_prst.s.soft_prst = 0;
1036215990Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
1037215990Sjmallett    }
1038215990Sjmallett    else
1039215990Sjmallett    {
1040215990Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
1041215990Sjmallett        ciu_soft_prst.s.soft_prst = 0;
1042215990Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
1043215990Sjmallett    }
1044215990Sjmallett
1045215990Sjmallett    /* Wait for PCIe reset to complete */
1046215990Sjmallett    cvmx_wait_usec(1000);
1047215990Sjmallett
1048215990Sjmallett    /* Check and make sure PCIe came out of reset. If it doesn't the board
1049215990Sjmallett        probably hasn't wired the clocks up and the interface should be
1050215990Sjmallett        skipped */
1051232812Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), cvmx_mio_rst_ctlx_t, rst_done, ==, 1, 10000))
1052215990Sjmallett    {
1053215990Sjmallett        cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
1054215990Sjmallett        return -1;
1055215990Sjmallett    }
1056215990Sjmallett
1057215990Sjmallett    /* Check BIST status */
1058215990Sjmallett    pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port));
1059215990Sjmallett    if (pemx_bist_status.u64)
1060215990Sjmallett        cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64));
1061215990Sjmallett    pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port));
1062232812Sjmallett    /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */
1063232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
1064232812Sjmallett        pemx_bist_status2.u64 &= ~0x3full;
1065215990Sjmallett    if (pemx_bist_status2.u64)
1066215990Sjmallett        cvmx_dprintf("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64));
1067215990Sjmallett
1068215990Sjmallett    /* Initialize the config space CSRs */
1069215990Sjmallett    __cvmx_pcie_rc_initialize_config_space(pcie_port);
1070215990Sjmallett
1071215990Sjmallett    /* Enable gen2 speed selection */
1072215990Sjmallett    pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port));
1073215990Sjmallett    pciercx_cfg515.s.dsc = 1;
1074215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32);
1075215990Sjmallett
1076215990Sjmallett    /* Bring the link up */
1077215990Sjmallett    if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port))
1078215990Sjmallett    {
1079215990Sjmallett        /* Some gen1 devices don't handle the gen 2 training correctly. Disable
1080215990Sjmallett            gen2 and try again with only gen1 */
1081215990Sjmallett        cvmx_pciercx_cfg031_t pciercx_cfg031;
1082215990Sjmallett        pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));
1083215990Sjmallett        pciercx_cfg031.s.mls = 1;
1084232812Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32);
1085215990Sjmallett        if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port))
1086215990Sjmallett        {
1087215990Sjmallett            cvmx_dprintf("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port);
1088215990Sjmallett            return -1;
1089215990Sjmallett        }
1090215990Sjmallett    }
1091215990Sjmallett
1092215990Sjmallett    /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
1093215990Sjmallett    sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL);
1094215990Sjmallett    sli_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
1095215990Sjmallett    sli_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
1096215990Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);
1097215990Sjmallett
1098215990Sjmallett    /* Setup Mem access SubDIDs */
1099215990Sjmallett    mem_access_subid.u64 = 0;
1100215990Sjmallett    mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1101215990Sjmallett    mem_access_subid.s.nmerge = 0;  /* Allow merging as it works on CN6XXX. */
1102215990Sjmallett    mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
1103215990Sjmallett    mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
1104215990Sjmallett    mem_access_subid.s.wtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1105215990Sjmallett    mem_access_subid.s.rtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1106232812Sjmallett    /* PCIe Adddress Bits <63:34>. */
1107232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
1108232812Sjmallett        mem_access_subid.cn68xx.ba = 0;
1109232812Sjmallett    else
1110232812Sjmallett        mem_access_subid.cn63xx.ba = 0;
1111215990Sjmallett
1112215990Sjmallett    /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */
1113215990Sjmallett    for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++)
1114215990Sjmallett    {
1115215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
1116232812Sjmallett        /* Set each SUBID to extend the addressable range */
1117232812Sjmallett	__cvmx_increment_ba(&mem_access_subid);
1118215990Sjmallett    }
1119215990Sjmallett
1120232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN61XX))
1121215990Sjmallett    {
1122232812Sjmallett        /* Disable the peer to peer forwarding register. This must be setup
1123232812Sjmallett            by the OS after it enumerates the bus and assigns addresses to the
1124232812Sjmallett            PCIe busses */
1125232812Sjmallett        for (i=0; i<4; i++)
1126232812Sjmallett        {
1127232812Sjmallett            cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1);
1128232812Sjmallett            cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1);
1129232812Sjmallett        }
1130215990Sjmallett    }
1131215990Sjmallett
1132215990Sjmallett    /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
1133215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0);
1134215990Sjmallett
1135215990Sjmallett    /* Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take precedence
1136215990Sjmallett        where they overlap. It also overlaps with the device addresses, so
1137215990Sjmallett        make sure the peer to peer forwarding is set right */
1138215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0);
1139215990Sjmallett
1140215990Sjmallett    /* Setup BAR2 attributes */
1141215990Sjmallett    /* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */
1142215990Sjmallett    /* � PTLP_RO,CTLP_RO should normally be set (except for debug). */
1143215990Sjmallett    /* � WAIT_COM=0 will likely work for all applications. */
1144215990Sjmallett    /* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */
1145215990Sjmallett    pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port));
1146215990Sjmallett    pemx_bar_ctl.s.bar1_siz = 3;  /* 256MB BAR1*/
1147215990Sjmallett    pemx_bar_ctl.s.bar2_enb = 1;
1148215990Sjmallett    pemx_bar_ctl.s.bar2_esx = 1;
1149215990Sjmallett    pemx_bar_ctl.s.bar2_cax = 0;
1150215990Sjmallett    cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64);
1151215990Sjmallett    sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port));
1152215990Sjmallett    sli_ctl_portx.s.ptlp_ro = 1;
1153215990Sjmallett    sli_ctl_portx.s.ctlp_ro = 1;
1154215990Sjmallett    sli_ctl_portx.s.wait_com = 0;
1155215990Sjmallett    sli_ctl_portx.s.waitl_com = 0;
1156215990Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64);
1157215990Sjmallett
1158215990Sjmallett    /* BAR1 follows BAR2 */
1159215990Sjmallett    cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
1160215990Sjmallett
1161215990Sjmallett    bar1_index.u64 = 0;
1162215990Sjmallett    bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
1163215990Sjmallett    bar1_index.s.ca = 1;       /* Not Cached */
1164215990Sjmallett    bar1_index.s.end_swp = 1;  /* Endian Swap mode */
1165215990Sjmallett    bar1_index.s.addr_v = 1;   /* Valid entry */
1166215990Sjmallett
1167215990Sjmallett    for (i = 0; i < 16; i++) {
1168215990Sjmallett        cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64);
1169215990Sjmallett        /* 256MB / 16 >> 22 == 4 */
1170215990Sjmallett        bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
1171215990Sjmallett    }
1172215990Sjmallett
1173215990Sjmallett    /* Allow config retries for 250ms. Count is based off the 5Ghz SERDES
1174215990Sjmallett        clock */
1175215990Sjmallett    pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
1176215990Sjmallett    pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000;
1177215990Sjmallett    cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64);
1178215990Sjmallett
1179215990Sjmallett    /* Display the link status */
1180215990Sjmallett    pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
1181215990Sjmallett    cvmx_dprintf("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);
1182215990Sjmallett
1183215990Sjmallett    return 0;
1184215990Sjmallett}
1185215990Sjmallett
1186215990Sjmallett/**
1187215990Sjmallett * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus.
1188215990Sjmallett *
1189215990Sjmallett * @param pcie_port PCIe port to initialize
1190215990Sjmallett *
1191215990Sjmallett * @return Zero on success
1192215990Sjmallett */
1193215990Sjmallettint cvmx_pcie_rc_initialize(int pcie_port)
1194215990Sjmallett{
1195215990Sjmallett    int result;
1196215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1197215990Sjmallett        result = __cvmx_pcie_rc_initialize_gen1(pcie_port);
1198215990Sjmallett    else
1199215990Sjmallett        result = __cvmx_pcie_rc_initialize_gen2(pcie_port);
1200232816Sjmallett#if (!defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)) || defined(CONFIG_CAVIUM_DECODE_RSL)
1201215990Sjmallett    if (result == 0)
1202215990Sjmallett        cvmx_error_enable_group(CVMX_ERROR_GROUP_PCI, pcie_port);
1203215990Sjmallett#endif
1204215990Sjmallett    return result;
1205215990Sjmallett}
1206215990Sjmallett
1207215990Sjmallett
1208215990Sjmallett/**
1209210284Sjmallett * Shutdown a PCIe port and put it in reset
1210210284Sjmallett *
1211210284Sjmallett * @param pcie_port PCIe port to shutdown
1212210284Sjmallett *
1213210284Sjmallett * @return Zero on success
1214210284Sjmallett */
1215210284Sjmallettint cvmx_pcie_rc_shutdown(int pcie_port)
1216210284Sjmallett{
1217232816Sjmallett#if (!defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)) || defined(CONFIG_CAVIUM_DECODE_RSL)
1218215990Sjmallett    cvmx_error_disable_group(CVMX_ERROR_GROUP_PCI, pcie_port);
1219215990Sjmallett#endif
1220210284Sjmallett    /* Wait for all pending operations to complete */
1221215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1222215990Sjmallett    {
1223215990Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CPL_LUT_VALID(pcie_port), cvmx_pescx_cpl_lut_valid_t, tag, ==, 0, 2000))
1224215990Sjmallett            cvmx_dprintf("PCIe: Port %d shutdown timeout\n", pcie_port);
1225215990Sjmallett    }
1226215990Sjmallett    else
1227215990Sjmallett    {
1228215990Sjmallett        if (CVMX_WAIT_FOR_FIELD64(CVMX_PEMX_CPL_LUT_VALID(pcie_port), cvmx_pemx_cpl_lut_valid_t, tag, ==, 0, 2000))
1229215990Sjmallett            cvmx_dprintf("PCIe: Port %d shutdown timeout\n", pcie_port);
1230215990Sjmallett    }
1231210284Sjmallett
1232210284Sjmallett    /* Force reset */
1233210284Sjmallett    if (pcie_port)
1234210284Sjmallett    {
1235210284Sjmallett        cvmx_ciu_soft_prst_t ciu_soft_prst;
1236210284Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
1237210284Sjmallett        ciu_soft_prst.s.soft_prst = 1;
1238210284Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
1239210284Sjmallett    }
1240210284Sjmallett    else
1241210284Sjmallett    {
1242210284Sjmallett        cvmx_ciu_soft_prst_t ciu_soft_prst;
1243210284Sjmallett        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
1244210284Sjmallett        ciu_soft_prst.s.soft_prst = 1;
1245210284Sjmallett        cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
1246210284Sjmallett    }
1247210284Sjmallett    return 0;
1248210284Sjmallett}
1249210284Sjmallett
1250210284Sjmallett
1251210284Sjmallett/**
1252210284Sjmallett * @INTERNAL
1253210284Sjmallett * Build a PCIe config space request address for a device
1254210284Sjmallett *
1255210284Sjmallett * @param pcie_port PCIe port to access
1256210284Sjmallett * @param bus       Sub bus
1257210284Sjmallett * @param dev       Device ID
1258210284Sjmallett * @param fn        Device sub function
1259210284Sjmallett * @param reg       Register to access
1260210284Sjmallett *
1261210284Sjmallett * @return 64bit Octeon IO address
1262210284Sjmallett */
1263210284Sjmallettstatic inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, int dev, int fn, int reg)
1264210284Sjmallett{
1265210284Sjmallett    cvmx_pcie_address_t pcie_addr;
1266210284Sjmallett    cvmx_pciercx_cfg006_t pciercx_cfg006;
1267210284Sjmallett
1268210284Sjmallett    pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port));
1269210284Sjmallett    if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0))
1270210284Sjmallett        return 0;
1271210284Sjmallett
1272210284Sjmallett    pcie_addr.u64 = 0;
1273210284Sjmallett    pcie_addr.config.upper = 2;
1274210284Sjmallett    pcie_addr.config.io = 1;
1275210284Sjmallett    pcie_addr.config.did = 3;
1276210284Sjmallett    pcie_addr.config.subdid = 1;
1277210284Sjmallett    pcie_addr.config.es = 1;
1278210284Sjmallett    pcie_addr.config.port = pcie_port;
1279210284Sjmallett    pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum);
1280210284Sjmallett    pcie_addr.config.bus = bus;
1281210284Sjmallett    pcie_addr.config.dev = dev;
1282210284Sjmallett    pcie_addr.config.func = fn;
1283210284Sjmallett    pcie_addr.config.reg = reg;
1284210284Sjmallett    return pcie_addr.u64;
1285210284Sjmallett}
1286210284Sjmallett
1287210284Sjmallett
1288210284Sjmallett/**
1289210284Sjmallett * Read 8bits from a Device's config space
1290210284Sjmallett *
1291210284Sjmallett * @param pcie_port PCIe port the device is on
1292210284Sjmallett * @param bus       Sub bus
1293210284Sjmallett * @param dev       Device ID
1294210284Sjmallett * @param fn        Device sub function
1295210284Sjmallett * @param reg       Register to access
1296210284Sjmallett *
1297210284Sjmallett * @return Result of the read
1298210284Sjmallett */
1299210284Sjmallettuint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg)
1300210284Sjmallett{
1301210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1302210284Sjmallett    if (address)
1303210284Sjmallett        return cvmx_read64_uint8(address);
1304210284Sjmallett    else
1305210284Sjmallett        return 0xff;
1306210284Sjmallett}
1307210284Sjmallett
1308210284Sjmallett
1309210284Sjmallett/**
1310210284Sjmallett * Read 16bits from a Device's config space
1311210284Sjmallett *
1312210284Sjmallett * @param pcie_port PCIe port the device is on
1313210284Sjmallett * @param bus       Sub bus
1314210284Sjmallett * @param dev       Device ID
1315210284Sjmallett * @param fn        Device sub function
1316210284Sjmallett * @param reg       Register to access
1317210284Sjmallett *
1318210284Sjmallett * @return Result of the read
1319210284Sjmallett */
1320210284Sjmallettuint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg)
1321210284Sjmallett{
1322210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1323210284Sjmallett    if (address)
1324210284Sjmallett        return cvmx_le16_to_cpu(cvmx_read64_uint16(address));
1325210284Sjmallett    else
1326210284Sjmallett        return 0xffff;
1327210284Sjmallett}
1328210284Sjmallett
1329210284Sjmallett
1330210284Sjmallett/**
1331210284Sjmallett * Read 32bits from a Device's config space
1332210284Sjmallett *
1333210284Sjmallett * @param pcie_port PCIe port the device is on
1334210284Sjmallett * @param bus       Sub bus
1335210284Sjmallett * @param dev       Device ID
1336210284Sjmallett * @param fn        Device sub function
1337210284Sjmallett * @param reg       Register to access
1338210284Sjmallett *
1339210284Sjmallett * @return Result of the read
1340210284Sjmallett */
1341210284Sjmallettuint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg)
1342210284Sjmallett{
1343250428Simp    uint64_t address;
1344250428Simp
1345250428Simp    address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1346210284Sjmallett    if (address)
1347210284Sjmallett        return cvmx_le32_to_cpu(cvmx_read64_uint32(address));
1348210284Sjmallett    else
1349210284Sjmallett        return 0xffffffff;
1350210284Sjmallett}
1351210284Sjmallett
1352210284Sjmallett
1353210284Sjmallett/**
1354210284Sjmallett * Write 8bits to a Device's config space
1355210284Sjmallett *
1356210284Sjmallett * @param pcie_port PCIe port the device is on
1357210284Sjmallett * @param bus       Sub bus
1358210284Sjmallett * @param dev       Device ID
1359210284Sjmallett * @param fn        Device sub function
1360210284Sjmallett * @param reg       Register to access
1361210284Sjmallett * @param val       Value to write
1362210284Sjmallett */
1363210284Sjmallettvoid cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, uint8_t val)
1364210284Sjmallett{
1365210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1366210284Sjmallett    if (address)
1367210284Sjmallett        cvmx_write64_uint8(address, val);
1368210284Sjmallett}
1369210284Sjmallett
1370210284Sjmallett
1371210284Sjmallett/**
1372210284Sjmallett * Write 16bits to a Device's config space
1373210284Sjmallett *
1374210284Sjmallett * @param pcie_port PCIe port the device is on
1375210284Sjmallett * @param bus       Sub bus
1376210284Sjmallett * @param dev       Device ID
1377210284Sjmallett * @param fn        Device sub function
1378210284Sjmallett * @param reg       Register to access
1379210284Sjmallett * @param val       Value to write
1380210284Sjmallett */
1381210284Sjmallettvoid cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, uint16_t val)
1382210284Sjmallett{
1383210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1384210284Sjmallett    if (address)
1385210284Sjmallett        cvmx_write64_uint16(address, cvmx_cpu_to_le16(val));
1386210284Sjmallett}
1387210284Sjmallett
1388210284Sjmallett
1389210284Sjmallett/**
1390210284Sjmallett * Write 32bits to a Device's config space
1391210284Sjmallett *
1392210284Sjmallett * @param pcie_port PCIe port the device is on
1393210284Sjmallett * @param bus       Sub bus
1394210284Sjmallett * @param dev       Device ID
1395210284Sjmallett * @param fn        Device sub function
1396210284Sjmallett * @param reg       Register to access
1397210284Sjmallett * @param val       Value to write
1398210284Sjmallett */
1399210284Sjmallettvoid cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, uint32_t val)
1400210284Sjmallett{
1401210284Sjmallett    uint64_t address = __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
1402210284Sjmallett    if (address)
1403210284Sjmallett        cvmx_write64_uint32(address, cvmx_cpu_to_le32(val));
1404210284Sjmallett}
1405210284Sjmallett
1406210284Sjmallett
1407210284Sjmallett/**
1408210284Sjmallett * Read a PCIe config space register indirectly. This is used for
1409210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
1410210284Sjmallett *
1411210284Sjmallett * @param pcie_port  PCIe port to read from
1412210284Sjmallett * @param cfg_offset Address to read
1413210284Sjmallett *
1414210284Sjmallett * @return Value read
1415210284Sjmallett */
1416210284Sjmallettuint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)
1417210284Sjmallett{
1418215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1419215990Sjmallett    {
1420215990Sjmallett        cvmx_pescx_cfg_rd_t pescx_cfg_rd;
1421215990Sjmallett        pescx_cfg_rd.u64 = 0;
1422215990Sjmallett        pescx_cfg_rd.s.addr = cfg_offset;
1423215990Sjmallett        cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64);
1424215990Sjmallett        pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port));
1425215990Sjmallett        return pescx_cfg_rd.s.data;
1426215990Sjmallett    }
1427215990Sjmallett    else
1428215990Sjmallett    {
1429215990Sjmallett        cvmx_pemx_cfg_rd_t pemx_cfg_rd;
1430215990Sjmallett        pemx_cfg_rd.u64 = 0;
1431215990Sjmallett        pemx_cfg_rd.s.addr = cfg_offset;
1432215990Sjmallett        cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64);
1433215990Sjmallett        pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port));
1434215990Sjmallett        return pemx_cfg_rd.s.data;
1435215990Sjmallett    }
1436210284Sjmallett}
1437210284Sjmallett
1438210284Sjmallett
1439210284Sjmallett/**
1440210284Sjmallett * Write a PCIe config space register indirectly. This is used for
1441210284Sjmallett * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
1442210284Sjmallett *
1443210284Sjmallett * @param pcie_port  PCIe port to write to
1444210284Sjmallett * @param cfg_offset Address to write
1445210284Sjmallett * @param val        Value to write
1446210284Sjmallett */
1447210284Sjmallettvoid cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val)
1448210284Sjmallett{
1449215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1450215990Sjmallett    {
1451215990Sjmallett        cvmx_pescx_cfg_wr_t pescx_cfg_wr;
1452215990Sjmallett        pescx_cfg_wr.u64 = 0;
1453215990Sjmallett        pescx_cfg_wr.s.addr = cfg_offset;
1454215990Sjmallett        pescx_cfg_wr.s.data = val;
1455215990Sjmallett        cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64);
1456215990Sjmallett    }
1457215990Sjmallett    else
1458215990Sjmallett    {
1459215990Sjmallett        cvmx_pemx_cfg_wr_t pemx_cfg_wr;
1460215990Sjmallett        pemx_cfg_wr.u64 = 0;
1461215990Sjmallett        pemx_cfg_wr.s.addr = cfg_offset;
1462215990Sjmallett        pemx_cfg_wr.s.data = val;
1463215990Sjmallett        cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64);
1464215990Sjmallett    }
1465210284Sjmallett}
1466210284Sjmallett
1467210284Sjmallett
1468210284Sjmallett/**
1469210284Sjmallett * Initialize a PCIe port for use in target(EP) mode.
1470210284Sjmallett *
1471215990Sjmallett * @param pcie_port PCIe port to initialize
1472215990Sjmallett *
1473210284Sjmallett * @return Zero on success
1474210284Sjmallett */
1475215990Sjmallettint cvmx_pcie_ep_initialize(int pcie_port)
1476210284Sjmallett{
1477215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1478215990Sjmallett    {
1479215990Sjmallett        cvmx_npei_ctl_status_t npei_ctl_status;
1480215990Sjmallett        npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
1481215990Sjmallett        if (npei_ctl_status.s.host_mode)
1482215990Sjmallett            return -1;
1483215990Sjmallett    }
1484215990Sjmallett    else
1485215990Sjmallett    {
1486215990Sjmallett        cvmx_mio_rst_ctlx_t mio_rst_ctl;
1487232812Sjmallett        int ep_mode;
1488215990Sjmallett        mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
1489232812Sjmallett        ep_mode = (OCTEON_IS_MODEL(OCTEON_CN61XX) ? (mio_rst_ctl.s.prtmode != 0) : mio_rst_ctl.s.host_mode);
1490232812Sjmallett        if (ep_mode)
1491215990Sjmallett            return -1;
1492215990Sjmallett    }
1493210284Sjmallett
1494215990Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
1495215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
1496215990Sjmallett    {
1497215990Sjmallett        if (pcie_port)
1498215990Sjmallett        {
1499215990Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
1500215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
1501215990Sjmallett            ciu_qlm.s.txbypass = 1;
1502215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1503215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1504215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
1505215990Sjmallett        }
1506215990Sjmallett        else
1507215990Sjmallett        {
1508215990Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
1509215990Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
1510215990Sjmallett            ciu_qlm.s.txbypass = 1;
1511215990Sjmallett            ciu_qlm.s.txdeemph = 5;
1512215990Sjmallett            ciu_qlm.s.txmargin = 0x17;
1513215990Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
1514215990Sjmallett        }
1515215990Sjmallett    }
1516210284Sjmallett
1517210284Sjmallett    /* Enable bus master and memory */
1518215990Sjmallett    cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIEEPX_CFG001(pcie_port), 0x6);
1519210284Sjmallett
1520210284Sjmallett    /* Max Payload Size (PCIE*_CFG030[MPS]) */
1521210284Sjmallett    /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
1522210284Sjmallett    /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
1523210284Sjmallett    /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
1524210284Sjmallett    {
1525215990Sjmallett        cvmx_pcieepx_cfg030_t pcieepx_cfg030;
1526215990Sjmallett        pcieepx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port));
1527215990Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
1528215990Sjmallett        {
1529215990Sjmallett            pcieepx_cfg030.s.mps = MPS_CN5XXX;
1530215990Sjmallett            pcieepx_cfg030.s.mrrs = MRRS_CN5XXX;
1531215990Sjmallett        }
1532215990Sjmallett        else
1533215990Sjmallett        {
1534215990Sjmallett            pcieepx_cfg030.s.mps = MPS_CN6XXX;
1535215990Sjmallett            pcieepx_cfg030.s.mrrs = MRRS_CN6XXX;
1536215990Sjmallett        }
1537215990Sjmallett        pcieepx_cfg030.s.ro_en = 1; /* Enable relaxed ordering. */
1538215990Sjmallett        pcieepx_cfg030.s.ns_en = 1; /* Enable no snoop. */
1539215990Sjmallett        pcieepx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */
1540215990Sjmallett        pcieepx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */
1541215990Sjmallett        pcieepx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */
1542215990Sjmallett        pcieepx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */
1543215990Sjmallett        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port), pcieepx_cfg030.u32);
1544210284Sjmallett    }
1545210284Sjmallett
1546215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1547210284Sjmallett    {
1548215990Sjmallett        /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */
1549215990Sjmallett        /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
1550210284Sjmallett        cvmx_npei_ctl_status2_t npei_ctl_status2;
1551210284Sjmallett        npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
1552215990Sjmallett        npei_ctl_status2.s.mps = MPS_CN5XXX; /* Max payload size = 128 bytes (Limit of most PCs) */
1553215990Sjmallett        npei_ctl_status2.s.mrrs = MRRS_CN5XXX; /* Max read request size = 128 bytes for best Octeon DMA performance */
1554210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
1555210284Sjmallett    }
1556215990Sjmallett    else
1557215990Sjmallett    {
1558215990Sjmallett        /* Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match PCIE*_CFG030[MPS] */
1559215990Sjmallett        /* Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not exceed PCIE*_CFG030[MRRS] */
1560215990Sjmallett        cvmx_dpi_sli_prtx_cfg_t prt_cfg;
1561215990Sjmallett        cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
1562215990Sjmallett        prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port));
1563215990Sjmallett        prt_cfg.s.mps = MPS_CN6XXX;
1564215990Sjmallett        prt_cfg.s.mrrs = MRRS_CN6XXX;
1565232812Sjmallett        /* Max outstanding load request. */
1566232812Sjmallett        prt_cfg.s.molr = 32;
1567215990Sjmallett        cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);
1568210284Sjmallett
1569215990Sjmallett        sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));
1570215990Sjmallett        sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX;
1571215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);
1572215990Sjmallett    }
1573215990Sjmallett
1574210284Sjmallett    /* Setup Mem access SubDID 12 to access Host memory */
1575215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1576210284Sjmallett    {
1577210284Sjmallett        cvmx_npei_mem_access_subidx_t mem_access_subid;
1578210284Sjmallett        mem_access_subid.u64 = 0;
1579210284Sjmallett        mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1580215990Sjmallett        mem_access_subid.s.nmerge = 1;  /* Merging is not allowed in this window. */
1581210284Sjmallett        mem_access_subid.s.esr = 0;     /* Endian-swap for Reads. */
1582210284Sjmallett        mem_access_subid.s.esw = 0;     /* Endian-swap for Writes. */
1583210284Sjmallett        mem_access_subid.s.nsr = 0;     /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
1584210284Sjmallett        mem_access_subid.s.nsw = 0;     /* Enable Snoop for Writes. */
1585210284Sjmallett        mem_access_subid.s.ror = 0;     /* Disable Relaxed Ordering for Reads. */
1586210284Sjmallett        mem_access_subid.s.row = 0;     /* Disable Relaxed Ordering for Writes. */
1587210284Sjmallett        mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
1588210284Sjmallett        cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(12), mem_access_subid.u64);
1589210284Sjmallett    }
1590215990Sjmallett    else
1591215990Sjmallett    {
1592215990Sjmallett        cvmx_sli_mem_access_subidx_t mem_access_subid;
1593215990Sjmallett        mem_access_subid.u64 = 0;
1594215990Sjmallett        mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
1595215990Sjmallett        mem_access_subid.s.nmerge = 0;  /* Merging is allowed in this window. */
1596215990Sjmallett        mem_access_subid.s.esr = 0;     /* Endian-swap for Reads. */
1597215990Sjmallett        mem_access_subid.s.esw = 0;     /* Endian-swap for Writes. */
1598215990Sjmallett        mem_access_subid.s.wtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1599215990Sjmallett        mem_access_subid.s.rtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
1600232812Sjmallett        /* PCIe Adddress Bits <63:34>. */
1601232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
1602232812Sjmallett            mem_access_subid.cn68xx.ba = 0;
1603232812Sjmallett        else
1604232812Sjmallett            mem_access_subid.cn63xx.ba = 0;
1605215990Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(12 + pcie_port*4), mem_access_subid.u64);
1606215990Sjmallett    }
1607210284Sjmallett    return 0;
1608210284Sjmallett}
1609210284Sjmallett
1610210284Sjmallett
1611210284Sjmallett/**
1612210284Sjmallett * Wait for posted PCIe read/writes to reach the other side of
1613210284Sjmallett * the internal PCIe switch. This will insure that core
1614210284Sjmallett * read/writes are posted before anything after this function
1615210284Sjmallett * is called. This may be necessary when writing to memory that
1616210284Sjmallett * will later be read using the DMA/PKT engines.
1617210284Sjmallett *
1618210284Sjmallett * @param pcie_port PCIe port to wait for
1619210284Sjmallett */
1620210284Sjmallettvoid cvmx_pcie_wait_for_pending(int pcie_port)
1621210284Sjmallett{
1622215990Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_NPEI))
1623215990Sjmallett    {
1624215990Sjmallett        cvmx_npei_data_out_cnt_t npei_data_out_cnt;
1625215990Sjmallett        int a;
1626215990Sjmallett        int b;
1627215990Sjmallett        int c;
1628210284Sjmallett
1629215990Sjmallett        /* See section 9.8, PCIe Core-initiated Requests, in the manual for a
1630215990Sjmallett            description of how this code works */
1631215990Sjmallett        npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT);
1632215990Sjmallett        if (pcie_port)
1633215990Sjmallett        {
1634215990Sjmallett            if (!npei_data_out_cnt.s.p1_fcnt)
1635215990Sjmallett                return;
1636215990Sjmallett            a = npei_data_out_cnt.s.p1_ucnt;
1637215990Sjmallett            b = (a + npei_data_out_cnt.s.p1_fcnt-1) & 0xffff;
1638215990Sjmallett        }
1639215990Sjmallett        else
1640215990Sjmallett        {
1641215990Sjmallett            if (!npei_data_out_cnt.s.p0_fcnt)
1642215990Sjmallett                return;
1643215990Sjmallett            a = npei_data_out_cnt.s.p0_ucnt;
1644215990Sjmallett            b = (a + npei_data_out_cnt.s.p0_fcnt-1) & 0xffff;
1645215990Sjmallett        }
1646215990Sjmallett
1647215990Sjmallett        while (1)
1648215990Sjmallett        {
1649215990Sjmallett            npei_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DATA_OUT_CNT);
1650215990Sjmallett            c = (pcie_port) ? npei_data_out_cnt.s.p1_ucnt : npei_data_out_cnt.s.p0_ucnt;
1651215990Sjmallett            if (a<=b)
1652215990Sjmallett            {
1653215990Sjmallett                if ((c<a) || (c>b))
1654215990Sjmallett                    return;
1655215990Sjmallett            }
1656215990Sjmallett            else
1657215990Sjmallett            {
1658215990Sjmallett                if ((c>b) && (c<a))
1659215990Sjmallett                    return;
1660215990Sjmallett            }
1661215990Sjmallett        }
1662210284Sjmallett    }
1663210284Sjmallett    else
1664210284Sjmallett    {
1665215990Sjmallett        cvmx_sli_data_out_cnt_t sli_data_out_cnt;
1666215990Sjmallett        int a;
1667215990Sjmallett        int b;
1668215990Sjmallett        int c;
1669210284Sjmallett
1670215990Sjmallett        sli_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_SLI_DATA_OUT_CNT);
1671215990Sjmallett        if (pcie_port)
1672210284Sjmallett        {
1673215990Sjmallett            if (!sli_data_out_cnt.s.p1_fcnt)
1674210284Sjmallett                return;
1675215990Sjmallett            a = sli_data_out_cnt.s.p1_ucnt;
1676215990Sjmallett            b = (a + sli_data_out_cnt.s.p1_fcnt-1) & 0xffff;
1677210284Sjmallett        }
1678210284Sjmallett        else
1679210284Sjmallett        {
1680215990Sjmallett            if (!sli_data_out_cnt.s.p0_fcnt)
1681210284Sjmallett                return;
1682215990Sjmallett            a = sli_data_out_cnt.s.p0_ucnt;
1683215990Sjmallett            b = (a + sli_data_out_cnt.s.p0_fcnt-1) & 0xffff;
1684210284Sjmallett        }
1685215990Sjmallett
1686215990Sjmallett        while (1)
1687215990Sjmallett        {
1688215990Sjmallett            sli_data_out_cnt.u64 = cvmx_read_csr(CVMX_PEXP_SLI_DATA_OUT_CNT);
1689215990Sjmallett            c = (pcie_port) ? sli_data_out_cnt.s.p1_ucnt : sli_data_out_cnt.s.p0_ucnt;
1690215990Sjmallett            if (a<=b)
1691215990Sjmallett            {
1692215990Sjmallett                if ((c<a) || (c>b))
1693215990Sjmallett                    return;
1694215990Sjmallett            }
1695215990Sjmallett            else
1696215990Sjmallett            {
1697215990Sjmallett                if ((c>b) && (c<a))
1698215990Sjmallett                    return;
1699215990Sjmallett            }
1700215990Sjmallett        }
1701210284Sjmallett    }
1702210284Sjmallett}
1703