1215976Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215976Sjmallett * reserved.
4215976Sjmallett *
5215976Sjmallett *
6215976Sjmallett * Redistribution and use in source and binary forms, with or without
7215976Sjmallett * modification, are permitted provided that the following conditions are
8215976Sjmallett * met:
9215976Sjmallett *
10215976Sjmallett *   * Redistributions of source code must retain the above copyright
11215976Sjmallett *     notice, this list of conditions and the following disclaimer.
12215976Sjmallett *
13215976Sjmallett *   * Redistributions in binary form must reproduce the above
14215976Sjmallett *     copyright notice, this list of conditions and the following
15215976Sjmallett *     disclaimer in the documentation and/or other materials provided
16215976Sjmallett *     with the distribution.
17215976Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215976Sjmallett *     its contributors may be used to endorse or promote products
20215976Sjmallett *     derived from this software without specific prior written
21215976Sjmallett *     permission.
22215976Sjmallett
23215976Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215976Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215976Sjmallett * regulations, and may be subject to export or import  regulations in other
26215976Sjmallett * countries.
27215976Sjmallett
28215976Sjmallett * 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
30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38215976Sjmallett ***********************license end**************************************/
39215976Sjmallett
40215976Sjmallett
41215976Sjmallett
42215976Sjmallett/**
43215976Sjmallett * @file
44215976Sjmallett *
45215976Sjmallett * Interface to SRIO
46215976Sjmallett *
47215976Sjmallett * <hr>$Revision: 41586 $<hr>
48215976Sjmallett */
49215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
50215976Sjmallett#include <asm/octeon/cvmx.h>
51215976Sjmallett#include <asm/octeon/cvmx-srio.h>
52215976Sjmallett#include <asm/octeon/cvmx-clock.h>
53215976Sjmallett#include <asm/octeon/cvmx-atomic.h>
54215976Sjmallett#ifdef CONFIG_CAVIUM_DECODE_RSL
55215976Sjmallett#include <asm/octeon/cvmx-error.h>
56215976Sjmallett#endif
57215976Sjmallett#include <asm/octeon/cvmx-sriox-defs.h>
58215976Sjmallett#include <asm/octeon/cvmx-sriomaintx-defs.h>
59215976Sjmallett#include <asm/octeon/cvmx-sli-defs.h>
60215976Sjmallett#include <asm/octeon/cvmx-dpi-defs.h>
61215976Sjmallett#include <asm/octeon/cvmx-pexp-defs.h>
62215976Sjmallett#include <asm/octeon/cvmx-helper.h>
63232812Sjmallett#include <asm/octeon/cvmx-qlm.h>
64215976Sjmallett#else
65215976Sjmallett#include "cvmx.h"
66215976Sjmallett#include "cvmx-srio.h"
67215976Sjmallett#include "cvmx-clock.h"
68215976Sjmallett#include "cvmx-helper.h"
69215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
70215976Sjmallett#include "cvmx-atomic.h"
71232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
72215976Sjmallett#include "cvmx-error.h"
73232816Sjmallett#endif
74215976Sjmallett#include "cvmx-helper-errata.h"
75215976Sjmallett#endif
76232812Sjmallett#include "cvmx-qlm.h"
77232812Sjmallett#include "cvmx-helper.h"
78215976Sjmallett#endif
79215976Sjmallett
80215976Sjmallett#define CVMX_SRIO_CONFIG_TIMEOUT        10000 /* 10ms */
81215976Sjmallett#define CVMX_SRIO_DOORBELL_TIMEOUT      10000 /* 10ms */
82215976Sjmallett#define CVMX_SRIO_CONFIG_PRIORITY       0
83215976Sjmallett#define ULL unsigned long long
84215976Sjmallett
85215976Sjmalletttypedef union
86215976Sjmallett{
87215976Sjmallett    uint64_t    u64;
88215976Sjmallett    struct
89215976Sjmallett    {
90232812Sjmallett#ifdef __BIG_ENDIAN_BITFIELD
91215976Sjmallett        uint64_t    upper           : 2;    /* Normally 2 for XKPHYS */
92215976Sjmallett        uint64_t    reserved_49_61  : 13;   /* Must be zero */
93215976Sjmallett        uint64_t    io              : 1;    /* 1 for IO space access */
94215976Sjmallett        uint64_t    did             : 5;    /* DID = 3 */
95215976Sjmallett        uint64_t    subdid          : 3;    /* SubDID = 3-6 */
96215976Sjmallett        uint64_t    reserved_36_39  : 4;    /* Must be zero */
97215976Sjmallett        uint64_t    se              : 2;    /* SubDID extender */
98215976Sjmallett        uint64_t    reserved_32_33  : 2;    /* Must be zero */
99215976Sjmallett        uint64_t    hopcount        : 8;    /* Hopcount */
100215976Sjmallett        uint64_t    address         : 24;   /* Mem address */
101215976Sjmallett#else
102215976Sjmallett        uint64_t    address         : 24;
103215976Sjmallett        uint64_t    hopcount        : 8;
104215976Sjmallett        uint64_t    reserved_32_33  : 2;
105215976Sjmallett        uint64_t    se              : 2;
106215976Sjmallett        uint64_t    reserved_36_39  : 4;
107215976Sjmallett        uint64_t    subdid          : 3;
108215976Sjmallett        uint64_t    did             : 5;
109215976Sjmallett        uint64_t    io              : 1;
110215976Sjmallett        uint64_t    reserved_49_61  : 13;
111215976Sjmallett        uint64_t    upper           : 2;
112215976Sjmallett#endif
113215976Sjmallett    } config;
114215976Sjmallett    struct
115215976Sjmallett    {
116232812Sjmallett#ifdef __BIG_ENDIAN_BITFIELD
117215976Sjmallett        uint64_t    upper           : 2;    /* Normally 2 for XKPHYS */
118215976Sjmallett        uint64_t    reserved_49_61  : 13;   /* Must be zero */
119215976Sjmallett        uint64_t    io              : 1;    /* 1 for IO space access */
120215976Sjmallett        uint64_t    did             : 5;    /* DID = 3 */
121215976Sjmallett        uint64_t    subdid          : 3;    /* SubDID = 3-6 */
122215976Sjmallett        uint64_t    reserved_36_39  : 4;    /* Must be zero */
123215976Sjmallett        uint64_t    se              : 2;    /* SubDID extender */
124215976Sjmallett        uint64_t    address         : 34;   /* Mem address */
125215976Sjmallett#else
126215976Sjmallett        uint64_t    address         : 34;
127215976Sjmallett        uint64_t    se              : 2;
128215976Sjmallett        uint64_t    reserved_36_39  : 4;
129215976Sjmallett        uint64_t    subdid          : 3;
130215976Sjmallett        uint64_t    did             : 5;
131215976Sjmallett        uint64_t    io              : 1;
132215976Sjmallett        uint64_t    reserved_49_61  : 13;
133215976Sjmallett        uint64_t    upper           : 2;
134215976Sjmallett#endif
135215976Sjmallett    } mem;
136215976Sjmallett} cvmx_sli_address_t;
137215976Sjmallett
138215976Sjmalletttypedef struct
139215976Sjmallett{
140215976Sjmallett    cvmx_srio_initialize_flags_t flags;
141215976Sjmallett    int32_t subidx_ref_count[16];   /* Reference count for SLI_MEM_ACCESS_SUBID[12-27]. Index=X-12 */
142215976Sjmallett    int32_t s2m_ref_count[16];   /* Reference count for SRIOX_S2M_TYPE[0-15]. */
143215976Sjmallett} __cvmx_srio_state_t;
144215976Sjmallett
145232812Sjmallettstatic CVMX_SHARED __cvmx_srio_state_t __cvmx_srio_state[4];
146215976Sjmallett
147215976Sjmallett
148215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
149215976Sjmallett/**
150215976Sjmallett * @INTERNAL
151215976Sjmallett * Allocate a SRIOX_S2M_TYPEX register for mapping a remote SRIO
152215976Sjmallett * device's address range into Octeons SLI address space. Reference
153215976Sjmallett * counting is used to allow sharing of duplicate setups. The current
154215976Sjmallett * implementation treats reads and writes as paired, but this could be
155215976Sjmallett * changed if we have trouble running out of indexes.
156215976Sjmallett *
157215976Sjmallett * @param srio_port SRIO port device is on
158215976Sjmallett * @param s2m       SRIOX_S2M_TYPEX setup required
159215976Sjmallett *
160215976Sjmallett * @return Index of CSR, or negative on failure
161215976Sjmallett */
162215976Sjmallettstatic int __cvmx_srio_alloc_s2m(int srio_port, cvmx_sriox_s2m_typex_t s2m)
163215976Sjmallett{
164215976Sjmallett    int s2m_index;
165215976Sjmallett    /* Search through the S2M_TYPE registers looking for an unsed one or one
166215976Sjmallett        setup the way we need it */
167215976Sjmallett    for (s2m_index=0; s2m_index<16; s2m_index++)
168215976Sjmallett    {
169215976Sjmallett        /* Increment ref count by 2 since we count read and write
170215976Sjmallett            independently. We might need a more complicated search in the
171215976Sjmallett            future */
172215976Sjmallett        int ref_count = cvmx_atomic_fetch_and_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[s2m_index], 2);
173215976Sjmallett        if (ref_count == 0)
174215976Sjmallett        {
175215976Sjmallett            /* Unused location. Write our value */
176215976Sjmallett            cvmx_write_csr(CVMX_SRIOX_S2M_TYPEX(s2m_index, srio_port), s2m.u64);
177232812Sjmallett            /* Read back to make sure the update is complete */
178232812Sjmallett            cvmx_read_csr(CVMX_SRIOX_S2M_TYPEX(s2m_index, srio_port));
179215976Sjmallett            return s2m_index;
180215976Sjmallett        }
181215976Sjmallett        else
182215976Sjmallett        {
183215976Sjmallett            /* In use, see if we can use it */
184215976Sjmallett            if (cvmx_read_csr(CVMX_SRIOX_S2M_TYPEX(s2m_index, srio_port)) == s2m.u64)
185215976Sjmallett                return s2m_index;
186215976Sjmallett            else
187215976Sjmallett                cvmx_atomic_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[s2m_index], -2);
188215976Sjmallett        }
189215976Sjmallett    }
190215976Sjmallett    cvmx_dprintf("SRIO%d: Unable to find free SRIOX_S2M_TYPEX\n", srio_port);
191215976Sjmallett    return -1;
192215976Sjmallett}
193215976Sjmallett
194215976Sjmallett
195215976Sjmallett/**
196215976Sjmallett * @INTERNAL
197215976Sjmallett * Free a handle allocated by __cvmx_srio_alloc_s2m
198215976Sjmallett *
199215976Sjmallett * @param srio_port SRIO port
200215976Sjmallett * @param index     Index to free
201215976Sjmallett */
202215976Sjmallettstatic void __cvmx_srio_free_s2m(int srio_port, int index)
203215976Sjmallett{
204215976Sjmallett    /* Read to force pending transactions to complete */
205215976Sjmallett    cvmx_read_csr(CVMX_SRIOX_S2M_TYPEX(index, srio_port));
206215976Sjmallett    cvmx_atomic_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[index], -2);
207215976Sjmallett}
208215976Sjmallett
209215976Sjmallett
210215976Sjmallett/**
211215976Sjmallett * @INTERNAL
212215976Sjmallett * Allocate a SLI SubID to map a region of memory. Reference
213215976Sjmallett * counting is used to allow sharing of duplicate setups.
214215976Sjmallett *
215215976Sjmallett * @param subid  SLI_MEM_ACCESS_SUBIDX we need an index for
216215976Sjmallett *
217215976Sjmallett * @return Index of CSR, or negative on failure
218215976Sjmallett */
219215976Sjmallettstatic int __cvmx_srio_alloc_subid(cvmx_sli_mem_access_subidx_t subid)
220215976Sjmallett{
221215976Sjmallett    int mem_index;
222215976Sjmallett    /* Search through the mem access subid registers looking for an unsed one
223215976Sjmallett        or one setup the way we need it. PCIe uses the low indexes, so search
224215976Sjmallett        backwards */
225215976Sjmallett    for (mem_index=27; mem_index>=12; mem_index--)
226215976Sjmallett    {
227215976Sjmallett        int ref_count = cvmx_atomic_fetch_and_add32(&__cvmx_srio_state[0].subidx_ref_count[mem_index-12], 1);
228215976Sjmallett        if (ref_count == 0)
229215976Sjmallett        {
230215976Sjmallett            /* Unused location. Write our value */
231215976Sjmallett            cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index), subid.u64);
232232812Sjmallett            /* Read back the value to make sure the update is complete */
233232812Sjmallett            cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index));
234215976Sjmallett            return mem_index;
235215976Sjmallett        }
236215976Sjmallett        else
237215976Sjmallett        {
238215976Sjmallett            /* In use, see if we can use it */
239215976Sjmallett            if (cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index)) == subid.u64)
240215976Sjmallett                return mem_index;
241215976Sjmallett            else
242215976Sjmallett                cvmx_atomic_add32(&__cvmx_srio_state[0].subidx_ref_count[mem_index-12], -1);
243215976Sjmallett        }
244215976Sjmallett    }
245215976Sjmallett    cvmx_dprintf("SRIO: Unable to find free SLI_MEM_ACCESS_SUBIDX\n");
246215976Sjmallett    return -1;
247215976Sjmallett}
248215976Sjmallett
249215976Sjmallett
250215976Sjmallett/**
251215976Sjmallett * @INTERNAL
252215976Sjmallett * Free a handle allocated by __cvmx_srio_alloc_subid
253215976Sjmallett *
254215976Sjmallett * @param index  Index to free
255215976Sjmallett */
256215976Sjmallettstatic void __cvmx_srio_free_subid(int index)
257215976Sjmallett{
258215976Sjmallett    /* Read to force pending transactions to complete */
259215976Sjmallett    cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(index));
260215976Sjmallett    cvmx_atomic_add32(&__cvmx_srio_state[0].subidx_ref_count[index-12], -1);
261215976Sjmallett}
262215976Sjmallett#endif
263215976Sjmallett
264215976Sjmallett
265215976Sjmallett/**
266215976Sjmallett * @INTERNAL
267215976Sjmallett * Read 32bits from a local port
268215976Sjmallett *
269215976Sjmallett * @param srio_port SRIO port the device is on
270215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
271215976Sjmallett * @param result    Result of the read. This will be unmodified on failure.
272215976Sjmallett *
273215976Sjmallett * @return Zero on success, negative on failure.
274215976Sjmallett */
275215976Sjmallettstatic int __cvmx_srio_local_read32(int srio_port, uint32_t offset, uint32_t *result)
276215976Sjmallett{
277215976Sjmallett    cvmx_sriox_maint_op_t maint_op;
278215976Sjmallett    cvmx_sriox_maint_rd_data_t maint_rd_data;
279215976Sjmallett    maint_op.u64 = 0;
280215976Sjmallett    maint_op.s.op = 0; /* Read */
281215976Sjmallett    maint_op.s.addr = offset;
282215976Sjmallett
283215976Sjmallett    /* Make sure SRIO isn't already busy */
284215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
285215976Sjmallett    {
286215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before config read\n", srio_port);
287215976Sjmallett        return -1;
288215976Sjmallett    }
289215976Sjmallett
290215976Sjmallett    /* Issue the read to the hardware */
291215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_MAINT_OP(srio_port), maint_op.u64);
292215976Sjmallett
293215976Sjmallett    /* Wait for the hardware to complete the operation */
294215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
295215976Sjmallett    {
296215976Sjmallett        cvmx_dprintf("SRIO%d: Config read timeout\n", srio_port);
297215976Sjmallett        return -1;
298215976Sjmallett    }
299215976Sjmallett
300215976Sjmallett    /* Display and error and return if the operation failed to issue */
301215976Sjmallett    maint_op.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_OP(srio_port));
302215976Sjmallett    if (maint_op.s.fail)
303215976Sjmallett    {
304215976Sjmallett        cvmx_dprintf("SRIO%d: Config read addressing error (offset=0x%x)\n", srio_port, (unsigned int)offset);
305215976Sjmallett        return -1;
306215976Sjmallett    }
307215976Sjmallett
308215976Sjmallett    /* Wait for the read data to become valid */
309215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_RD_DATA(srio_port), cvmx_sriox_maint_rd_data_t, valid, ==, 1, CVMX_SRIO_CONFIG_TIMEOUT))
310215976Sjmallett    {
311215976Sjmallett        cvmx_dprintf("SRIO%d: Config read data timeout\n", srio_port);
312215976Sjmallett        return -1;
313215976Sjmallett    }
314215976Sjmallett
315215976Sjmallett    /* Get the read data */
316215976Sjmallett    maint_rd_data.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_RD_DATA(srio_port));
317215976Sjmallett    *result = maint_rd_data.s.rd_data;
318215976Sjmallett    return 0;
319215976Sjmallett}
320215976Sjmallett
321215976Sjmallett
322215976Sjmallett/**
323215976Sjmallett * @INTERNAL
324215976Sjmallett * Write 32bits to a local port
325215976Sjmallett * @param srio_port SRIO port the device is on
326215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
327215976Sjmallett * @param data      Data to write.
328215976Sjmallett *
329215976Sjmallett * @return Zero on success, negative on failure.
330215976Sjmallett */
331215976Sjmallettstatic int __cvmx_srio_local_write32(int srio_port, uint32_t offset, uint32_t data)
332215976Sjmallett{
333215976Sjmallett    cvmx_sriox_maint_op_t maint_op;
334215976Sjmallett    maint_op.u64 = 0;
335215976Sjmallett    maint_op.s.wr_data = data;
336215976Sjmallett    maint_op.s.op = 1; /* Write */
337215976Sjmallett    maint_op.s.addr = offset;
338215976Sjmallett
339215976Sjmallett    /* Make sure SRIO isn't already busy */
340215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
341215976Sjmallett    {
342215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before config write\n", srio_port);
343215976Sjmallett        return -1;
344215976Sjmallett    }
345215976Sjmallett
346215976Sjmallett    /* Issue the write to the hardware */
347215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_MAINT_OP(srio_port), maint_op.u64);
348215976Sjmallett
349215976Sjmallett    /* Wait for the hardware to complete the operation */
350215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
351215976Sjmallett    {
352215976Sjmallett        cvmx_dprintf("SRIO%d: Config write timeout\n", srio_port);
353215976Sjmallett        return -1;
354215976Sjmallett    }
355215976Sjmallett
356215976Sjmallett    /* Display and error and return if the operation failed to issue */
357215976Sjmallett    maint_op.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_OP(srio_port));
358215976Sjmallett    if (maint_op.s.fail)
359215976Sjmallett    {
360215976Sjmallett        cvmx_dprintf("SRIO%d: Config write addressing error (offset=0x%x)\n", srio_port, (unsigned int)offset);
361215976Sjmallett        return -1;
362215976Sjmallett    }
363215976Sjmallett    return 0;
364215976Sjmallett}
365215976Sjmallett
366215976Sjmallett
367215976Sjmallett/**
368232812Sjmallett * Reset SRIO to link partner
369232812Sjmallett *
370232812Sjmallett * @param srio_port  SRIO port to initialize
371232812Sjmallett *
372232812Sjmallett * @return Zero on success
373232812Sjmallett */
374232812Sjmallettint cvmx_srio_link_rst(int srio_port)
375232812Sjmallett{
376232812Sjmallett    cvmx_sriomaintx_port_0_link_resp_t link_resp;
377232812Sjmallett
378232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
379232812Sjmallett        return -1;
380232812Sjmallett
381232812Sjmallett    /* Generate a symbol reset to the link partner by writing 0x3. */
382232812Sjmallett    if (cvmx_srio_config_write32(srio_port, 0, -1, 0, 0,
383232812Sjmallett        CVMX_SRIOMAINTX_PORT_0_LINK_REQ(srio_port), 3))
384232812Sjmallett        return -1;
385232812Sjmallett
386232812Sjmallett    if (cvmx_srio_config_read32(srio_port, 0, -1, 0, 0,
387232812Sjmallett        CVMX_SRIOMAINTX_PORT_0_LINK_RESP(srio_port), &link_resp.u32))
388232812Sjmallett        return -1;
389232812Sjmallett
390232812Sjmallett    /* Poll until link partner has received the reset. */
391232812Sjmallett    while (link_resp.s.valid == 0)
392232812Sjmallett    {
393232812Sjmallett        //cvmx_dprintf("Waiting for Link Response\n");
394232812Sjmallett        if (cvmx_srio_config_read32(srio_port, 0, -1, 0, 0,
395232812Sjmallett            CVMX_SRIOMAINTX_PORT_0_LINK_RESP(srio_port), &link_resp.u32))
396232812Sjmallett            return -1;
397232812Sjmallett    }
398232812Sjmallett
399232812Sjmallett    /* Valid response, Asserting MAC reset */
400232812Sjmallett    cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1);
401232812Sjmallett
402232812Sjmallett    cvmx_wait(10);
403232812Sjmallett
404232812Sjmallett    /* De-asserting MAC Reset */
405232812Sjmallett    cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0);
406232812Sjmallett
407232812Sjmallett    return 0;
408232812Sjmallett}
409232812Sjmallett
410232812Sjmallett/**
411215976Sjmallett * Initialize a SRIO port for use.
412215976Sjmallett *
413215976Sjmallett * @param srio_port SRIO port to initialize
414215976Sjmallett * @param flags     Optional flags
415215976Sjmallett *
416215976Sjmallett * @return Zero on success
417215976Sjmallett */
418215976Sjmallettint cvmx_srio_initialize(int srio_port, cvmx_srio_initialize_flags_t flags)
419215976Sjmallett{
420215976Sjmallett    cvmx_sriomaintx_port_lt_ctl_t port_lt_ctl;
421215976Sjmallett    cvmx_sriomaintx_port_rt_ctl_t port_rt_ctl;
422215976Sjmallett    cvmx_sriomaintx_port_0_ctl_t port_0_ctl;
423215976Sjmallett    cvmx_sriomaintx_core_enables_t core_enables;
424215976Sjmallett    cvmx_sriomaintx_port_gen_ctl_t port_gen_ctl;
425215976Sjmallett    cvmx_sriox_status_reg_t sriox_status_reg;
426215976Sjmallett    cvmx_mio_rst_ctlx_t mio_rst_ctl;
427215976Sjmallett    cvmx_sriox_imsg_vport_thr_t sriox_imsg_vport_thr;
428215976Sjmallett    cvmx_dpi_sli_prtx_cfg_t prt_cfg;
429215976Sjmallett    cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
430232812Sjmallett    cvmx_sli_mem_access_ctl_t sli_mem_access_ctl;
431232812Sjmallett    cvmx_sriomaintx_port_0_ctl2_t port_0_ctl2;
432215976Sjmallett
433215976Sjmallett    sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(srio_port));
434232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
435215976Sjmallett    {
436232812Sjmallett        /* All SRIO ports are connected to QLM0 */
437232812Sjmallett        int status = cvmx_qlm_get_status(0);
438232812Sjmallett        if (status < 4 || status > 6)
439232812Sjmallett        {
440232812Sjmallett            cvmx_dprintf("SRIO%d: Initialization called on a port not in SRIO mode\n", srio_port);
441232812Sjmallett            return -1;
442232812Sjmallett        }
443232812Sjmallett    }
444232812Sjmallett    else if (!sriox_status_reg.s.srio)
445232812Sjmallett    {
446215976Sjmallett        cvmx_dprintf("SRIO%d: Initialization called on a port not in SRIO mode\n", srio_port);
447215976Sjmallett        return -1;
448215976Sjmallett    }
449215976Sjmallett
450215976Sjmallett    __cvmx_srio_state[srio_port].flags = flags;
451215976Sjmallett
452215976Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be
453215976Sjmallett        programmed */
454215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
455215976Sjmallett    {
456215976Sjmallett        if (srio_port)
457215976Sjmallett        {
458215976Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
459215976Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
460215976Sjmallett            ciu_qlm.s.txbypass = 1;
461215976Sjmallett            ciu_qlm.s.txdeemph = 5;
462215976Sjmallett            ciu_qlm.s.txmargin = 0x17;
463215976Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
464215976Sjmallett        }
465215976Sjmallett        else
466215976Sjmallett        {
467215976Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
468215976Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
469215976Sjmallett            ciu_qlm.s.txbypass = 1;
470215976Sjmallett            ciu_qlm.s.txdeemph = 5;
471215976Sjmallett            ciu_qlm.s.txmargin = 0x17;
472215976Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
473215976Sjmallett        }
474215976Sjmallett    }
475215976Sjmallett
476232812Sjmallett    /* Don't receive or drive reset signals for the SRIO QLM */
477232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
478232812Sjmallett    {
479232812Sjmallett        /* The reset signals are available only for srio_port == 0. */
480232812Sjmallett        if (srio_port == 0 || (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2) && srio_port == 1))
481232812Sjmallett        {
482232812Sjmallett            cvmx_mio_rst_cntlx_t mio_rst_cntl;
483232812Sjmallett            mio_rst_cntl.u64 = cvmx_read_csr(CVMX_MIO_RST_CNTLX(srio_port));
484232812Sjmallett            mio_rst_cntl.s.rst_drv = 0;
485232812Sjmallett            mio_rst_cntl.s.rst_rcv = 0;
486232812Sjmallett            mio_rst_cntl.s.rst_chip = 0;
487232812Sjmallett            cvmx_write_csr(CVMX_MIO_RST_CNTLX(srio_port), mio_rst_cntl.u64);
488232812Sjmallett        }
489232812Sjmallett        /* MIO_RST_CNTL2<prtmode> is initialized to 0 on cold reset */
490232812Sjmallett        mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CNTLX(srio_port));
491232812Sjmallett    }
492232812Sjmallett    else
493232812Sjmallett    {
494232812Sjmallett        mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(srio_port));
495232812Sjmallett        mio_rst_ctl.s.rst_drv = 0;
496232812Sjmallett        mio_rst_ctl.s.rst_rcv = 0;
497232812Sjmallett        mio_rst_ctl.s.rst_chip = 0;
498232812Sjmallett        cvmx_write_csr(CVMX_MIO_RST_CTLX(srio_port), mio_rst_ctl.u64);
499232812Sjmallett
500232812Sjmallett        mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(srio_port));
501232812Sjmallett    }
502232812Sjmallett
503215976Sjmallett    cvmx_dprintf("SRIO%d: Port in %s mode\n", srio_port,
504215976Sjmallett        (mio_rst_ctl.s.prtmode) ? "host" : "endpoint");
505215976Sjmallett
506215976Sjmallett    /* Bring the port out of reset if necessary */
507232812Sjmallett    switch (srio_port)
508215976Sjmallett    {
509232812Sjmallett        case 0:
510215976Sjmallett        {
511232812Sjmallett            cvmx_ciu_soft_prst_t prst;
512232812Sjmallett            prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
513232812Sjmallett            if (prst.s.soft_prst)
514232812Sjmallett            {
515232812Sjmallett                prst.s.soft_prst = 0;
516232812Sjmallett                cvmx_write_csr(CVMX_CIU_SOFT_PRST, prst.u64);
517232812Sjmallett                /* Wait up to 250ms for the port to come out of reset */
518232812Sjmallett                if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_STATUS_REG(srio_port), cvmx_sriox_status_reg_t, access, ==, 1, 250000))
519232812Sjmallett                    return -1;
520232812Sjmallett            }
521232812Sjmallett            break;
522215976Sjmallett        }
523232812Sjmallett        case 1:
524215976Sjmallett        {
525232812Sjmallett            cvmx_ciu_soft_prst1_t prst;
526232812Sjmallett            prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
527232812Sjmallett            if (prst.s.soft_prst)
528232812Sjmallett            {
529232812Sjmallett                prst.s.soft_prst = 0;
530232812Sjmallett                cvmx_write_csr(CVMX_CIU_SOFT_PRST1, prst.u64);
531232812Sjmallett                /* Wait up to 250ms for the port to come out of reset */
532232812Sjmallett                if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_STATUS_REG(srio_port), cvmx_sriox_status_reg_t, access, ==, 1, 250000))
533232812Sjmallett                    return -1;
534232812Sjmallett            }
535232812Sjmallett            break;
536215976Sjmallett        }
537232812Sjmallett        case 2:
538232812Sjmallett        {
539232812Sjmallett            cvmx_ciu_soft_prst2_t prst;
540232812Sjmallett            prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST2);
541232812Sjmallett            if (prst.s.soft_prst)
542232812Sjmallett            {
543232812Sjmallett                prst.s.soft_prst = 0;
544232812Sjmallett                cvmx_write_csr(CVMX_CIU_SOFT_PRST2, prst.u64);
545232812Sjmallett                /* Wait up to 250ms for the port to come out of reset */
546232812Sjmallett                if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_STATUS_REG(srio_port), cvmx_sriox_status_reg_t, access, ==, 1, 250000))
547232812Sjmallett                    return -1;
548232812Sjmallett            }
549232812Sjmallett            break;
550232812Sjmallett        }
551215976Sjmallett    }
552215976Sjmallett
553215976Sjmallett    /* Disable the link while we make changes */
554215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), &port_0_ctl.u32))
555215976Sjmallett        return -1;
556232812Sjmallett    port_0_ctl.s.o_enable = 0;
557232812Sjmallett    port_0_ctl.s.i_enable = 0;
558232812Sjmallett    port_0_ctl.s.prt_lock = 1;
559232812Sjmallett    port_0_ctl.s.disable = 0;
560215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), port_0_ctl.u32))
561215976Sjmallett        return -1;
562215976Sjmallett
563232812Sjmallett    /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be
564232812Sjmallett        programmed when using a 156.25Mhz ref clock */
565232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) ||
566232812Sjmallett        OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1))
567232812Sjmallett    {
568232812Sjmallett        cvmx_mio_rst_boot_t mio_rst_boot;
569232812Sjmallett        cvmx_sriomaintx_lane_x_status_0_t lane_x_status;
570232812Sjmallett
571232812Sjmallett        /* Read the QLM config and speed pins */
572232812Sjmallett        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
573232812Sjmallett        if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_LANE_X_STATUS_0(0, srio_port), &lane_x_status.u32))
574232812Sjmallett            return -1;
575232812Sjmallett
576232812Sjmallett        if (srio_port)
577232812Sjmallett        {
578232812Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
579232812Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
580232812Sjmallett            switch (mio_rst_boot.cn63xx.qlm1_spd)
581232812Sjmallett            {
582232812Sjmallett                case 0x4: /* 1.25 Gbaud, 156.25MHz */
583232812Sjmallett                    ciu_qlm.s.txbypass = 1;
584232812Sjmallett                    ciu_qlm.s.txdeemph = 0x0;
585232812Sjmallett                    ciu_qlm.s.txmargin = (lane_x_status.s.rx_type == 0) ? 0x11 : 0x1c; /* short or med/long */
586232812Sjmallett                    break;
587232812Sjmallett                case 0xb: /* 5.0 Gbaud, 156.25MHz */
588232812Sjmallett                    ciu_qlm.s.txbypass = 1;
589232812Sjmallett                    ciu_qlm.s.txdeemph = (lane_x_status.s.rx_type == 0) ? 0xa : 0xf; /* short or med/long */
590232812Sjmallett                    ciu_qlm.s.txmargin = (lane_x_status.s.rx_type == 0) ? 0xf : 0x1a; /* short or med/long */
591232812Sjmallett                    break;
592232812Sjmallett            }
593232812Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
594232812Sjmallett        }
595232812Sjmallett        else
596232812Sjmallett        {
597232812Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
598232812Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
599232812Sjmallett            switch (mio_rst_boot.cn63xx.qlm0_spd)
600232812Sjmallett            {
601232812Sjmallett                case 0x4: /* 1.25 Gbaud, 156.25MHz */
602232812Sjmallett                    ciu_qlm.s.txbypass = 1;
603232812Sjmallett                    ciu_qlm.s.txdeemph = 0x0;
604232812Sjmallett                    ciu_qlm.s.txmargin = (lane_x_status.s.rx_type == 0) ? 0x11 : 0x1c; /* short or med/long */
605232812Sjmallett                    break;
606232812Sjmallett                case 0xb: /* 5.0 Gbaud, 156.25MHz */
607232812Sjmallett                    ciu_qlm.s.txbypass = 1;
608232812Sjmallett                    ciu_qlm.s.txdeemph = (lane_x_status.s.rx_type == 0) ? 0xa : 0xf; /* short or med/long */
609232812Sjmallett                    ciu_qlm.s.txmargin = (lane_x_status.s.rx_type == 0) ? 0xf : 0x1a; /* short or med/long */
610232812Sjmallett                    break;
611232812Sjmallett            }
612232812Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
613232812Sjmallett        }
614232812Sjmallett    }
615232812Sjmallett
616215976Sjmallett    /* Errata SRIO-14485: Link speed is reported incorrectly in CN63XX
617215976Sjmallett        pass 1.x */
618215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
619215976Sjmallett    {
620215976Sjmallett        cvmx_sriomaintx_port_0_ctl2_t port_0_ctl2;
621215976Sjmallett        if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), &port_0_ctl2.u32))
622215976Sjmallett            return -1;
623215976Sjmallett        if (port_0_ctl2.s.enb_500g)
624215976Sjmallett        {
625215976Sjmallett            port_0_ctl2.u32 = 0;
626215976Sjmallett            port_0_ctl2.s.enb_625g = 1;
627215976Sjmallett        }
628215976Sjmallett        else if (port_0_ctl2.s.enb_312g)
629215976Sjmallett        {
630215976Sjmallett            port_0_ctl2.u32 = 0;
631215976Sjmallett            port_0_ctl2.s.enb_500g = 1;
632215976Sjmallett        }
633215976Sjmallett        else if (port_0_ctl2.s.enb_250g)
634215976Sjmallett        {
635215976Sjmallett            port_0_ctl2.u32 = 0;
636215976Sjmallett            port_0_ctl2.s.enb_312g = 1;
637215976Sjmallett        }
638215976Sjmallett        else if (port_0_ctl2.s.enb_125g)
639215976Sjmallett        {
640215976Sjmallett            port_0_ctl2.u32 = 0;
641215976Sjmallett            port_0_ctl2.s.enb_250g = 1;
642215976Sjmallett        }
643215976Sjmallett        else
644215976Sjmallett        {
645215976Sjmallett            port_0_ctl2.u32 = 0;
646215976Sjmallett            port_0_ctl2.s.enb_125g = 1;
647215976Sjmallett        }
648215976Sjmallett        if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), port_0_ctl2.u32))
649215976Sjmallett            return -1;
650215976Sjmallett    }
651215976Sjmallett
652232812Sjmallett    /* Errata SRIO-15351: Turn off SRIOMAINTX_MAC_CTRL[TYPE_MRG] as it may
653232812Sjmallett        cause packet ACCEPT to be lost */
654232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) || OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1))
655232812Sjmallett    {
656232812Sjmallett        cvmx_sriomaintx_mac_ctrl_t mac_ctrl;
657232812Sjmallett        if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_MAC_CTRL(srio_port), &mac_ctrl.u32))
658232812Sjmallett            return -1;
659232812Sjmallett        mac_ctrl.s.type_mrg = 0;
660232812Sjmallett        if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_MAC_CTRL(srio_port), mac_ctrl.u32))
661232812Sjmallett            return -1;
662232812Sjmallett    }
663232812Sjmallett
664232812Sjmallett    /* Set the link layer timeout to 1ms. The default is too high and causes
665215976Sjmallett        core bus errors */
666215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_LT_CTL(srio_port), &port_lt_ctl.u32))
667215976Sjmallett        return -1;
668232812Sjmallett    port_lt_ctl.s.timeout = 1000000 / 200; /* 1ms = 1000000ns / 200ns */
669215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_LT_CTL(srio_port), port_lt_ctl.u32))
670215976Sjmallett        return -1;
671215976Sjmallett
672232812Sjmallett    /* Set the logical layer timeout to 100ms. The default is too high and causes
673215976Sjmallett        core bus errors */
674215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_RT_CTL(srio_port), &port_rt_ctl.u32))
675215976Sjmallett        return -1;
676232812Sjmallett    port_rt_ctl.s.timeout = 100000000 / 200; /* 100ms = 100000000ns / 200ns */
677215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_RT_CTL(srio_port), port_rt_ctl.u32))
678215976Sjmallett        return -1;
679215976Sjmallett
680215976Sjmallett    /* Allow memory and doorbells. Messaging is enabled later */
681215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_CORE_ENABLES(srio_port), &core_enables.u32))
682215976Sjmallett        return -1;
683215976Sjmallett    core_enables.s.doorbell = 1;
684215976Sjmallett    core_enables.s.memory = 1;
685215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_CORE_ENABLES(srio_port), core_enables.u32))
686215976Sjmallett        return -1;
687215976Sjmallett
688215976Sjmallett    /* Allow us to master transactions */
689215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_GEN_CTL(srio_port), &port_gen_ctl.u32))
690215976Sjmallett        return -1;
691215976Sjmallett    port_gen_ctl.s.menable = 1;
692215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_GEN_CTL(srio_port), port_gen_ctl.u32))
693215976Sjmallett        return -1;
694215976Sjmallett
695215976Sjmallett    /* Set the MRRS and MPS for optimal SRIO performance */
696215976Sjmallett    prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(srio_port));
697215976Sjmallett    prt_cfg.s.mps = 1;
698215976Sjmallett    prt_cfg.s.mrrs = 1;
699232812Sjmallett    prt_cfg.s.molr = 32;
700232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
701232812Sjmallett        prt_cfg.s.molr = ((prt_cfg.s.qlm_cfg == 1 || prt_cfg.s.qlm_cfg == 3) ? 8
702232812Sjmallett                          : (prt_cfg.s.qlm_cfg == 4 || prt_cfg.s.qlm_cfg == 6) ? 16
703232812Sjmallett                          : 32);
704215976Sjmallett    cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(srio_port), prt_cfg.u64);
705215976Sjmallett
706215976Sjmallett    sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(srio_port));
707215976Sjmallett    sli_s2m_portx_ctl.s.mrrs = 1;
708215976Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(srio_port), sli_s2m_portx_ctl.u64);
709215976Sjmallett
710215976Sjmallett    /* Setup RX messaging thresholds */
711215976Sjmallett    sriox_imsg_vport_thr.u64 = cvmx_read_csr(CVMX_SRIOX_IMSG_VPORT_THR(srio_port));
712232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
713232812Sjmallett        sriox_imsg_vport_thr.s.max_tot = ((prt_cfg.s.qlm_cfg == 1 || prt_cfg.s.qlm_cfg == 3) ? 44 : 46);
714232812Sjmallett    else
715232812Sjmallett        sriox_imsg_vport_thr.s.max_tot = 48;
716215976Sjmallett    sriox_imsg_vport_thr.s.max_s1 = 24;
717215976Sjmallett    sriox_imsg_vport_thr.s.max_s0 = 24;
718215976Sjmallett    sriox_imsg_vport_thr.s.sp_vport = 1;
719215976Sjmallett    sriox_imsg_vport_thr.s.buf_thr = 4;
720215976Sjmallett    sriox_imsg_vport_thr.s.max_p1 = 12;
721215976Sjmallett    sriox_imsg_vport_thr.s.max_p0 = 12;
722215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_IMSG_VPORT_THR(srio_port), sriox_imsg_vport_thr.u64);
723215976Sjmallett
724232812Sjmallett    /* Setup RX messaging thresholds for other virtual ports. */
725232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
726232812Sjmallett    {
727232812Sjmallett        cvmx_sriox_imsg_vport_thr2_t sriox_imsg_vport_thr2;
728232812Sjmallett        sriox_imsg_vport_thr2.u64 = cvmx_read_csr(CVMX_SRIOX_IMSG_VPORT_THR2(srio_port));
729232812Sjmallett        sriox_imsg_vport_thr2.s.max_s2 = 24;
730232812Sjmallett        sriox_imsg_vport_thr2.s.max_s3 = 24;
731232812Sjmallett        cvmx_write_csr(CVMX_SRIOX_IMSG_VPORT_THR2(srio_port), sriox_imsg_vport_thr2.u64);
732232812Sjmallett    }
733232812Sjmallett
734215976Sjmallett    /* Errata SRIO-X: SRIO error behavior may not be optimal in CN63XX pass 1.x */
735215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
736215976Sjmallett    {
737215976Sjmallett        cvmx_sriox_tx_ctrl_t sriox_tx_ctrl;
738215976Sjmallett        sriox_tx_ctrl.u64 = cvmx_read_csr(CVMX_SRIOX_TX_CTRL(srio_port));
739215976Sjmallett        sriox_tx_ctrl.s.tag_th2 = 2;
740215976Sjmallett        sriox_tx_ctrl.s.tag_th1 = 3;
741215976Sjmallett        sriox_tx_ctrl.s.tag_th0 = 4;
742215976Sjmallett        cvmx_write_csr(CVMX_SRIOX_TX_CTRL(srio_port), sriox_tx_ctrl.u64);
743215976Sjmallett    }
744215976Sjmallett
745232812Sjmallett    /* Errata SLI-15954: SLI relaxed order issues */
746232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X))
747232812Sjmallett    {
748232812Sjmallett        cvmx_sli_ctl_portx_t sli_ctl_portx;
749232812Sjmallett        sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(srio_port));
750232812Sjmallett        sli_ctl_portx.s.ptlp_ro = 1;    /* Set to same value for all MACs. */
751232812Sjmallett        sli_ctl_portx.s.ctlp_ro = 1;    /* Set to same value for all MACs. */
752232812Sjmallett        sli_ctl_portx.s.wait_com = 0;   /* So that no inbound stores wait for a commit */
753232812Sjmallett        sli_ctl_portx.s.waitl_com = 0;
754232812Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(srio_port), sli_ctl_portx.u64);
755232812Sjmallett    }
756232812Sjmallett
757232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
758232812Sjmallett    {
759232812Sjmallett        /* Clear the ACK state */
760232812Sjmallett        if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_LOCAL_ACKID(srio_port), 0))
761232812Sjmallett            return -1;
762232812Sjmallett    }
763232812Sjmallett
764232812Sjmallett    /* Bring the link down, then up, by writing to the SRIO port's
765232812Sjmallett       PORT_0_CTL2 CSR. */
766232812Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), &port_0_ctl2.u32))
767232812Sjmallett        return -1;
768232812Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), port_0_ctl2.u32))
769232812Sjmallett        return -1;
770232812Sjmallett
771215976Sjmallett    /* Clear any pending interrupts */
772215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_INT_REG(srio_port), cvmx_read_csr(CVMX_SRIOX_INT_REG(srio_port)));
773215976Sjmallett
774215976Sjmallett    /* Enable error reporting */
775232816Sjmallett#if (!defined(CVMX_BUILD_FOR_LINUX_HOST) && !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)) || defined(CONFIG_CAVIUM_DECODE_RSL)
776215976Sjmallett    cvmx_error_enable_group(CVMX_ERROR_GROUP_SRIO, srio_port);
777215976Sjmallett#endif
778215976Sjmallett
779215976Sjmallett    /* Finally enable the link */
780215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), &port_0_ctl.u32))
781215976Sjmallett        return -1;
782215976Sjmallett    port_0_ctl.s.o_enable = 1;
783215976Sjmallett    port_0_ctl.s.i_enable = 1;
784215976Sjmallett    port_0_ctl.s.disable = 0;
785215976Sjmallett    port_0_ctl.s.prt_lock = 0;
786215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), port_0_ctl.u32))
787215976Sjmallett        return -1;
788215976Sjmallett
789232812Sjmallett    /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
790232812Sjmallett    sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL);
791232812Sjmallett    sli_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
792232812Sjmallett    sli_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
793232812Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);
794232812Sjmallett
795232812Sjmallett    /* FIXME: Disable sending a link request when the SRIO link is
796232812Sjmallett        brought up. For unknown reasons this code causes issues with some SRIO
797232812Sjmallett        devices. As we currently don't support hotplug in software, this code
798232812Sjmallett        should never be needed.  Without link down/up events, the ACKs should
799232812Sjmallett        start off and stay synchronized */
800232812Sjmallett#if 0
801232812Sjmallett    /* Ask for a link and align our ACK state. CN63XXp1 didn't support this */
802232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
803232812Sjmallett    {
804232812Sjmallett        uint64_t stop_cycle;
805232812Sjmallett        cvmx_sriomaintx_port_0_err_stat_t sriomaintx_port_0_err_stat;
806232812Sjmallett
807232812Sjmallett        /* Clear the SLI_CTL_PORTX[DIS_PORT[ bit to re-enable traffic-flow
808232812Sjmallett           to the SRIO MACs. */
809232812Sjmallett        cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(srio_port), cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(srio_port)));
810232812Sjmallett
811232812Sjmallett        /* Wait a little to see if the link comes up */
812232812Sjmallett        stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/4 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
813232812Sjmallett        do
814232812Sjmallett        {
815232812Sjmallett            /* Read the port link status */
816232812Sjmallett            if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_ERR_STAT(srio_port), &sriomaintx_port_0_err_stat.u32))
817232812Sjmallett                return -1;
818232812Sjmallett        } while (!sriomaintx_port_0_err_stat.s.pt_ok && (cvmx_clock_get_count(CVMX_CLOCK_CORE) < stop_cycle));
819232812Sjmallett
820232812Sjmallett        /* Send link request if link is up */
821232812Sjmallett        if (sriomaintx_port_0_err_stat.s.pt_ok)
822232812Sjmallett        {
823232812Sjmallett            cvmx_sriomaintx_port_0_link_req_t link_req;
824232812Sjmallett            cvmx_sriomaintx_port_0_link_resp_t link_resp;
825232812Sjmallett            link_req.u32 = 0;
826232812Sjmallett            link_req.s.cmd = 4;
827232812Sjmallett
828232812Sjmallett            /* Send the request */
829232812Sjmallett            if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_LINK_REQ(srio_port), link_req.u32))
830232812Sjmallett                return -1;
831232812Sjmallett
832232812Sjmallett            /* Wait for the response */
833232812Sjmallett            stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/8 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
834232812Sjmallett            do
835232812Sjmallett            {
836232812Sjmallett                if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_LINK_RESP(srio_port), &link_resp.u32))
837232812Sjmallett                    return -1;
838232812Sjmallett            } while (!link_resp.s.valid && (cvmx_clock_get_count(CVMX_CLOCK_CORE) < stop_cycle));
839232812Sjmallett
840232812Sjmallett            /* Set our ACK state if we got a response */
841232812Sjmallett            if (link_resp.s.valid)
842232812Sjmallett            {
843232812Sjmallett                cvmx_sriomaintx_port_0_local_ackid_t local_ackid;
844232812Sjmallett                local_ackid.u32 = 0;
845232812Sjmallett                local_ackid.s.i_ackid = 0;
846232812Sjmallett                local_ackid.s.e_ackid = link_resp.s.ackid;
847232812Sjmallett                local_ackid.s.o_ackid = link_resp.s.ackid;
848232812Sjmallett                if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_LOCAL_ACKID(srio_port), local_ackid.u32))
849232812Sjmallett                    return -1;
850232812Sjmallett            }
851232812Sjmallett            else
852232812Sjmallett                return -1;
853232812Sjmallett        }
854232812Sjmallett    }
855232812Sjmallett#endif
856232812Sjmallett
857215976Sjmallett    return 0;
858215976Sjmallett}
859215976Sjmallett
860215976Sjmallett
861215976Sjmallett/**
862215976Sjmallett * Read 32bits from a Device's config space
863215976Sjmallett *
864215976Sjmallett * @param srio_port SRIO port the device is on
865215976Sjmallett * @param srcid_index
866215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
867215976Sjmallett * @param destid    RapidIO device ID, or -1 for the local Octeon.
868215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
869215976Sjmallett *                  if transactions should use 8bit device IDs.
870215976Sjmallett * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
871215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
872215976Sjmallett * @param result    Result of the read. This will be unmodified on failure.
873215976Sjmallett *
874215976Sjmallett * @return Zero on success, negative on failure.
875215976Sjmallett */
876215976Sjmallettint cvmx_srio_config_read32(int srio_port, int srcid_index, int destid,
877215976Sjmallett                            int is16bit, uint8_t hopcount, uint32_t offset,
878215976Sjmallett                            uint32_t *result)
879215976Sjmallett{
880215976Sjmallett    if (destid == -1)
881215976Sjmallett    {
882215976Sjmallett        int status = __cvmx_srio_local_read32(srio_port, offset, result);
883215976Sjmallett
884215976Sjmallett        if ((status == 0) && (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG))
885215976Sjmallett            cvmx_dprintf("SRIO%d: Local read [0x%06x] <= 0x%08x\n", srio_port, (unsigned int)offset, (unsigned int)*result);
886215976Sjmallett
887215976Sjmallett        return status;
888215976Sjmallett    }
889215976Sjmallett    else
890215976Sjmallett    {
891232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
892232812Sjmallett        {
893232812Sjmallett            int return_code;
894232812Sjmallett            uint32_t pkt = 0;
895232812Sjmallett            uint32_t sourceid;
896232812Sjmallett            uint64_t stop_cycle;
897232812Sjmallett            char rx_buffer[64];
898215976Sjmallett
899232812Sjmallett            /* Tell the user */
900232812Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
901232812Sjmallett                cvmx_dprintf("SRIO%d: Remote read [id=0x%04x hop=%3d offset=0x%06x] <= ", srio_port, destid, hopcount, (unsigned int)offset);
902215976Sjmallett
903232812Sjmallett            /* Read the proper source ID */
904232812Sjmallett            if (srcid_index)
905232812Sjmallett                __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_SEC_DEV_ID(srio_port), &sourceid);
906232812Sjmallett            else
907232812Sjmallett                __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PRI_DEV_ID(srio_port), &sourceid);
908215976Sjmallett
909232812Sjmallett            if (is16bit)
910232812Sjmallett            {
911232812Sjmallett                /* Use the 16bit source ID */
912232812Sjmallett                sourceid &= 0xffff;
913215976Sjmallett
914232812Sjmallett                /* MAINT Reads are 11 bytes */
915232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 11<<16);
916215976Sjmallett
917232812Sjmallett                pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
918232812Sjmallett                pkt |= 1 << 28;                         /* tt       [29:28] */
919232812Sjmallett                pkt |= 0x8 << 24;                       /* ftype    [27:24] */
920232812Sjmallett                pkt |= destid << 8;                     /* destID   [23:8] */
921232812Sjmallett                pkt |= sourceid >> 8;                   /* sourceID [7:0] */
922232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
923232812Sjmallett                pkt = 0;
924232812Sjmallett                pkt |= sourceid << 24;                  /* sourceID [31:24] */
925232812Sjmallett                pkt |= 0 << 20;                         /* transaction [23:20] */
926232812Sjmallett                pkt |= 8 << 16;                         /* rdsize [19:16] */
927232812Sjmallett                pkt |= 0xc0 << 8;                       /* srcTID [15:8] */
928232812Sjmallett                pkt |= hopcount;                        /* hopcount [7:0] */
929232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
930232812Sjmallett                pkt = 0;
931232812Sjmallett                pkt |= offset << 8;                     /* offset [31:11, wdptr[10], reserved[9:8] */
932232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
933232812Sjmallett            }
934232812Sjmallett            else
935232812Sjmallett            {
936232812Sjmallett                /* Use the 8bit source ID */
937232812Sjmallett                sourceid = (sourceid >> 16) & 0xff;
938215976Sjmallett
939232812Sjmallett                /* MAINT Reads are 9 bytes */
940232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 9<<16);
941215976Sjmallett
942232812Sjmallett                pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
943232812Sjmallett                pkt |= 0 << 28;                         /* tt       [29:28] */
944232812Sjmallett                pkt |= 0x8 << 24;                       /* ftype    [27:24] */
945232812Sjmallett                pkt |= destid << 16;                    /* destID   [23:16] */
946232812Sjmallett                pkt |= sourceid << 8;                   /* sourceID [15:8] */
947232812Sjmallett                pkt |= 0 << 4;                          /* transaction [7:4] */
948232812Sjmallett                pkt |= 8 << 0;                          /* rdsize [3:0] */
949232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
950232812Sjmallett                pkt = 0;
951232812Sjmallett                pkt |= 0xc0 << 24;                      /* srcTID [31:24] */
952232812Sjmallett                pkt |= hopcount << 16;                  /* hopcount [23:16] */
953232812Sjmallett                pkt |= offset >> 8;                     /* offset [15:0] */
954232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
955232812Sjmallett                pkt = 0;
956232812Sjmallett                pkt |= offset << 24;                    /* offset [31:27, wdptr[26], reserved[25:24] */
957232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
958232812Sjmallett            }
959215976Sjmallett
960232812Sjmallett            stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/10 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
961232812Sjmallett            do
962215976Sjmallett            {
963232812Sjmallett                return_code = cvmx_srio_receive_spf(srio_port, rx_buffer, sizeof(rx_buffer));
964232812Sjmallett                if ((return_code == 0) && (cvmx_clock_get_count(CVMX_CLOCK_CORE) > stop_cycle))
965232812Sjmallett                {
966232812Sjmallett                    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
967232812Sjmallett                        cvmx_dprintf("timeout\n");
968232812Sjmallett                    return_code = -1;
969232812Sjmallett                }
970232812Sjmallett            } while (return_code == 0);
971215976Sjmallett
972232812Sjmallett            if (return_code == ((is16bit) ? 23 : 19))
973215976Sjmallett            {
974232812Sjmallett                if (is16bit)
975232812Sjmallett                {
976232812Sjmallett                    if (offset & 4)
977232812Sjmallett                        *result = *(uint32_t*)(rx_buffer + 15);
978232812Sjmallett                    else
979232812Sjmallett                        *result = *(uint32_t*)(rx_buffer + 11);
980232812Sjmallett                }
981215976Sjmallett                else
982232812Sjmallett                {
983232812Sjmallett                    if (offset & 4)
984232812Sjmallett                        *result = *(uint32_t*)(rx_buffer + 13);
985232812Sjmallett                    else
986232812Sjmallett                        *result = *(uint32_t*)(rx_buffer + 9);
987232812Sjmallett                }
988232812Sjmallett                if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
989232812Sjmallett                    cvmx_dprintf("0x%08x\n", (unsigned int)*result);
990232812Sjmallett                return_code = 0;
991215976Sjmallett            }
992215976Sjmallett            else
993215976Sjmallett            {
994232812Sjmallett                *result = 0xffffffff;
995232812Sjmallett                return_code = -1;
996215976Sjmallett            }
997232812Sjmallett
998232812Sjmallett            return return_code;
999215976Sjmallett        }
1000215976Sjmallett        else
1001215976Sjmallett        {
1002232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_HOST)
1003232812Sjmallett            uint64_t physical;
1004232812Sjmallett            physical = cvmx_srio_physical_map(srio_port,
1005232812Sjmallett                CVMX_SRIO_WRITE_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
1006232812Sjmallett                CVMX_SRIO_READ_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
1007232812Sjmallett                srcid_index, destid, is16bit, offset + (hopcount<<24), 4);
1008232812Sjmallett            if (!physical)
1009232812Sjmallett                return -1;
1010215976Sjmallett
1011232812Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1012232812Sjmallett                cvmx_dprintf("SRIO%d: Remote read [id=0x%04x hop=%3d offset=0x%06x] <= ", srio_port, destid, hopcount, (unsigned int)offset);
1013215976Sjmallett
1014232812Sjmallett            /* Finally do the maintenance read to complete the config request */
1015232812Sjmallett            *result = cvmx_read64_uint32(CVMX_ADD_IO_SEG(physical));
1016232812Sjmallett            cvmx_srio_physical_unmap(physical, 4);
1017215976Sjmallett
1018232812Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1019232812Sjmallett                cvmx_dprintf("0x%08x\n", (unsigned int)*result);
1020215976Sjmallett
1021232812Sjmallett            return 0;
1022215976Sjmallett#else
1023232812Sjmallett            return -1;
1024215976Sjmallett#endif
1025232812Sjmallett        }
1026215976Sjmallett    }
1027215976Sjmallett}
1028232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1029232812SjmallettEXPORT_SYMBOL(cvmx_srio_config_read32);
1030232812Sjmallett#endif
1031215976Sjmallett
1032215976Sjmallett
1033215976Sjmallett/**
1034215976Sjmallett * Write 32bits to a Device's config space
1035215976Sjmallett *
1036215976Sjmallett * @param srio_port SRIO port the device is on
1037215976Sjmallett * @param srcid_index
1038215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
1039215976Sjmallett * @param destid    RapidIO device ID, or -1 for the local Octeon.
1040215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1041215976Sjmallett *                  if transactions should use 8bit device IDs.
1042215976Sjmallett * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
1043215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
1044215976Sjmallett * @param data      Data to write.
1045215976Sjmallett *
1046215976Sjmallett * @return Zero on success, negative on failure.
1047215976Sjmallett */
1048215976Sjmallettint cvmx_srio_config_write32(int srio_port, int srcid_index, int destid,
1049215976Sjmallett                             int is16bit, uint8_t hopcount, uint32_t offset,
1050215976Sjmallett                             uint32_t data)
1051215976Sjmallett{
1052215976Sjmallett    if (destid == -1)
1053215976Sjmallett    {
1054215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1055215976Sjmallett            cvmx_dprintf("SRIO%d: Local write[0x%06x] => 0x%08x\n", srio_port, (unsigned int)offset, (unsigned int)data);
1056215976Sjmallett
1057215976Sjmallett        return __cvmx_srio_local_write32(srio_port, offset, data);
1058215976Sjmallett    }
1059215976Sjmallett    else
1060215976Sjmallett    {
1061232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
1062215976Sjmallett        {
1063232812Sjmallett            int return_code;
1064232812Sjmallett            uint32_t pkt = 0;
1065232812Sjmallett            uint32_t sourceid;
1066232812Sjmallett            uint64_t stop_cycle;
1067232812Sjmallett            char rx_buffer[64];
1068215976Sjmallett
1069232812Sjmallett            /* Tell the user */
1070232812Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1071232812Sjmallett                cvmx_dprintf("SRIO%d: Remote write[id=0x%04x hop=%3d offset=0x%06x] => 0x%08x\n", srio_port, destid, hopcount, (unsigned int)offset, (unsigned int)data);
1072215976Sjmallett
1073232812Sjmallett            /* Read the proper source ID */
1074232812Sjmallett            if (srcid_index)
1075232812Sjmallett                __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_SEC_DEV_ID(srio_port), &sourceid);
1076215976Sjmallett            else
1077232812Sjmallett                __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PRI_DEV_ID(srio_port), &sourceid);
1078232812Sjmallett
1079232812Sjmallett            if (is16bit)
1080215976Sjmallett            {
1081232812Sjmallett                /* Use the 16bit source ID */
1082232812Sjmallett                sourceid &= 0xffff;
1083215976Sjmallett
1084232812Sjmallett                /* MAINT Writes are 19 bytes */
1085232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 19<<16);
1086215976Sjmallett
1087232812Sjmallett                pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
1088232812Sjmallett                pkt |= 1 << 28;                         /* tt       [29:28] */
1089232812Sjmallett                pkt |= 0x8 << 24;                       /* ftype    [27:24] */
1090232812Sjmallett                pkt |= destid << 8;                     /* destID   [23:8] */
1091232812Sjmallett                pkt |= sourceid >> 8;                   /* sourceID [7:0] */
1092215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1093232812Sjmallett                pkt = 0;
1094232812Sjmallett                pkt |= sourceid << 24;                  /* sourceID [31:24] */
1095232812Sjmallett                pkt |= 1 << 20;                         /* transaction [23:20] */
1096232812Sjmallett                pkt |= 8 << 16;                         /* wrsize [19:16] */
1097232812Sjmallett                pkt |= 0xc0 << 8;                       /* srcTID [15:8] */
1098232812Sjmallett                pkt |= hopcount;                        /* hopcount [7:0] */
1099215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1100232812Sjmallett                pkt = 0;
1101232812Sjmallett                pkt |= offset << 8;                     /* offset [31:11, wdptr[10], reserved[9:8] */
1102232812Sjmallett                if ((offset & 4) == 0)
1103232812Sjmallett                    pkt |= 0xff & (data >> 24);       /* data [7:0] */
1104215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1105232812Sjmallett                if (offset & 4)
1106232812Sjmallett                {
1107232812Sjmallett                    pkt = 0xff & (data >> 24);
1108232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1109232812Sjmallett                    pkt = data << 8;
1110232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1111232812Sjmallett                }
1112232812Sjmallett                else
1113232812Sjmallett                {
1114232812Sjmallett                    pkt = data << 8;
1115232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1116232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), 0);
1117232812Sjmallett                }
1118215976Sjmallett            }
1119215976Sjmallett            else
1120215976Sjmallett            {
1121232812Sjmallett                /* Use the 8bit source ID */
1122232812Sjmallett                sourceid = (sourceid >> 16) & 0xff;
1123232812Sjmallett
1124232812Sjmallett                /* MAINT Writes are 17 bytes */
1125232812Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 17<<16);
1126232812Sjmallett
1127232812Sjmallett                pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
1128232812Sjmallett                pkt |= 0 << 28;                         /* tt       [29:28] */
1129232812Sjmallett                pkt |= 0x8 << 24;                       /* ftype    [27:24] */
1130232812Sjmallett                pkt |= destid << 16;                    /* destID   [23:16] */
1131232812Sjmallett                pkt |= sourceid << 8;                   /* sourceID [15:8] */
1132232812Sjmallett                pkt |= 1 << 4;                          /* transaction [7:4] */
1133232812Sjmallett                pkt |= 8 << 0;                          /* wrsize [3:0] */
1134215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1135232812Sjmallett                pkt = 0;
1136232812Sjmallett                pkt |= 0xc0 << 24;                      /* srcTID [31:24] */
1137232812Sjmallett                pkt |= hopcount << 16;                  /* hopcount [23:16] */
1138232812Sjmallett                pkt |= offset >> 8;                     /* offset [15:0] */
1139215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1140232812Sjmallett                pkt = 0;
1141232812Sjmallett                pkt |= offset << 24;                    /* offset [31:27, wdptr[26], reserved[25:24] */
1142232812Sjmallett                if (offset & 4)
1143232812Sjmallett                {
1144232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1145232812Sjmallett                    pkt = data >> 8;
1146232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1147232812Sjmallett                    pkt = data << 24;
1148232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1149232812Sjmallett                }
1150232812Sjmallett                else
1151232812Sjmallett                {
1152232812Sjmallett                    pkt |= data >> 8;                    /* data [23:0] */
1153232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1154232812Sjmallett                    pkt = data << 24;                    /* data [31:24] */
1155232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
1156232812Sjmallett                    __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), 0);
1157232812Sjmallett                }
1158215976Sjmallett            }
1159215976Sjmallett
1160232812Sjmallett            stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/10 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
1161232812Sjmallett            do
1162215976Sjmallett            {
1163232812Sjmallett                return_code = cvmx_srio_receive_spf(srio_port, rx_buffer, sizeof(rx_buffer));
1164232812Sjmallett                if ((return_code == 0) && (cvmx_clock_get_count(CVMX_CLOCK_CORE) > stop_cycle))
1165232812Sjmallett                {
1166232812Sjmallett                    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1167232812Sjmallett                        cvmx_dprintf("timeout\n");
1168232812Sjmallett                    return_code = -1;
1169232812Sjmallett                }
1170232812Sjmallett            } while (return_code == 0);
1171232812Sjmallett
1172232812Sjmallett            if (return_code == ((is16bit) ? 15 : 11))
1173232812Sjmallett                return_code = 0;
1174232812Sjmallett            else
1175232812Sjmallett            {
1176232812Sjmallett                cvmx_dprintf("SRIO%d: Remote write failed\n", srio_port);
1177215976Sjmallett                return_code = -1;
1178215976Sjmallett            }
1179215976Sjmallett
1180232812Sjmallett            return return_code;
1181232812Sjmallett        }
1182215976Sjmallett        else
1183215976Sjmallett        {
1184232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_HOST)
1185232812Sjmallett            uint64_t physical = cvmx_srio_physical_map(srio_port,
1186232812Sjmallett                    CVMX_SRIO_WRITE_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
1187232812Sjmallett                    CVMX_SRIO_READ_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
1188232812Sjmallett                    srcid_index, destid, is16bit, offset + (hopcount<<24), 4);
1189232812Sjmallett            if (!physical)
1190232812Sjmallett                return -1;
1191215976Sjmallett
1192232812Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1193232812Sjmallett                cvmx_dprintf("SRIO%d: Remote write[id=0x%04x hop=%3d offset=0x%06x] => 0x%08x\n", srio_port, destid, hopcount, (unsigned int)offset, (unsigned int)data);
1194215976Sjmallett
1195232812Sjmallett            /* Finally do the maintenance write to complete the config request */
1196232812Sjmallett            cvmx_write64_uint32(CVMX_ADD_IO_SEG(physical), data);
1197232812Sjmallett            return cvmx_srio_physical_unmap(physical, 4);
1198215976Sjmallett#else
1199232812Sjmallett            return -1;
1200215976Sjmallett#endif
1201232812Sjmallett        }
1202215976Sjmallett    }
1203215976Sjmallett}
1204215976Sjmallett
1205215976Sjmallett
1206215976Sjmallett/**
1207215976Sjmallett * Send a RapidIO doorbell to a remote device
1208215976Sjmallett *
1209215976Sjmallett * @param srio_port SRIO port the device is on
1210215976Sjmallett * @param srcid_index
1211215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
1212215976Sjmallett * @param destid    RapidIO device ID.
1213215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1214215976Sjmallett *                  if transactions should use 8bit device IDs.
1215215976Sjmallett * @param priority  Doorbell priority (0-3)
1216215976Sjmallett * @param data      Data for doorbell.
1217215976Sjmallett *
1218215976Sjmallett * @return Zero on success, negative on failure.
1219215976Sjmallett */
1220215976Sjmallettint cvmx_srio_send_doorbell(int srio_port, int srcid_index, int destid, int is16bit, int priority, uint16_t data)
1221215976Sjmallett{
1222215976Sjmallett    cvmx_sriox_tx_bell_t tx_bell;
1223215976Sjmallett    tx_bell.u64 = 0;
1224215976Sjmallett    tx_bell.s.data = data;
1225215976Sjmallett    tx_bell.s.dest_id = destid;
1226215976Sjmallett    tx_bell.s.src_id = srcid_index;
1227215976Sjmallett    tx_bell.s.id16 = !!is16bit;
1228215976Sjmallett    tx_bell.s.priority = priority;
1229215976Sjmallett
1230215976Sjmallett    /* Make sure the previous doorbell has completed */
1231215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_TX_BELL(srio_port), cvmx_sriox_tx_bell_t, pending, ==, 0, CVMX_SRIO_DOORBELL_TIMEOUT))
1232215976Sjmallett    {
1233215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before doorbell\n", srio_port);
1234215976Sjmallett        return -1;
1235215976Sjmallett    }
1236215976Sjmallett
1237215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1238215976Sjmallett        cvmx_dprintf("SRIO%d: Send doorbell destid=0x%x, priority=%d, data=0x%x\n", srio_port, destid, priority, 0xffff & data);
1239215976Sjmallett
1240215976Sjmallett    /* Send the doorbell. We don't wait for it to complete. The next doorbell
1241215976Sjmallett        may delay on the pending bit, but this gives the caller the ability to
1242215976Sjmallett        do other stuff while the doorbell processes */
1243215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_TX_BELL(srio_port), tx_bell.u64);
1244215976Sjmallett    return 0;
1245215976Sjmallett}
1246232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1247232812SjmallettEXPORT_SYMBOL(cvmx_srio_send_doorbell);
1248232812Sjmallett#endif
1249215976Sjmallett
1250215976Sjmallett/**
1251215976Sjmallett * Get the status of the last doorbell sent. If the dooorbell
1252215976Sjmallett * hardware is done, then the status is cleared to get ready for
1253215976Sjmallett * the next doorbell (or retry).
1254215976Sjmallett *
1255215976Sjmallett * @param srio_port SRIO port to check doorbell on
1256215976Sjmallett *
1257215976Sjmallett * @return Doorbell status
1258215976Sjmallett */
1259215976Sjmallettcvmx_srio_doorbell_status_t cvmx_srio_send_doorbell_status(int srio_port)
1260215976Sjmallett{
1261215976Sjmallett    cvmx_sriox_tx_bell_t tx_bell;
1262215976Sjmallett    cvmx_sriox_tx_bell_info_t tx_bell_info;
1263215976Sjmallett    cvmx_sriox_int_reg_t int_reg;
1264215976Sjmallett    cvmx_sriox_int_reg_t int_reg_clear;
1265215976Sjmallett
1266215976Sjmallett    /* Return busy if the doorbell is still processing */
1267215976Sjmallett    tx_bell.u64 = cvmx_read_csr(CVMX_SRIOX_TX_BELL(srio_port));
1268215976Sjmallett    if (tx_bell.s.pending)
1269215976Sjmallett        return CVMX_SRIO_DOORBELL_BUSY;
1270215976Sjmallett
1271215976Sjmallett    /* Read and clear the TX doorbell interrupts */
1272215976Sjmallett    int_reg.u64 = cvmx_read_csr(CVMX_SRIOX_INT_REG(srio_port));
1273215976Sjmallett    int_reg_clear.u64 = 0;
1274215976Sjmallett    int_reg_clear.s.bell_err = int_reg.s.bell_err;
1275215976Sjmallett    int_reg_clear.s.txbell = int_reg.s.txbell;
1276215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_INT_REG(srio_port), int_reg_clear.u64);
1277215976Sjmallett
1278215976Sjmallett    /* Check for errors */
1279215976Sjmallett    if (int_reg.s.bell_err)
1280215976Sjmallett    {
1281215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1282215976Sjmallett            cvmx_dprintf("SRIO%d: Send doorbell failed\n", srio_port);
1283215976Sjmallett        tx_bell_info.u64 = cvmx_read_csr(CVMX_SRIOX_TX_BELL_INFO(srio_port));
1284232812Sjmallett        if (tx_bell_info.s.timeout)
1285232812Sjmallett            return CVMX_SRIO_DOORBELL_TMOUT;
1286232812Sjmallett        if (tx_bell_info.s.error)
1287215976Sjmallett            return CVMX_SRIO_DOORBELL_ERROR;
1288215976Sjmallett        if (tx_bell_info.s.retry)
1289215976Sjmallett            return CVMX_SRIO_DOORBELL_RETRY;
1290215976Sjmallett    }
1291215976Sjmallett
1292215976Sjmallett    /* Check if we're done */
1293215976Sjmallett    if (int_reg.s.txbell)
1294215976Sjmallett        return CVMX_SRIO_DOORBELL_DONE;
1295215976Sjmallett
1296215976Sjmallett    /* No doorbell found */
1297215976Sjmallett    return CVMX_SRIO_DOORBELL_NONE;
1298215976Sjmallett}
1299215976Sjmallett
1300215976Sjmallett
1301215976Sjmallett/**
1302215976Sjmallett * Read a received doorbell and report data about it.
1303215976Sjmallett *
1304215976Sjmallett * @param srio_port SRIO port to check for the received doorbell
1305215976Sjmallett * @param destid_index
1306215976Sjmallett *                  Which Octeon destination ID was the doorbell for
1307215976Sjmallett * @param sequence_num
1308215976Sjmallett *                  Sequence number of doorbell (32bits)
1309215976Sjmallett * @param srcid     RapidIO source ID of the doorbell sender
1310215976Sjmallett * @param priority  Priority of the doorbell (0-3)
1311215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1312215976Sjmallett *                  if transactions should use 8bit device IDs.
1313215976Sjmallett * @param data      Data in the doorbell (16 bits)
1314215976Sjmallett *
1315215976Sjmallett * @return Doorbell status. Either DONE, NONE, or ERROR.
1316215976Sjmallett */
1317215976Sjmallettcvmx_srio_doorbell_status_t cvmx_srio_receive_doorbell(int srio_port,
1318215976Sjmallett        int *destid_index, uint32_t *sequence_num, int *srcid, int *priority,
1319215976Sjmallett        int *is16bit, uint16_t *data)
1320215976Sjmallett{
1321215976Sjmallett    cvmx_sriox_rx_bell_seq_t rx_bell_seq;
1322215976Sjmallett    cvmx_sriox_rx_bell_t rx_bell;
1323215976Sjmallett
1324215976Sjmallett    /* Check if there are any pending doorbells */
1325215976Sjmallett    rx_bell_seq.u64 = cvmx_read_csr(CVMX_SRIOX_RX_BELL_SEQ(srio_port));
1326215976Sjmallett    if (!rx_bell_seq.s.count)
1327215976Sjmallett        return CVMX_SRIO_DOORBELL_NONE;
1328215976Sjmallett
1329215976Sjmallett    /* Read the doorbell and write our return parameters */
1330215976Sjmallett    rx_bell.u64 = cvmx_read_csr(CVMX_SRIOX_RX_BELL(srio_port));
1331215976Sjmallett    *sequence_num = rx_bell_seq.s.seq;
1332215976Sjmallett    *srcid = rx_bell.s.src_id;
1333215976Sjmallett    *priority = rx_bell.s.priority;
1334215976Sjmallett    *is16bit = rx_bell.s.id16;
1335215976Sjmallett    *data = rx_bell.s.data;
1336215976Sjmallett    *destid_index = rx_bell.s.dest_id;
1337215976Sjmallett
1338215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1339215976Sjmallett        cvmx_dprintf("SRIO%d: Receive doorbell sequence=0x%x, srcid=0x%x, priority=%d, data=0x%x\n",
1340215976Sjmallett            srio_port, rx_bell_seq.s.seq, rx_bell.s.src_id, rx_bell.s.priority, rx_bell.s.data);
1341215976Sjmallett
1342215976Sjmallett    return CVMX_SRIO_DOORBELL_DONE;
1343215976Sjmallett}
1344215976Sjmallett
1345215976Sjmallett
1346215976Sjmallett/**
1347215976Sjmallett * Receive a packet from the Soft Packet FIFO (SPF).
1348215976Sjmallett *
1349215976Sjmallett * @param srio_port SRIO port to read the packet from.
1350215976Sjmallett * @param buffer    Buffer to receive the packet.
1351215976Sjmallett * @param buffer_length
1352215976Sjmallett *                  Length of the buffer in bytes.
1353215976Sjmallett *
1354215976Sjmallett * @return Returns the length of the packet read. Negative on failure.
1355215976Sjmallett *         Zero if no packets are available.
1356215976Sjmallett */
1357215976Sjmallettint cvmx_srio_receive_spf(int srio_port, void *buffer, int buffer_length)
1358215976Sjmallett{
1359215976Sjmallett    uint32_t *ptr = (uint32_t *)buffer;
1360215976Sjmallett    cvmx_sriomaintx_ir_sp_rx_stat_t sriomaintx_ir_sp_rx_stat;
1361215976Sjmallett
1362215976Sjmallett    /* Read the SFP status */
1363215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_IR_SP_RX_STAT(srio_port), &sriomaintx_ir_sp_rx_stat.u32))
1364215976Sjmallett        return -1;
1365215976Sjmallett
1366215976Sjmallett    /* Return zero if there isn't a packet available */
1367215976Sjmallett    if (sriomaintx_ir_sp_rx_stat.s.buffers < 1)
1368215976Sjmallett        return 0;
1369215976Sjmallett
1370215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1371215976Sjmallett        cvmx_dprintf("SRIO%d: Soft packet FIFO received %d bytes", srio_port, sriomaintx_ir_sp_rx_stat.s.octets);
1372215976Sjmallett
1373215976Sjmallett    /* Return error if the packet is larger than our buffer */
1374215976Sjmallett    if (sriomaintx_ir_sp_rx_stat.s.octets > buffer_length)
1375215976Sjmallett        return -1;
1376215976Sjmallett
1377215976Sjmallett    /* Read out the packet four bytes at a time */
1378215976Sjmallett    buffer_length = sriomaintx_ir_sp_rx_stat.s.octets;
1379215976Sjmallett    while (buffer_length > 0)
1380215976Sjmallett    {
1381215976Sjmallett        __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_IR_SP_RX_DATA(srio_port), ptr);
1382215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1383215976Sjmallett            cvmx_dprintf(" %08x", (unsigned int)*ptr);
1384215976Sjmallett        ptr++;
1385215976Sjmallett        buffer_length-=4;
1386215976Sjmallett    }
1387215976Sjmallett
1388215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1389215976Sjmallett        cvmx_dprintf("\n");
1390215976Sjmallett
1391215976Sjmallett    /* Return the number of bytes in the buffer */
1392215976Sjmallett    return sriomaintx_ir_sp_rx_stat.s.octets;
1393215976Sjmallett}
1394215976Sjmallett
1395215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
1396215976Sjmallett/**
1397215976Sjmallett * Map a remote device's memory region into Octeon's physical
1398215976Sjmallett * address area. The caller can then map this into a core using
1399215976Sjmallett * the TLB or XKPHYS.
1400215976Sjmallett *
1401215976Sjmallett * @param srio_port SRIO port to map the device on
1402215976Sjmallett * @param write_op  Type of operation to perform on a write to the device.
1403215976Sjmallett *                  Normally should be CVMX_SRIO_WRITE_MODE_AUTO.
1404215976Sjmallett * @param write_priority
1405215976Sjmallett *                  SRIO priority of writes (0-3)
1406215976Sjmallett * @param read_op   Type of operation to perform on reads to the device.
1407215976Sjmallett *                  Normally should be CVMX_SRIO_READ_MODE_NORMAL.
1408215976Sjmallett * @param read_priority
1409215976Sjmallett *                  SRIO priority of reads (0-3)
1410215976Sjmallett * @param srcid_index
1411215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
1412215976Sjmallett * @param destid    RapidIO device ID.
1413215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1414215976Sjmallett *                  if transactions should use 8bit device IDs.
1415215976Sjmallett * @param base      Device base address to start the mapping
1416215976Sjmallett * @param size      Size of the mapping in bytes
1417215976Sjmallett *
1418215976Sjmallett * @return Octeon 64bit physical address that accesses the remote device,
1419215976Sjmallett *         or zero on failure.
1420215976Sjmallett */
1421215976Sjmallettuint64_t cvmx_srio_physical_map(int srio_port, cvmx_srio_write_mode_t write_op,
1422215976Sjmallett        int write_priority, cvmx_srio_read_mode_t read_op, int read_priority,
1423215976Sjmallett        int srcid_index, int destid, int is16bit, uint64_t base, uint64_t size)
1424215976Sjmallett{
1425215976Sjmallett    cvmx_sriox_s2m_typex_t needed_s2m_type;
1426215976Sjmallett    cvmx_sli_mem_access_subidx_t needed_subid;
1427215976Sjmallett    int s2m_index;
1428215976Sjmallett    int subdid;
1429215976Sjmallett    cvmx_sli_address_t sli_address;
1430215976Sjmallett
1431215976Sjmallett    /* We currently don't support mapping regions that span a 34 bit boundary.
1432215976Sjmallett        Keeping track of multiple regions to span 34 bits is hard and not
1433215976Sjmallett        likely to be needed */
1434215976Sjmallett    if (((base+size-1)>>34) != (base>>34))
1435215976Sjmallett    {
1436215976Sjmallett        cvmx_dprintf("SRIO%d: Failed to map range 0x%llx-0x%llx spanning a 34bit boundary\n",
1437215976Sjmallett            srio_port, (ULL)base, (ULL)base+size-1);
1438215976Sjmallett        return 0;
1439215976Sjmallett    }
1440215976Sjmallett
1441215976Sjmallett    /* Build the S2M_TYPE we are going to need */
1442215976Sjmallett    needed_s2m_type.u64 = 0;
1443215976Sjmallett    needed_s2m_type.s.wr_op = write_op;
1444215976Sjmallett    needed_s2m_type.s.rd_op = read_op;
1445215976Sjmallett    needed_s2m_type.s.wr_prior = write_priority;
1446215976Sjmallett    needed_s2m_type.s.rd_prior = read_priority;
1447215976Sjmallett    needed_s2m_type.s.src_id = srcid_index;
1448215976Sjmallett    needed_s2m_type.s.id16 = !!is16bit;
1449215976Sjmallett
1450215976Sjmallett    /* Build the needed SubID config */
1451215976Sjmallett    needed_subid.u64 = 0;
1452215976Sjmallett    needed_subid.s.port = srio_port;
1453232812Sjmallett    needed_subid.s.nmerge = 0;
1454215976Sjmallett
1455215976Sjmallett    /* FIXME: We might want to use the device ID swapping modes so the device
1456215976Sjmallett        ID is part of the lower address bits. This would allow many more
1457215976Sjmallett        devices to share S2M_TYPE indexes. This would require "base+size-1"
1458215976Sjmallett        to fit in bits [17:0] or bits[25:0] for 8 bits of device ID */
1459215976Sjmallett    if (base < (1ull<<34))
1460215976Sjmallett    {
1461232812Sjmallett        needed_subid.cn63xx.ba = destid;
1462215976Sjmallett        needed_s2m_type.s.iaow_sel = 0;
1463215976Sjmallett    }
1464215976Sjmallett    else if (base < (1ull<<42))
1465215976Sjmallett    {
1466232812Sjmallett        needed_subid.cn63xx.ba = (base>>34) & 0xff;
1467232812Sjmallett        needed_subid.cn63xx.ba |= ((uint64_t)destid & 0xff) << (42-34);
1468232812Sjmallett        needed_subid.cn63xx.ba |= (((uint64_t)destid>>8) & 0xff) << (51-34);
1469215976Sjmallett        needed_s2m_type.s.iaow_sel = 1;
1470215976Sjmallett    }
1471215976Sjmallett    else
1472215976Sjmallett    {
1473215976Sjmallett        if (destid>>8)
1474215976Sjmallett        {
1475215976Sjmallett            cvmx_dprintf("SRIO%d: Attempt to map 16bit device ID 0x%x using 66bit addressing\n", srio_port, destid);
1476215976Sjmallett            return 0;
1477215976Sjmallett        }
1478215976Sjmallett        if (base>>50)
1479215976Sjmallett        {
1480215976Sjmallett            cvmx_dprintf("SRIO%d: Attempt to map address 0x%llx using 66bit addressing\n", srio_port, (ULL)base);
1481215976Sjmallett            return 0;
1482215976Sjmallett        }
1483232812Sjmallett        needed_subid.cn63xx.ba = (base>>34) & 0xffff;
1484232812Sjmallett        needed_subid.cn63xx.ba |= ((uint64_t)destid & 0xff) << (51-34);
1485215976Sjmallett        needed_s2m_type.s.iaow_sel = 2;
1486215976Sjmallett    }
1487215976Sjmallett
1488215976Sjmallett    /* Find a S2M_TYPE index to use. If this fails return 0 */
1489215976Sjmallett    s2m_index = __cvmx_srio_alloc_s2m(srio_port, needed_s2m_type);
1490215976Sjmallett    if (s2m_index == -1)
1491215976Sjmallett        return 0;
1492215976Sjmallett
1493215976Sjmallett    /* Attach the SubID to the S2M_TYPE index */
1494215976Sjmallett    needed_subid.s.rtype = s2m_index & 3;
1495215976Sjmallett    needed_subid.s.wtype = s2m_index & 3;
1496232812Sjmallett    needed_subid.cn63xx.ba |= (((uint64_t)s2m_index >> 2) & 1) << (50-34);
1497232812Sjmallett    needed_subid.cn63xx.ba |= (((uint64_t)s2m_index >> 3) & 1) << (59-34);
1498215976Sjmallett
1499215976Sjmallett    /* Allocate a SubID for use */
1500215976Sjmallett    subdid = __cvmx_srio_alloc_subid(needed_subid);
1501215976Sjmallett    if (subdid == -1)
1502215976Sjmallett    {
1503215976Sjmallett        /* Free the s2m_index as we aren't using it */
1504215976Sjmallett        __cvmx_srio_free_s2m(srio_port, s2m_index);
1505215976Sjmallett        return 0;
1506215976Sjmallett    }
1507215976Sjmallett
1508215976Sjmallett    /* Build the final core physical address */
1509215976Sjmallett    sli_address.u64 = 0;
1510215976Sjmallett    sli_address.mem.io = 1;
1511215976Sjmallett    sli_address.mem.did = 3;
1512215976Sjmallett    sli_address.mem.subdid = subdid>>2;
1513215976Sjmallett    sli_address.mem.se = subdid & 3;
1514215976Sjmallett    sli_address.mem.address = base; /* Bits[33:0] of full address */
1515215976Sjmallett    return sli_address.u64;
1516215976Sjmallett}
1517215976Sjmallett
1518215976Sjmallett
1519215976Sjmallett/**
1520215976Sjmallett * Unmap a physical address window created by cvmx_srio_phys_map().
1521215976Sjmallett *
1522215976Sjmallett * @param physical_address
1523215976Sjmallett *               Physical address returned by cvmx_srio_phys_map().
1524215976Sjmallett * @param size   Size used on original call.
1525215976Sjmallett *
1526215976Sjmallett * @return Zero on success, negative on failure.
1527215976Sjmallett */
1528215976Sjmallettint cvmx_srio_physical_unmap(uint64_t physical_address, uint64_t size)
1529215976Sjmallett{
1530215976Sjmallett    cvmx_sli_mem_access_subidx_t subid;
1531215976Sjmallett    int subdid = (physical_address >> 40) & 7;
1532215976Sjmallett    int extender = (physical_address >> 34) & 3;
1533215976Sjmallett    int mem_index = subdid * 4 + extender;
1534215976Sjmallett    int read_s2m_type;
1535215976Sjmallett
1536215976Sjmallett    /* Get the subid setup so we can figure out where this mapping was for */
1537215976Sjmallett    subid.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index));
1538215976Sjmallett    /* Type[0] is mapped to the Relaxed Ordering
1539215976Sjmallett       Type[1] is mapped to the No Snoop
1540215976Sjmallett       Type[2] is mapped directly to bit 50 of the SLI address
1541215976Sjmallett       Type[3] is mapped directly to bit 59 of the SLI address */
1542232812Sjmallett    read_s2m_type = ((subid.cn63xx.ba>>(50-34))&1<<2) | ((subid.cn63xx.ba>>(59-34))&1<<3);
1543215976Sjmallett    read_s2m_type |= subid.s.rtype;
1544215976Sjmallett    __cvmx_srio_free_subid(mem_index);
1545215976Sjmallett    __cvmx_srio_free_s2m(subid.s.port, read_s2m_type);
1546215976Sjmallett    return 0;
1547215976Sjmallett}
1548232812Sjmallett
1549232812Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
1550232812Sjmallett/**
1551232812Sjmallett * fill out outbound message descriptor
1552232812Sjmallett *
1553232812Sjmallett * @param port        pip/ipd port number
1554232812Sjmallett * @param buf_ptr     pointer to a buffer pointer. the buffer pointer points
1555232812Sjmallett *                    to a chain of buffers that hold an outbound srio packet.
1556232812Sjmallett *                    the packet can take the format of (1) a pip/ipd inbound
1557232812Sjmallett *                    message or (2) an application-generated outbound message
1558232812Sjmallett * @param desc_ptr    pointer to an outbound message descriptor. should be null
1559232812Sjmallett *                    if *buf_ptr is in the format (1)
1560232812Sjmallett *
1561232812Sjmallett * @return           0 on success; negative of failure.
1562232812Sjmallett */
1563232812Sjmallettint cvmx_srio_omsg_desc (uint64_t port, cvmx_buf_ptr_t *buf_ptr,
1564232812Sjmallett                         cvmx_srio_tx_message_header_t *desc_ptr)
1565232812Sjmallett{
1566232812Sjmallett    int ret_val = -1;
1567232812Sjmallett    int intf_num;
1568232812Sjmallett    cvmx_helper_interface_mode_t imode;
1569232812Sjmallett
1570232812Sjmallett    uint64_t *desc_addr, *hdr_addr;
1571232812Sjmallett    cvmx_srio_rx_message_header_t rx_msg_hdr;
1572232812Sjmallett    cvmx_srio_tx_message_header_t *tx_msg_hdr_ptr;
1573232812Sjmallett
1574232812Sjmallett    if (buf_ptr == NULL)
1575232812Sjmallett        return ret_val;
1576232812Sjmallett
1577232812Sjmallett    /* check if port is an srio port */
1578232812Sjmallett    intf_num = cvmx_helper_get_interface_num (port);
1579232812Sjmallett    imode = cvmx_helper_interface_get_mode (intf_num);
1580232812Sjmallett    if (imode !=  CVMX_HELPER_INTERFACE_MODE_SRIO)
1581232812Sjmallett        return ret_val;
1582232812Sjmallett
1583232812Sjmallett    /* app-generated outbound message. descriptor space pre-allocated */
1584232812Sjmallett    if (desc_ptr != NULL)
1585232812Sjmallett    {
1586232812Sjmallett        desc_addr = (uint64_t *) cvmx_phys_to_ptr ((*buf_ptr).s.addr);
1587232812Sjmallett        *desc_addr = *(uint64_t *) desc_ptr;
1588232812Sjmallett        ret_val = 0;
1589232812Sjmallett        return ret_val;
1590232812Sjmallett    }
1591232812Sjmallett
1592232812Sjmallett    /* pip/ipd inbound message. 16-byte srio message header is present */
1593232812Sjmallett    hdr_addr = (uint64_t *) cvmx_phys_to_ptr ((*buf_ptr).s.addr);
1594232812Sjmallett    rx_msg_hdr.word0.u64 = *hdr_addr;
1595232812Sjmallett
1596232812Sjmallett    /* adjust buffer pointer to get rid of srio message header word 0 */
1597232812Sjmallett    (*buf_ptr).s.addr += 8;
1598232812Sjmallett    (*buf_ptr).s.size -= 8; /* last buffer or not */
1599232812Sjmallett    if ((*buf_ptr).s.addr >> 7 > ((*buf_ptr).s.addr - 8) >> 7)
1600232812Sjmallett        (*buf_ptr).s.back++;
1601232812Sjmallett    tx_msg_hdr_ptr = (cvmx_srio_tx_message_header_t *)
1602232812Sjmallett                         cvmx_phys_to_ptr ((*buf_ptr).s.addr);
1603232812Sjmallett
1604232812Sjmallett    /* transfer values from rx to tx */
1605232812Sjmallett    tx_msg_hdr_ptr->s.prio = rx_msg_hdr.word0.s.prio;
1606232812Sjmallett    tx_msg_hdr_ptr->s.tt = rx_msg_hdr.word0.s.tt; /* called id in hrm */
1607232812Sjmallett    tx_msg_hdr_ptr->s.sis = rx_msg_hdr.word0.s.dis;
1608232812Sjmallett    tx_msg_hdr_ptr->s.ssize = rx_msg_hdr.word0.s.ssize;
1609232812Sjmallett    tx_msg_hdr_ptr->s.did = rx_msg_hdr.word0.s.sid;
1610232812Sjmallett    tx_msg_hdr_ptr->s.mbox = rx_msg_hdr.word0.s.mbox;
1611232812Sjmallett
1612232812Sjmallett    /* other values we have to decide */
1613232812Sjmallett    tx_msg_hdr_ptr->s.xmbox = 0;  /* multi-segement in general */
1614232812Sjmallett    tx_msg_hdr_ptr->s.letter = 0; /* fake like traffic gen */
1615232812Sjmallett    tx_msg_hdr_ptr->s.lns = 0;    /* not use sriox_omsg_ctrly[] */
1616232812Sjmallett    tx_msg_hdr_ptr->s.intr = 1;   /* get status */
1617232812Sjmallett
1618232812Sjmallett    ret_val = 0;
1619232812Sjmallett    return ret_val;
1620232812Sjmallett}
1621215976Sjmallett#endif
1622232812Sjmallett#endif
1623