1215976Sjmallett/***********************license start***************
2215976Sjmallett * Copyright (c) 2003-2010  Cavium Networks (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
18215976Sjmallett *   * Neither the name of Cavium Networks 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"
29215976Sjmallett * AND WITH ALL FAULTS AND CAVIUM  NETWORKS 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>
63215976Sjmallett#else
64215976Sjmallett#include "cvmx.h"
65215976Sjmallett#include "cvmx-srio.h"
66215976Sjmallett#include "cvmx-clock.h"
67215976Sjmallett#include "cvmx-helper.h"
68215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
69215976Sjmallett#include "cvmx-atomic.h"
70215976Sjmallett#include "cvmx-error.h"
71215976Sjmallett#include "cvmx-helper-errata.h"
72215976Sjmallett#endif
73215976Sjmallett#endif
74215976Sjmallett
75215976Sjmallett#define CVMX_SRIO_USE_FIFO_FOR_MAINT    1
76215976Sjmallett#define CVMX_SRIO_CONFIG_TIMEOUT        10000 /* 10ms */
77215976Sjmallett#define CVMX_SRIO_DOORBELL_TIMEOUT      10000 /* 10ms */
78215976Sjmallett#define CVMX_SRIO_CONFIG_PRIORITY       0
79215976Sjmallett#define ULL unsigned long long
80215976Sjmallett
81215976Sjmalletttypedef union
82215976Sjmallett{
83215976Sjmallett    uint64_t    u64;
84215976Sjmallett    struct
85215976Sjmallett    {
86215976Sjmallett#if __BYTE_ORDER == __BIG_ENDIAN
87215976Sjmallett        uint64_t    upper           : 2;    /* Normally 2 for XKPHYS */
88215976Sjmallett        uint64_t    reserved_49_61  : 13;   /* Must be zero */
89215976Sjmallett        uint64_t    io              : 1;    /* 1 for IO space access */
90215976Sjmallett        uint64_t    did             : 5;    /* DID = 3 */
91215976Sjmallett        uint64_t    subdid          : 3;    /* SubDID = 3-6 */
92215976Sjmallett        uint64_t    reserved_36_39  : 4;    /* Must be zero */
93215976Sjmallett        uint64_t    se              : 2;    /* SubDID extender */
94215976Sjmallett        uint64_t    reserved_32_33  : 2;    /* Must be zero */
95215976Sjmallett        uint64_t    hopcount        : 8;    /* Hopcount */
96215976Sjmallett        uint64_t    address         : 24;   /* Mem address */
97215976Sjmallett#else
98215976Sjmallett        uint64_t    address         : 24;
99215976Sjmallett        uint64_t    hopcount        : 8;
100215976Sjmallett        uint64_t    reserved_32_33  : 2;
101215976Sjmallett        uint64_t    se              : 2;
102215976Sjmallett        uint64_t    reserved_36_39  : 4;
103215976Sjmallett        uint64_t    subdid          : 3;
104215976Sjmallett        uint64_t    did             : 5;
105215976Sjmallett        uint64_t    io              : 1;
106215976Sjmallett        uint64_t    reserved_49_61  : 13;
107215976Sjmallett        uint64_t    upper           : 2;
108215976Sjmallett#endif
109215976Sjmallett    } config;
110215976Sjmallett    struct
111215976Sjmallett    {
112215976Sjmallett#if __BYTE_ORDER == __BIG_ENDIAN
113215976Sjmallett        uint64_t    upper           : 2;    /* Normally 2 for XKPHYS */
114215976Sjmallett        uint64_t    reserved_49_61  : 13;   /* Must be zero */
115215976Sjmallett        uint64_t    io              : 1;    /* 1 for IO space access */
116215976Sjmallett        uint64_t    did             : 5;    /* DID = 3 */
117215976Sjmallett        uint64_t    subdid          : 3;    /* SubDID = 3-6 */
118215976Sjmallett        uint64_t    reserved_36_39  : 4;    /* Must be zero */
119215976Sjmallett        uint64_t    se              : 2;    /* SubDID extender */
120215976Sjmallett        uint64_t    address         : 34;   /* Mem address */
121215976Sjmallett#else
122215976Sjmallett        uint64_t    address         : 34;
123215976Sjmallett        uint64_t    se              : 2;
124215976Sjmallett        uint64_t    reserved_36_39  : 4;
125215976Sjmallett        uint64_t    subdid          : 3;
126215976Sjmallett        uint64_t    did             : 5;
127215976Sjmallett        uint64_t    io              : 1;
128215976Sjmallett        uint64_t    reserved_49_61  : 13;
129215976Sjmallett        uint64_t    upper           : 2;
130215976Sjmallett#endif
131215976Sjmallett    } mem;
132215976Sjmallett} cvmx_sli_address_t;
133215976Sjmallett
134215976Sjmalletttypedef struct
135215976Sjmallett{
136215976Sjmallett    cvmx_srio_initialize_flags_t flags;
137215976Sjmallett    int32_t subidx_ref_count[16];   /* Reference count for SLI_MEM_ACCESS_SUBID[12-27]. Index=X-12 */
138215976Sjmallett    int32_t s2m_ref_count[16];   /* Reference count for SRIOX_S2M_TYPE[0-15]. */
139215976Sjmallett} __cvmx_srio_state_t;
140215976Sjmallett
141215976Sjmallettstatic CVMX_SHARED __cvmx_srio_state_t __cvmx_srio_state[2];
142215976Sjmallett
143215976Sjmallett
144215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
145215976Sjmallett/**
146215976Sjmallett * @INTERNAL
147215976Sjmallett * Allocate a SRIOX_S2M_TYPEX register for mapping a remote SRIO
148215976Sjmallett * device's address range into Octeons SLI address space. Reference
149215976Sjmallett * counting is used to allow sharing of duplicate setups. The current
150215976Sjmallett * implementation treats reads and writes as paired, but this could be
151215976Sjmallett * changed if we have trouble running out of indexes.
152215976Sjmallett *
153215976Sjmallett * @param srio_port SRIO port device is on
154215976Sjmallett * @param s2m       SRIOX_S2M_TYPEX setup required
155215976Sjmallett *
156215976Sjmallett * @return Index of CSR, or negative on failure
157215976Sjmallett */
158215976Sjmallettstatic int __cvmx_srio_alloc_s2m(int srio_port, cvmx_sriox_s2m_typex_t s2m)
159215976Sjmallett{
160215976Sjmallett    int s2m_index;
161215976Sjmallett    /* Search through the S2M_TYPE registers looking for an unsed one or one
162215976Sjmallett        setup the way we need it */
163215976Sjmallett    for (s2m_index=0; s2m_index<16; s2m_index++)
164215976Sjmallett    {
165215976Sjmallett        /* Increment ref count by 2 since we count read and write
166215976Sjmallett            independently. We might need a more complicated search in the
167215976Sjmallett            future */
168215976Sjmallett        int ref_count = cvmx_atomic_fetch_and_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[s2m_index], 2);
169215976Sjmallett        if (ref_count == 0)
170215976Sjmallett        {
171215976Sjmallett            /* Unused location. Write our value */
172215976Sjmallett            cvmx_write_csr(CVMX_SRIOX_S2M_TYPEX(s2m_index, srio_port), s2m.u64);
173215976Sjmallett            return s2m_index;
174215976Sjmallett        }
175215976Sjmallett        else
176215976Sjmallett        {
177215976Sjmallett            /* In use, see if we can use it */
178215976Sjmallett            if (cvmx_read_csr(CVMX_SRIOX_S2M_TYPEX(s2m_index, srio_port)) == s2m.u64)
179215976Sjmallett                return s2m_index;
180215976Sjmallett            else
181215976Sjmallett                cvmx_atomic_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[s2m_index], -2);
182215976Sjmallett        }
183215976Sjmallett    }
184215976Sjmallett    cvmx_dprintf("SRIO%d: Unable to find free SRIOX_S2M_TYPEX\n", srio_port);
185215976Sjmallett    return -1;
186215976Sjmallett}
187215976Sjmallett
188215976Sjmallett
189215976Sjmallett/**
190215976Sjmallett * @INTERNAL
191215976Sjmallett * Free a handle allocated by __cvmx_srio_alloc_s2m
192215976Sjmallett *
193215976Sjmallett * @param srio_port SRIO port
194215976Sjmallett * @param index     Index to free
195215976Sjmallett */
196215976Sjmallettstatic void __cvmx_srio_free_s2m(int srio_port, int index)
197215976Sjmallett{
198215976Sjmallett    /* Read to force pending transactions to complete */
199215976Sjmallett    cvmx_read_csr(CVMX_SRIOX_S2M_TYPEX(index, srio_port));
200215976Sjmallett    cvmx_atomic_add32(&__cvmx_srio_state[srio_port].s2m_ref_count[index], -2);
201215976Sjmallett}
202215976Sjmallett
203215976Sjmallett
204215976Sjmallett/**
205215976Sjmallett * @INTERNAL
206215976Sjmallett * Allocate a SLI SubID to map a region of memory. Reference
207215976Sjmallett * counting is used to allow sharing of duplicate setups.
208215976Sjmallett *
209215976Sjmallett * @param subid  SLI_MEM_ACCESS_SUBIDX we need an index for
210215976Sjmallett *
211215976Sjmallett * @return Index of CSR, or negative on failure
212215976Sjmallett */
213215976Sjmallettstatic int __cvmx_srio_alloc_subid(cvmx_sli_mem_access_subidx_t subid)
214215976Sjmallett{
215215976Sjmallett    int mem_index;
216215976Sjmallett    /* Search through the mem access subid registers looking for an unsed one
217215976Sjmallett        or one setup the way we need it. PCIe uses the low indexes, so search
218215976Sjmallett        backwards */
219215976Sjmallett    for (mem_index=27; mem_index>=12; mem_index--)
220215976Sjmallett    {
221215976Sjmallett        int ref_count = cvmx_atomic_fetch_and_add32(&__cvmx_srio_state[0].subidx_ref_count[mem_index-12], 1);
222215976Sjmallett        if (ref_count == 0)
223215976Sjmallett        {
224215976Sjmallett            /* Unused location. Write our value */
225215976Sjmallett            cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index), subid.u64);
226215976Sjmallett            return mem_index;
227215976Sjmallett        }
228215976Sjmallett        else
229215976Sjmallett        {
230215976Sjmallett            /* In use, see if we can use it */
231215976Sjmallett            if (cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index)) == subid.u64)
232215976Sjmallett                return mem_index;
233215976Sjmallett            else
234215976Sjmallett                cvmx_atomic_add32(&__cvmx_srio_state[0].subidx_ref_count[mem_index-12], -1);
235215976Sjmallett        }
236215976Sjmallett    }
237215976Sjmallett    cvmx_dprintf("SRIO: Unable to find free SLI_MEM_ACCESS_SUBIDX\n");
238215976Sjmallett    return -1;
239215976Sjmallett}
240215976Sjmallett
241215976Sjmallett
242215976Sjmallett/**
243215976Sjmallett * @INTERNAL
244215976Sjmallett * Free a handle allocated by __cvmx_srio_alloc_subid
245215976Sjmallett *
246215976Sjmallett * @param index  Index to free
247215976Sjmallett */
248215976Sjmallettstatic void __cvmx_srio_free_subid(int index)
249215976Sjmallett{
250215976Sjmallett    /* Read to force pending transactions to complete */
251215976Sjmallett    cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(index));
252215976Sjmallett    cvmx_atomic_add32(&__cvmx_srio_state[0].subidx_ref_count[index-12], -1);
253215976Sjmallett}
254215976Sjmallett#endif
255215976Sjmallett
256215976Sjmallett
257215976Sjmallett/**
258215976Sjmallett * @INTERNAL
259215976Sjmallett * Read 32bits from a local port
260215976Sjmallett *
261215976Sjmallett * @param srio_port SRIO port the device is on
262215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
263215976Sjmallett * @param result    Result of the read. This will be unmodified on failure.
264215976Sjmallett *
265215976Sjmallett * @return Zero on success, negative on failure.
266215976Sjmallett */
267215976Sjmallettstatic int __cvmx_srio_local_read32(int srio_port, uint32_t offset, uint32_t *result)
268215976Sjmallett{
269215976Sjmallett    cvmx_sriox_maint_op_t maint_op;
270215976Sjmallett    cvmx_sriox_maint_rd_data_t maint_rd_data;
271215976Sjmallett    maint_op.u64 = 0;
272215976Sjmallett    maint_op.s.op = 0; /* Read */
273215976Sjmallett    maint_op.s.addr = offset;
274215976Sjmallett
275215976Sjmallett    /* Make sure SRIO isn't already busy */
276215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
277215976Sjmallett    {
278215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before config read\n", srio_port);
279215976Sjmallett        return -1;
280215976Sjmallett    }
281215976Sjmallett
282215976Sjmallett    /* Issue the read to the hardware */
283215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_MAINT_OP(srio_port), maint_op.u64);
284215976Sjmallett
285215976Sjmallett    /* Wait for the hardware to complete the operation */
286215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
287215976Sjmallett    {
288215976Sjmallett        cvmx_dprintf("SRIO%d: Config read timeout\n", srio_port);
289215976Sjmallett        return -1;
290215976Sjmallett    }
291215976Sjmallett
292215976Sjmallett    /* Display and error and return if the operation failed to issue */
293215976Sjmallett    maint_op.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_OP(srio_port));
294215976Sjmallett    if (maint_op.s.fail)
295215976Sjmallett    {
296215976Sjmallett        cvmx_dprintf("SRIO%d: Config read addressing error (offset=0x%x)\n", srio_port, (unsigned int)offset);
297215976Sjmallett        return -1;
298215976Sjmallett    }
299215976Sjmallett
300215976Sjmallett    /* Wait for the read data to become valid */
301215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_RD_DATA(srio_port), cvmx_sriox_maint_rd_data_t, valid, ==, 1, CVMX_SRIO_CONFIG_TIMEOUT))
302215976Sjmallett    {
303215976Sjmallett        cvmx_dprintf("SRIO%d: Config read data timeout\n", srio_port);
304215976Sjmallett        return -1;
305215976Sjmallett    }
306215976Sjmallett
307215976Sjmallett    /* Get the read data */
308215976Sjmallett    maint_rd_data.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_RD_DATA(srio_port));
309215976Sjmallett    *result = maint_rd_data.s.rd_data;
310215976Sjmallett    return 0;
311215976Sjmallett}
312215976Sjmallett
313215976Sjmallett
314215976Sjmallett/**
315215976Sjmallett * @INTERNAL
316215976Sjmallett * Write 32bits to a local port
317215976Sjmallett * @param srio_port SRIO port the device is on
318215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
319215976Sjmallett * @param data      Data to write.
320215976Sjmallett *
321215976Sjmallett * @return Zero on success, negative on failure.
322215976Sjmallett */
323215976Sjmallettstatic int __cvmx_srio_local_write32(int srio_port, uint32_t offset, uint32_t data)
324215976Sjmallett{
325215976Sjmallett    cvmx_sriox_maint_op_t maint_op;
326215976Sjmallett    maint_op.u64 = 0;
327215976Sjmallett    maint_op.s.wr_data = data;
328215976Sjmallett    maint_op.s.op = 1; /* Write */
329215976Sjmallett    maint_op.s.addr = offset;
330215976Sjmallett
331215976Sjmallett    /* Make sure SRIO isn't already busy */
332215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
333215976Sjmallett    {
334215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before config write\n", srio_port);
335215976Sjmallett        return -1;
336215976Sjmallett    }
337215976Sjmallett
338215976Sjmallett    /* Issue the write to the hardware */
339215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_MAINT_OP(srio_port), maint_op.u64);
340215976Sjmallett
341215976Sjmallett    /* Wait for the hardware to complete the operation */
342215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_MAINT_OP(srio_port), cvmx_sriox_maint_op_t, pending, ==, 0, CVMX_SRIO_CONFIG_TIMEOUT))
343215976Sjmallett    {
344215976Sjmallett        cvmx_dprintf("SRIO%d: Config write timeout\n", srio_port);
345215976Sjmallett        return -1;
346215976Sjmallett    }
347215976Sjmallett
348215976Sjmallett    /* Display and error and return if the operation failed to issue */
349215976Sjmallett    maint_op.u64 = cvmx_read_csr(CVMX_SRIOX_MAINT_OP(srio_port));
350215976Sjmallett    if (maint_op.s.fail)
351215976Sjmallett    {
352215976Sjmallett        cvmx_dprintf("SRIO%d: Config write addressing error (offset=0x%x)\n", srio_port, (unsigned int)offset);
353215976Sjmallett        return -1;
354215976Sjmallett    }
355215976Sjmallett    return 0;
356215976Sjmallett}
357215976Sjmallett
358215976Sjmallett
359215976Sjmallett/**
360215976Sjmallett * Initialize a SRIO port for use.
361215976Sjmallett *
362215976Sjmallett * @param srio_port SRIO port to initialize
363215976Sjmallett * @param flags     Optional flags
364215976Sjmallett *
365215976Sjmallett * @return Zero on success
366215976Sjmallett */
367215976Sjmallettint cvmx_srio_initialize(int srio_port, cvmx_srio_initialize_flags_t flags)
368215976Sjmallett{
369215976Sjmallett    cvmx_sriomaintx_port_lt_ctl_t port_lt_ctl;
370215976Sjmallett    cvmx_sriomaintx_port_rt_ctl_t port_rt_ctl;
371215976Sjmallett    cvmx_sriomaintx_port_0_ctl_t port_0_ctl;
372215976Sjmallett    cvmx_sriomaintx_core_enables_t core_enables;
373215976Sjmallett    cvmx_sriomaintx_port_gen_ctl_t port_gen_ctl;
374215976Sjmallett    cvmx_sriox_status_reg_t sriox_status_reg;
375215976Sjmallett    cvmx_mio_rst_ctlx_t mio_rst_ctl;
376215976Sjmallett    cvmx_sriox_imsg_vport_thr_t sriox_imsg_vport_thr;
377215976Sjmallett    cvmx_dpi_sli_prtx_cfg_t prt_cfg;
378215976Sjmallett    cvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;
379215976Sjmallett
380215976Sjmallett    sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(srio_port));
381215976Sjmallett    if (!sriox_status_reg.s.srio)
382215976Sjmallett    {
383215976Sjmallett        cvmx_dprintf("SRIO%d: Initialization called on a port not in SRIO mode\n", srio_port);
384215976Sjmallett        return -1;
385215976Sjmallett    }
386215976Sjmallett
387215976Sjmallett    __cvmx_srio_state[srio_port].flags = flags;
388215976Sjmallett
389215976Sjmallett    /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be
390215976Sjmallett        programmed */
391215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0))
392215976Sjmallett    {
393215976Sjmallett        if (srio_port)
394215976Sjmallett        {
395215976Sjmallett            cvmx_ciu_qlm1_t ciu_qlm;
396215976Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
397215976Sjmallett            ciu_qlm.s.txbypass = 1;
398215976Sjmallett            ciu_qlm.s.txdeemph = 5;
399215976Sjmallett            ciu_qlm.s.txmargin = 0x17;
400215976Sjmallett            cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
401215976Sjmallett        }
402215976Sjmallett        else
403215976Sjmallett        {
404215976Sjmallett            cvmx_ciu_qlm0_t ciu_qlm;
405215976Sjmallett            ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
406215976Sjmallett            ciu_qlm.s.txbypass = 1;
407215976Sjmallett            ciu_qlm.s.txdeemph = 5;
408215976Sjmallett            ciu_qlm.s.txmargin = 0x17;
409215976Sjmallett            cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
410215976Sjmallett        }
411215976Sjmallett    }
412215976Sjmallett
413215976Sjmallett    mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(srio_port));
414215976Sjmallett    cvmx_dprintf("SRIO%d: Port in %s mode\n", srio_port,
415215976Sjmallett        (mio_rst_ctl.s.prtmode) ? "host" : "endpoint");
416215976Sjmallett
417215976Sjmallett    /* Bring the port out of reset if necessary */
418215976Sjmallett    if (srio_port)
419215976Sjmallett    {
420215976Sjmallett        cvmx_ciu_soft_prst1_t prst;
421215976Sjmallett        prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
422215976Sjmallett        if (prst.s.soft_prst)
423215976Sjmallett        {
424215976Sjmallett            prst.s.soft_prst = 0;
425215976Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST1, prst.u64);
426215976Sjmallett            cvmx_wait_usec(10000); /* 10ms for new link to stabalize */
427215976Sjmallett        }
428215976Sjmallett    }
429215976Sjmallett    else
430215976Sjmallett    {
431215976Sjmallett        cvmx_ciu_soft_prst_t prst;
432215976Sjmallett        prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
433215976Sjmallett        if (prst.s.soft_prst)
434215976Sjmallett        {
435215976Sjmallett            prst.s.soft_prst = 0;
436215976Sjmallett            cvmx_write_csr(CVMX_CIU_SOFT_PRST, prst.u64);
437215976Sjmallett            cvmx_wait_usec(10000); /* 10ms for new link to stabalize */
438215976Sjmallett        }
439215976Sjmallett    }
440215976Sjmallett
441215976Sjmallett    /* Disable the link while we make changes */
442215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), &port_0_ctl.u32))
443215976Sjmallett        return -1;
444215976Sjmallett    port_0_ctl.s.disable = 1;
445215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), port_0_ctl.u32))
446215976Sjmallett        return -1;
447215976Sjmallett
448215976Sjmallett    /* Errata SRIO-14485: Link speed is reported incorrectly in CN63XX
449215976Sjmallett        pass 1.x */
450215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
451215976Sjmallett    {
452215976Sjmallett        cvmx_sriomaintx_port_0_ctl2_t port_0_ctl2;
453215976Sjmallett        if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), &port_0_ctl2.u32))
454215976Sjmallett            return -1;
455215976Sjmallett        if (port_0_ctl2.s.enb_500g)
456215976Sjmallett        {
457215976Sjmallett            port_0_ctl2.u32 = 0;
458215976Sjmallett            port_0_ctl2.s.enb_625g = 1;
459215976Sjmallett        }
460215976Sjmallett        else if (port_0_ctl2.s.enb_312g)
461215976Sjmallett        {
462215976Sjmallett            port_0_ctl2.u32 = 0;
463215976Sjmallett            port_0_ctl2.s.enb_500g = 1;
464215976Sjmallett        }
465215976Sjmallett        else if (port_0_ctl2.s.enb_250g)
466215976Sjmallett        {
467215976Sjmallett            port_0_ctl2.u32 = 0;
468215976Sjmallett            port_0_ctl2.s.enb_312g = 1;
469215976Sjmallett        }
470215976Sjmallett        else if (port_0_ctl2.s.enb_125g)
471215976Sjmallett        {
472215976Sjmallett            port_0_ctl2.u32 = 0;
473215976Sjmallett            port_0_ctl2.s.enb_250g = 1;
474215976Sjmallett        }
475215976Sjmallett        else
476215976Sjmallett        {
477215976Sjmallett            port_0_ctl2.u32 = 0;
478215976Sjmallett            port_0_ctl2.s.enb_125g = 1;
479215976Sjmallett        }
480215976Sjmallett        if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL2(srio_port), port_0_ctl2.u32))
481215976Sjmallett            return -1;
482215976Sjmallett    }
483215976Sjmallett
484215976Sjmallett    /* Set the link layer timeout to 10us. The default is too high and causes
485215976Sjmallett        core bus errors */
486215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_LT_CTL(srio_port), &port_lt_ctl.u32))
487215976Sjmallett        return -1;
488215976Sjmallett    port_lt_ctl.s.timeout = 10000 / 200; /* 10us = 10000ns / 200ns */
489215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_LT_CTL(srio_port), port_lt_ctl.u32))
490215976Sjmallett        return -1;
491215976Sjmallett
492215976Sjmallett    /* Set the logical layer timeout to 10ms. The default is too high and causes
493215976Sjmallett        core bus errors */
494215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_RT_CTL(srio_port), &port_rt_ctl.u32))
495215976Sjmallett        return -1;
496215976Sjmallett    port_rt_ctl.s.timeout = 10000000 / 200; /* 10ms = 10000000ns / 200ns */
497215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_RT_CTL(srio_port), port_rt_ctl.u32))
498215976Sjmallett        return -1;
499215976Sjmallett
500215976Sjmallett    /* Allow memory and doorbells. Messaging is enabled later */
501215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_CORE_ENABLES(srio_port), &core_enables.u32))
502215976Sjmallett        return -1;
503215976Sjmallett    core_enables.s.doorbell = 1;
504215976Sjmallett    core_enables.s.memory = 1;
505215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_CORE_ENABLES(srio_port), core_enables.u32))
506215976Sjmallett        return -1;
507215976Sjmallett
508215976Sjmallett    /* Allow us to master transactions */
509215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_GEN_CTL(srio_port), &port_gen_ctl.u32))
510215976Sjmallett        return -1;
511215976Sjmallett    port_gen_ctl.s.menable = 1;
512215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_GEN_CTL(srio_port), port_gen_ctl.u32))
513215976Sjmallett        return -1;
514215976Sjmallett
515215976Sjmallett    /* Set the MRRS and MPS for optimal SRIO performance */
516215976Sjmallett    prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(srio_port));
517215976Sjmallett    prt_cfg.s.mps = 1;
518215976Sjmallett    prt_cfg.s.mrrs = 1;
519215976Sjmallett    cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(srio_port), prt_cfg.u64);
520215976Sjmallett
521215976Sjmallett    sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(srio_port));
522215976Sjmallett    sli_s2m_portx_ctl.s.mrrs = 1;
523215976Sjmallett    cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(srio_port), sli_s2m_portx_ctl.u64);
524215976Sjmallett
525215976Sjmallett    /* Setup RX messaging thresholds */
526215976Sjmallett    sriox_imsg_vport_thr.u64 = cvmx_read_csr(CVMX_SRIOX_IMSG_VPORT_THR(srio_port));
527215976Sjmallett    sriox_imsg_vport_thr.s.max_tot = 48;
528215976Sjmallett    sriox_imsg_vport_thr.s.max_s1 = 24;
529215976Sjmallett    sriox_imsg_vport_thr.s.max_s0 = 24;
530215976Sjmallett    sriox_imsg_vport_thr.s.sp_vport = 1;
531215976Sjmallett    sriox_imsg_vport_thr.s.buf_thr = 4;
532215976Sjmallett    sriox_imsg_vport_thr.s.max_p1 = 12;
533215976Sjmallett    sriox_imsg_vport_thr.s.max_p0 = 12;
534215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_IMSG_VPORT_THR(srio_port), sriox_imsg_vport_thr.u64);
535215976Sjmallett
536215976Sjmallett    /* Errata SRIO-X: SRIO error behavior may not be optimal in CN63XX pass 1.x */
537215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
538215976Sjmallett    {
539215976Sjmallett        cvmx_sriox_tx_ctrl_t sriox_tx_ctrl;
540215976Sjmallett        sriox_tx_ctrl.u64 = cvmx_read_csr(CVMX_SRIOX_TX_CTRL(srio_port));
541215976Sjmallett        sriox_tx_ctrl.s.tag_th2 = 2;
542215976Sjmallett        sriox_tx_ctrl.s.tag_th1 = 3;
543215976Sjmallett        sriox_tx_ctrl.s.tag_th0 = 4;
544215976Sjmallett        cvmx_write_csr(CVMX_SRIOX_TX_CTRL(srio_port), sriox_tx_ctrl.u64);
545215976Sjmallett    }
546215976Sjmallett
547215976Sjmallett    /* Clear any pending interrupts */
548215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_INT_REG(srio_port), cvmx_read_csr(CVMX_SRIOX_INT_REG(srio_port)));
549215976Sjmallett
550215976Sjmallett    /* Enable error reporting */
551215976Sjmallett#if (!defined(CVMX_BUILD_FOR_LINUX_HOST) && !defined(CVMX_BUILD_FOR_LINUX_KERNEL)) || defined(CONFIG_CAVIUM_DECODE_RSL)
552215976Sjmallett    cvmx_error_enable_group(CVMX_ERROR_GROUP_SRIO, srio_port);
553215976Sjmallett#endif
554215976Sjmallett
555215976Sjmallett    /* Finally enable the link */
556215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), &port_0_ctl.u32))
557215976Sjmallett        return -1;
558215976Sjmallett    port_0_ctl.s.o_enable = 1;
559215976Sjmallett    port_0_ctl.s.i_enable = 1;
560215976Sjmallett    port_0_ctl.s.disable = 0;
561215976Sjmallett    port_0_ctl.s.prt_lock = 0;
562215976Sjmallett    if (__cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_PORT_0_CTL(srio_port), port_0_ctl.u32))
563215976Sjmallett        return -1;
564215976Sjmallett
565215976Sjmallett    return 0;
566215976Sjmallett}
567215976Sjmallett
568215976Sjmallett
569215976Sjmallett/**
570215976Sjmallett * Read 32bits from a Device's config space
571215976Sjmallett *
572215976Sjmallett * @param srio_port SRIO port the device is on
573215976Sjmallett * @param srcid_index
574215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
575215976Sjmallett * @param destid    RapidIO device ID, or -1 for the local Octeon.
576215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
577215976Sjmallett *                  if transactions should use 8bit device IDs.
578215976Sjmallett * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
579215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
580215976Sjmallett * @param result    Result of the read. This will be unmodified on failure.
581215976Sjmallett *
582215976Sjmallett * @return Zero on success, negative on failure.
583215976Sjmallett */
584215976Sjmallettint cvmx_srio_config_read32(int srio_port, int srcid_index, int destid,
585215976Sjmallett                            int is16bit, uint8_t hopcount, uint32_t offset,
586215976Sjmallett                            uint32_t *result)
587215976Sjmallett{
588215976Sjmallett    if (destid == -1)
589215976Sjmallett    {
590215976Sjmallett        int status = __cvmx_srio_local_read32(srio_port, offset, result);
591215976Sjmallett
592215976Sjmallett        if ((status == 0) && (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG))
593215976Sjmallett            cvmx_dprintf("SRIO%d: Local read [0x%06x] <= 0x%08x\n", srio_port, (unsigned int)offset, (unsigned int)*result);
594215976Sjmallett
595215976Sjmallett        return status;
596215976Sjmallett    }
597215976Sjmallett    else
598215976Sjmallett    {
599215976Sjmallett#if CVMX_SRIO_USE_FIFO_FOR_MAINT
600215976Sjmallett        int return_code;
601215976Sjmallett        uint32_t pkt = 0;
602215976Sjmallett        uint32_t sourceid;
603215976Sjmallett        uint64_t stop_cycle;
604215976Sjmallett        char rx_buffer[64];
605215976Sjmallett
606215976Sjmallett        /* Tell the user */
607215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
608215976Sjmallett            cvmx_dprintf("SRIO%d: Remote read [id=0x%04x hop=%3d offset=0x%06x] <= ", srio_port, destid, hopcount, (unsigned int)offset);
609215976Sjmallett
610215976Sjmallett        /* Read the proper source ID */
611215976Sjmallett        if (srcid_index)
612215976Sjmallett            __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_SEC_DEV_ID(srio_port), &sourceid);
613215976Sjmallett        else
614215976Sjmallett            __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PRI_DEV_ID(srio_port), &sourceid);
615215976Sjmallett
616215976Sjmallett        if (is16bit)
617215976Sjmallett        {
618215976Sjmallett            /* Use the 16bit source ID */
619215976Sjmallett            sourceid &= 0xffff;
620215976Sjmallett
621215976Sjmallett            /* MAINT Reads are 11 bytes */
622215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 11<<16);
623215976Sjmallett
624215976Sjmallett            pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
625215976Sjmallett            pkt |= 1 << 28;                         /* tt       [29:28] */
626215976Sjmallett            pkt |= 0x8 << 24;                       /* ftype    [27:24] */
627215976Sjmallett            pkt |= destid << 8;                     /* destID   [23:8] */
628215976Sjmallett            pkt |= sourceid >> 8;                   /* sourceID [7:0] */
629215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
630215976Sjmallett            pkt = 0;
631215976Sjmallett            pkt |= sourceid << 24;                  /* sourceID [31:24] */
632215976Sjmallett            pkt |= 0 << 20;                         /* transaction [23:20] */
633215976Sjmallett            pkt |= 8 << 16;                         /* rdsize [19:16] */
634215976Sjmallett            pkt |= 0xc0 << 8;                       /* srcTID [15:8] */
635215976Sjmallett            pkt |= hopcount;                        /* hopcount [7:0] */
636215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
637215976Sjmallett            pkt = 0;
638215976Sjmallett            pkt |= offset << 8;                     /* offset [31:11, wdptr[10], reserved[9:8] */
639215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
640215976Sjmallett        }
641215976Sjmallett        else
642215976Sjmallett        {
643215976Sjmallett            /* Use the 8bit source ID */
644215976Sjmallett            sourceid = (sourceid >> 16) & 0xff;
645215976Sjmallett
646215976Sjmallett            /* MAINT Reads are 9 bytes */
647215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 9<<16);
648215976Sjmallett
649215976Sjmallett            pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
650215976Sjmallett            pkt |= 0 << 28;                         /* tt       [29:28] */
651215976Sjmallett            pkt |= 0x8 << 24;                       /* ftype    [27:24] */
652215976Sjmallett            pkt |= destid << 16;                    /* destID   [23:16] */
653215976Sjmallett            pkt |= sourceid << 8;                   /* sourceID [15:8] */
654215976Sjmallett            pkt |= 0 << 4;                          /* transaction [7:4] */
655215976Sjmallett            pkt |= 8 << 0;                          /* rdsize [3:0] */
656215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
657215976Sjmallett            pkt = 0;
658215976Sjmallett            pkt |= 0xc0 << 24;                      /* srcTID [31:24] */
659215976Sjmallett            pkt |= hopcount << 16;                  /* hopcount [23:16] */
660215976Sjmallett            pkt |= offset >> 8;                     /* offset [15:0] */
661215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
662215976Sjmallett            pkt = 0;
663215976Sjmallett            pkt |= offset << 24;                    /* offset [31:27, wdptr[26], reserved[25:24] */
664215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
665215976Sjmallett        }
666215976Sjmallett
667215976Sjmallett        stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/10 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
668215976Sjmallett        do
669215976Sjmallett        {
670215976Sjmallett            return_code = cvmx_srio_receive_spf(srio_port, rx_buffer, sizeof(rx_buffer));
671215976Sjmallett            if ((return_code == 0) && (cvmx_clock_get_count(CVMX_CLOCK_CORE) > stop_cycle))
672215976Sjmallett            {
673215976Sjmallett                if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
674215976Sjmallett                    cvmx_dprintf("timeout\n");
675215976Sjmallett                return_code = -1;
676215976Sjmallett            }
677215976Sjmallett        } while (return_code == 0);
678215976Sjmallett
679215976Sjmallett        if (return_code == ((is16bit) ? 23 : 19))
680215976Sjmallett        {
681215976Sjmallett            if (is16bit)
682215976Sjmallett            {
683215976Sjmallett                if (offset & 4)
684215976Sjmallett                    *result = *(uint32_t*)(rx_buffer + 15);
685215976Sjmallett                else
686215976Sjmallett                    *result = *(uint32_t*)(rx_buffer + 11);
687215976Sjmallett            }
688215976Sjmallett            else
689215976Sjmallett            {
690215976Sjmallett                if (offset & 4)
691215976Sjmallett                    *result = *(uint32_t*)(rx_buffer + 13);
692215976Sjmallett                else
693215976Sjmallett                    *result = *(uint32_t*)(rx_buffer + 9);
694215976Sjmallett            }
695215976Sjmallett            if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
696215976Sjmallett                cvmx_dprintf("0x%08x\n", (unsigned int)*result);
697215976Sjmallett            return_code = 0;
698215976Sjmallett        }
699215976Sjmallett        else
700215976Sjmallett        {
701215976Sjmallett            *result = 0xffffffff;
702215976Sjmallett            return_code = -1;
703215976Sjmallett        }
704215976Sjmallett
705215976Sjmallett        return return_code;
706215976Sjmallett#elif !defined(CVMX_BUILD_FOR_LINUX_HOST)
707215976Sjmallett        uint64_t physical;
708215976Sjmallett        physical = cvmx_srio_physical_map(srio_port,
709215976Sjmallett            CVMX_SRIO_WRITE_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
710215976Sjmallett            CVMX_SRIO_READ_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
711215976Sjmallett            srcid_index, destid, is16bit, offset + (hopcount<<24), 4);
712215976Sjmallett        if (!physical)
713215976Sjmallett            return -1;
714215976Sjmallett
715215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
716215976Sjmallett            cvmx_dprintf("SRIO%d: Remote read [id=0x%04x hop=%3d offset=0x%06x] <= ", srio_port, destid, hopcount, offset);
717215976Sjmallett
718215976Sjmallett        /* Finally do the maintenance read to complete the config request */
719215976Sjmallett        *result = cvmx_read64_uint32(CVMX_ADD_IO_SEG(physical));
720215976Sjmallett        cvmx_srio_physical_unmap(physical, 4);
721215976Sjmallett
722215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
723215976Sjmallett            cvmx_dprintf("0x%08x\n", *result);
724215976Sjmallett
725215976Sjmallett        return 0;
726215976Sjmallett#else
727215976Sjmallett        return -1;
728215976Sjmallett#endif
729215976Sjmallett    }
730215976Sjmallett}
731215976Sjmallett
732215976Sjmallett
733215976Sjmallett/**
734215976Sjmallett * Write 32bits to a Device's config space
735215976Sjmallett *
736215976Sjmallett * @param srio_port SRIO port the device is on
737215976Sjmallett * @param srcid_index
738215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
739215976Sjmallett * @param destid    RapidIO device ID, or -1 for the local Octeon.
740215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
741215976Sjmallett *                  if transactions should use 8bit device IDs.
742215976Sjmallett * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
743215976Sjmallett * @param offset    Offset in config space. This must be a multiple of 32 bits.
744215976Sjmallett * @param data      Data to write.
745215976Sjmallett *
746215976Sjmallett * @return Zero on success, negative on failure.
747215976Sjmallett */
748215976Sjmallettint cvmx_srio_config_write32(int srio_port, int srcid_index, int destid,
749215976Sjmallett                             int is16bit, uint8_t hopcount, uint32_t offset,
750215976Sjmallett                             uint32_t data)
751215976Sjmallett{
752215976Sjmallett    if (destid == -1)
753215976Sjmallett    {
754215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
755215976Sjmallett            cvmx_dprintf("SRIO%d: Local write[0x%06x] => 0x%08x\n", srio_port, (unsigned int)offset, (unsigned int)data);
756215976Sjmallett
757215976Sjmallett        return __cvmx_srio_local_write32(srio_port, offset, data);
758215976Sjmallett    }
759215976Sjmallett    else
760215976Sjmallett    {
761215976Sjmallett#if CVMX_SRIO_USE_FIFO_FOR_MAINT
762215976Sjmallett        int return_code;
763215976Sjmallett        uint32_t pkt = 0;
764215976Sjmallett        uint32_t sourceid;
765215976Sjmallett        uint64_t stop_cycle;
766215976Sjmallett        char rx_buffer[64];
767215976Sjmallett
768215976Sjmallett        /* Tell the user */
769215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
770215976Sjmallett            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);
771215976Sjmallett
772215976Sjmallett        /* Read the proper source ID */
773215976Sjmallett        if (srcid_index)
774215976Sjmallett            __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_SEC_DEV_ID(srio_port), &sourceid);
775215976Sjmallett        else
776215976Sjmallett            __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_PRI_DEV_ID(srio_port), &sourceid);
777215976Sjmallett
778215976Sjmallett        if (is16bit)
779215976Sjmallett        {
780215976Sjmallett            /* Use the 16bit source ID */
781215976Sjmallett            sourceid &= 0xffff;
782215976Sjmallett
783215976Sjmallett            /* MAINT Writes are 19 bytes */
784215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 19<<16);
785215976Sjmallett
786215976Sjmallett            pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
787215976Sjmallett            pkt |= 1 << 28;                         /* tt       [29:28] */
788215976Sjmallett            pkt |= 0x8 << 24;                       /* ftype    [27:24] */
789215976Sjmallett            pkt |= destid << 8;                     /* destID   [23:8] */
790215976Sjmallett            pkt |= sourceid >> 8;                   /* sourceID [7:0] */
791215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
792215976Sjmallett            pkt = 0;
793215976Sjmallett            pkt |= sourceid << 24;                  /* sourceID [31:24] */
794215976Sjmallett            pkt |= 1 << 20;                         /* transaction [23:20] */
795215976Sjmallett            pkt |= 8 << 16;                         /* wrsize [19:16] */
796215976Sjmallett            pkt |= 0xc0 << 8;                       /* srcTID [15:8] */
797215976Sjmallett            pkt |= hopcount;                        /* hopcount [7:0] */
798215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
799215976Sjmallett            pkt = 0;
800215976Sjmallett            pkt |= offset << 8;                     /* offset [31:11, wdptr[10], reserved[9:8] */
801215976Sjmallett            if ((offset & 4) == 0)
802215976Sjmallett                pkt |= 0xff & (data >> 24);       /* data [7:0] */
803215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
804215976Sjmallett            if (offset & 4)
805215976Sjmallett            {
806215976Sjmallett                pkt = 0xff & (data >> 24);
807215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
808215976Sjmallett                pkt = data << 8;
809215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
810215976Sjmallett            }
811215976Sjmallett            else
812215976Sjmallett            {
813215976Sjmallett                pkt = data << 8;
814215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
815215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), 0);
816215976Sjmallett            }
817215976Sjmallett        }
818215976Sjmallett        else
819215976Sjmallett        {
820215976Sjmallett            /* Use the 8bit source ID */
821215976Sjmallett            sourceid = (sourceid >> 16) & 0xff;
822215976Sjmallett
823215976Sjmallett            /* MAINT Writes are 17 bytes */
824215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_CTRL(srio_port), 17<<16);
825215976Sjmallett
826215976Sjmallett            pkt |= CVMX_SRIO_CONFIG_PRIORITY << 30; /* priority [31:30] */
827215976Sjmallett            pkt |= 0 << 28;                         /* tt       [29:28] */
828215976Sjmallett            pkt |= 0x8 << 24;                       /* ftype    [27:24] */
829215976Sjmallett            pkt |= destid << 16;                    /* destID   [23:16] */
830215976Sjmallett            pkt |= sourceid << 8;                   /* sourceID [15:8] */
831215976Sjmallett            pkt |= 1 << 4;                          /* transaction [7:4] */
832215976Sjmallett            pkt |= 8 << 0;                          /* wrsize [3:0] */
833215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
834215976Sjmallett            pkt = 0;
835215976Sjmallett            pkt |= 0xc0 << 24;                      /* srcTID [31:24] */
836215976Sjmallett            pkt |= hopcount << 16;                  /* hopcount [23:16] */
837215976Sjmallett            pkt |= offset >> 8;                     /* offset [15:0] */
838215976Sjmallett            __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
839215976Sjmallett            pkt = 0;
840215976Sjmallett            pkt |= offset << 24;                    /* offset [31:27, wdptr[26], reserved[25:24] */
841215976Sjmallett            if (offset & 4)
842215976Sjmallett            {
843215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
844215976Sjmallett                pkt = data >> 8;
845215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
846215976Sjmallett                pkt = data << 24;
847215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
848215976Sjmallett            }
849215976Sjmallett            else
850215976Sjmallett            {
851215976Sjmallett                pkt |= data >> 8;                    /* data [23:0] */
852215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
853215976Sjmallett                pkt = data << 24;                    /* data [31:24] */
854215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), pkt);
855215976Sjmallett                __cvmx_srio_local_write32(srio_port, CVMX_SRIOMAINTX_IR_SP_TX_DATA(srio_port), 0);
856215976Sjmallett            }
857215976Sjmallett        }
858215976Sjmallett
859215976Sjmallett        stop_cycle = cvmx_clock_get_rate(CVMX_CLOCK_CORE)/10 + cvmx_clock_get_count(CVMX_CLOCK_CORE);
860215976Sjmallett        do
861215976Sjmallett        {
862215976Sjmallett            return_code = cvmx_srio_receive_spf(srio_port, rx_buffer, sizeof(rx_buffer));
863215976Sjmallett            if ((return_code == 0) && (cvmx_clock_get_count(CVMX_CLOCK_CORE) > stop_cycle))
864215976Sjmallett            {
865215976Sjmallett                if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
866215976Sjmallett                    cvmx_dprintf("timeout\n");
867215976Sjmallett                return_code = -1;
868215976Sjmallett            }
869215976Sjmallett        } while (return_code == 0);
870215976Sjmallett
871215976Sjmallett        if (return_code == ((is16bit) ? 15 : 11))
872215976Sjmallett            return_code = 0;
873215976Sjmallett        else
874215976Sjmallett        {
875215976Sjmallett            cvmx_dprintf("SRIO%d: Remote write failed\n", srio_port);
876215976Sjmallett            return_code = -1;
877215976Sjmallett        }
878215976Sjmallett
879215976Sjmallett        return return_code;
880215976Sjmallett#elif !defined(CVMX_BUILD_FOR_LINUX_HOST)
881215976Sjmallett        uint64_t physical = cvmx_srio_physical_map(srio_port,
882215976Sjmallett                CVMX_SRIO_WRITE_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
883215976Sjmallett                CVMX_SRIO_READ_MODE_MAINTENANCE, CVMX_SRIO_CONFIG_PRIORITY,
884215976Sjmallett                srcid_index, destid, is16bit, offset + (hopcount<<24), 4);
885215976Sjmallett        if (!physical)
886215976Sjmallett            return -1;
887215976Sjmallett
888215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
889215976Sjmallett            cvmx_dprintf("SRIO%d: Remote write[id=0x%04x hop=%3d offset=0x%06x] => 0x%08x\n", srio_port, destid, hopcount, offset, data);
890215976Sjmallett
891215976Sjmallett        /* Finally do the maintenance write to complete the config request */
892215976Sjmallett        cvmx_write64_uint32(CVMX_ADD_IO_SEG(physical), data);
893215976Sjmallett        return cvmx_srio_physical_unmap(physical, 4);
894215976Sjmallett#else
895215976Sjmallett        return -1;
896215976Sjmallett#endif
897215976Sjmallett    }
898215976Sjmallett}
899215976Sjmallett
900215976Sjmallett
901215976Sjmallett/**
902215976Sjmallett * Send a RapidIO doorbell to a remote device
903215976Sjmallett *
904215976Sjmallett * @param srio_port SRIO port the device is on
905215976Sjmallett * @param srcid_index
906215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
907215976Sjmallett * @param destid    RapidIO device ID.
908215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
909215976Sjmallett *                  if transactions should use 8bit device IDs.
910215976Sjmallett * @param priority  Doorbell priority (0-3)
911215976Sjmallett * @param data      Data for doorbell.
912215976Sjmallett *
913215976Sjmallett * @return Zero on success, negative on failure.
914215976Sjmallett */
915215976Sjmallettint cvmx_srio_send_doorbell(int srio_port, int srcid_index, int destid, int is16bit, int priority, uint16_t data)
916215976Sjmallett{
917215976Sjmallett    cvmx_sriox_tx_bell_t tx_bell;
918215976Sjmallett    tx_bell.u64 = 0;
919215976Sjmallett    tx_bell.s.data = data;
920215976Sjmallett    tx_bell.s.dest_id = destid;
921215976Sjmallett    tx_bell.s.src_id = srcid_index;
922215976Sjmallett    tx_bell.s.id16 = !!is16bit;
923215976Sjmallett    tx_bell.s.priority = priority;
924215976Sjmallett
925215976Sjmallett    /* Make sure the previous doorbell has completed */
926215976Sjmallett    if (CVMX_WAIT_FOR_FIELD64(CVMX_SRIOX_TX_BELL(srio_port), cvmx_sriox_tx_bell_t, pending, ==, 0, CVMX_SRIO_DOORBELL_TIMEOUT))
927215976Sjmallett    {
928215976Sjmallett        cvmx_dprintf("SRIO%d: Pending bit stuck before doorbell\n", srio_port);
929215976Sjmallett        return -1;
930215976Sjmallett    }
931215976Sjmallett
932215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
933215976Sjmallett        cvmx_dprintf("SRIO%d: Send doorbell destid=0x%x, priority=%d, data=0x%x\n", srio_port, destid, priority, 0xffff & data);
934215976Sjmallett
935215976Sjmallett    /* Send the doorbell. We don't wait for it to complete. The next doorbell
936215976Sjmallett        may delay on the pending bit, but this gives the caller the ability to
937215976Sjmallett        do other stuff while the doorbell processes */
938215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_TX_BELL(srio_port), tx_bell.u64);
939215976Sjmallett    return 0;
940215976Sjmallett}
941215976Sjmallett
942215976Sjmallett
943215976Sjmallett/**
944215976Sjmallett * Get the status of the last doorbell sent. If the dooorbell
945215976Sjmallett * hardware is done, then the status is cleared to get ready for
946215976Sjmallett * the next doorbell (or retry).
947215976Sjmallett *
948215976Sjmallett * @param srio_port SRIO port to check doorbell on
949215976Sjmallett *
950215976Sjmallett * @return Doorbell status
951215976Sjmallett */
952215976Sjmallettcvmx_srio_doorbell_status_t cvmx_srio_send_doorbell_status(int srio_port)
953215976Sjmallett{
954215976Sjmallett    cvmx_sriox_tx_bell_t tx_bell;
955215976Sjmallett    cvmx_sriox_tx_bell_info_t tx_bell_info;
956215976Sjmallett    cvmx_sriox_int_reg_t int_reg;
957215976Sjmallett    cvmx_sriox_int_reg_t int_reg_clear;
958215976Sjmallett
959215976Sjmallett    /* Return busy if the doorbell is still processing */
960215976Sjmallett    tx_bell.u64 = cvmx_read_csr(CVMX_SRIOX_TX_BELL(srio_port));
961215976Sjmallett    if (tx_bell.s.pending)
962215976Sjmallett        return CVMX_SRIO_DOORBELL_BUSY;
963215976Sjmallett
964215976Sjmallett    /* Read and clear the TX doorbell interrupts */
965215976Sjmallett    int_reg.u64 = cvmx_read_csr(CVMX_SRIOX_INT_REG(srio_port));
966215976Sjmallett    int_reg_clear.u64 = 0;
967215976Sjmallett    int_reg_clear.s.bell_err = int_reg.s.bell_err;
968215976Sjmallett    int_reg_clear.s.txbell = int_reg.s.txbell;
969215976Sjmallett    cvmx_write_csr(CVMX_SRIOX_INT_REG(srio_port), int_reg_clear.u64);
970215976Sjmallett
971215976Sjmallett    /* Check for errors */
972215976Sjmallett    if (int_reg.s.bell_err)
973215976Sjmallett    {
974215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
975215976Sjmallett            cvmx_dprintf("SRIO%d: Send doorbell failed\n", srio_port);
976215976Sjmallett        tx_bell_info.u64 = cvmx_read_csr(CVMX_SRIOX_TX_BELL_INFO(srio_port));
977215976Sjmallett        if (tx_bell_info.s.timeout || tx_bell_info.s.error)
978215976Sjmallett            return CVMX_SRIO_DOORBELL_ERROR;
979215976Sjmallett        if (tx_bell_info.s.retry)
980215976Sjmallett            return CVMX_SRIO_DOORBELL_RETRY;
981215976Sjmallett    }
982215976Sjmallett
983215976Sjmallett    /* Check if we're done */
984215976Sjmallett    if (int_reg.s.txbell)
985215976Sjmallett        return CVMX_SRIO_DOORBELL_DONE;
986215976Sjmallett
987215976Sjmallett    /* No doorbell found */
988215976Sjmallett    return CVMX_SRIO_DOORBELL_NONE;
989215976Sjmallett}
990215976Sjmallett
991215976Sjmallett
992215976Sjmallett/**
993215976Sjmallett * Read a received doorbell and report data about it.
994215976Sjmallett *
995215976Sjmallett * @param srio_port SRIO port to check for the received doorbell
996215976Sjmallett * @param destid_index
997215976Sjmallett *                  Which Octeon destination ID was the doorbell for
998215976Sjmallett * @param sequence_num
999215976Sjmallett *                  Sequence number of doorbell (32bits)
1000215976Sjmallett * @param srcid     RapidIO source ID of the doorbell sender
1001215976Sjmallett * @param priority  Priority of the doorbell (0-3)
1002215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1003215976Sjmallett *                  if transactions should use 8bit device IDs.
1004215976Sjmallett * @param data      Data in the doorbell (16 bits)
1005215976Sjmallett *
1006215976Sjmallett * @return Doorbell status. Either DONE, NONE, or ERROR.
1007215976Sjmallett */
1008215976Sjmallettcvmx_srio_doorbell_status_t cvmx_srio_receive_doorbell(int srio_port,
1009215976Sjmallett        int *destid_index, uint32_t *sequence_num, int *srcid, int *priority,
1010215976Sjmallett        int *is16bit, uint16_t *data)
1011215976Sjmallett{
1012215976Sjmallett    cvmx_sriox_rx_bell_seq_t rx_bell_seq;
1013215976Sjmallett    cvmx_sriox_rx_bell_t rx_bell;
1014215976Sjmallett
1015215976Sjmallett    /* Check if there are any pending doorbells */
1016215976Sjmallett    rx_bell_seq.u64 = cvmx_read_csr(CVMX_SRIOX_RX_BELL_SEQ(srio_port));
1017215976Sjmallett    if (!rx_bell_seq.s.count)
1018215976Sjmallett        return CVMX_SRIO_DOORBELL_NONE;
1019215976Sjmallett
1020215976Sjmallett    /* Read the doorbell and write our return parameters */
1021215976Sjmallett    rx_bell.u64 = cvmx_read_csr(CVMX_SRIOX_RX_BELL(srio_port));
1022215976Sjmallett    *sequence_num = rx_bell_seq.s.seq;
1023215976Sjmallett    *srcid = rx_bell.s.src_id;
1024215976Sjmallett    *priority = rx_bell.s.priority;
1025215976Sjmallett    *is16bit = rx_bell.s.id16;
1026215976Sjmallett    *data = rx_bell.s.data;
1027215976Sjmallett    *destid_index = rx_bell.s.dest_id;
1028215976Sjmallett
1029215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1030215976Sjmallett        cvmx_dprintf("SRIO%d: Receive doorbell sequence=0x%x, srcid=0x%x, priority=%d, data=0x%x\n",
1031215976Sjmallett            srio_port, rx_bell_seq.s.seq, rx_bell.s.src_id, rx_bell.s.priority, rx_bell.s.data);
1032215976Sjmallett
1033215976Sjmallett    return CVMX_SRIO_DOORBELL_DONE;
1034215976Sjmallett}
1035215976Sjmallett
1036215976Sjmallett
1037215976Sjmallett/**
1038215976Sjmallett * Receive a packet from the Soft Packet FIFO (SPF).
1039215976Sjmallett *
1040215976Sjmallett * @param srio_port SRIO port to read the packet from.
1041215976Sjmallett * @param buffer    Buffer to receive the packet.
1042215976Sjmallett * @param buffer_length
1043215976Sjmallett *                  Length of the buffer in bytes.
1044215976Sjmallett *
1045215976Sjmallett * @return Returns the length of the packet read. Negative on failure.
1046215976Sjmallett *         Zero if no packets are available.
1047215976Sjmallett */
1048215976Sjmallettint cvmx_srio_receive_spf(int srio_port, void *buffer, int buffer_length)
1049215976Sjmallett{
1050215976Sjmallett    uint32_t *ptr = (uint32_t *)buffer;
1051215976Sjmallett    cvmx_sriomaintx_ir_sp_rx_stat_t sriomaintx_ir_sp_rx_stat;
1052215976Sjmallett
1053215976Sjmallett    /* Read the SFP status */
1054215976Sjmallett    if (__cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_IR_SP_RX_STAT(srio_port), &sriomaintx_ir_sp_rx_stat.u32))
1055215976Sjmallett        return -1;
1056215976Sjmallett
1057215976Sjmallett    /* Return zero if there isn't a packet available */
1058215976Sjmallett    if (sriomaintx_ir_sp_rx_stat.s.buffers < 1)
1059215976Sjmallett        return 0;
1060215976Sjmallett
1061215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1062215976Sjmallett        cvmx_dprintf("SRIO%d: Soft packet FIFO received %d bytes", srio_port, sriomaintx_ir_sp_rx_stat.s.octets);
1063215976Sjmallett
1064215976Sjmallett    /* Return error if the packet is larger than our buffer */
1065215976Sjmallett    if (sriomaintx_ir_sp_rx_stat.s.octets > buffer_length)
1066215976Sjmallett        return -1;
1067215976Sjmallett
1068215976Sjmallett    /* Read out the packet four bytes at a time */
1069215976Sjmallett    buffer_length = sriomaintx_ir_sp_rx_stat.s.octets;
1070215976Sjmallett    while (buffer_length > 0)
1071215976Sjmallett    {
1072215976Sjmallett        __cvmx_srio_local_read32(srio_port, CVMX_SRIOMAINTX_IR_SP_RX_DATA(srio_port), ptr);
1073215976Sjmallett        if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1074215976Sjmallett            cvmx_dprintf(" %08x", (unsigned int)*ptr);
1075215976Sjmallett        ptr++;
1076215976Sjmallett        buffer_length-=4;
1077215976Sjmallett    }
1078215976Sjmallett
1079215976Sjmallett    if (__cvmx_srio_state[srio_port].flags & CVMX_SRIO_INITIALIZE_DEBUG)
1080215976Sjmallett        cvmx_dprintf("\n");
1081215976Sjmallett
1082215976Sjmallett    /* Return the number of bytes in the buffer */
1083215976Sjmallett    return sriomaintx_ir_sp_rx_stat.s.octets;
1084215976Sjmallett}
1085215976Sjmallett
1086215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
1087215976Sjmallett/**
1088215976Sjmallett * Map a remote device's memory region into Octeon's physical
1089215976Sjmallett * address area. The caller can then map this into a core using
1090215976Sjmallett * the TLB or XKPHYS.
1091215976Sjmallett *
1092215976Sjmallett * @param srio_port SRIO port to map the device on
1093215976Sjmallett * @param write_op  Type of operation to perform on a write to the device.
1094215976Sjmallett *                  Normally should be CVMX_SRIO_WRITE_MODE_AUTO.
1095215976Sjmallett * @param write_priority
1096215976Sjmallett *                  SRIO priority of writes (0-3)
1097215976Sjmallett * @param read_op   Type of operation to perform on reads to the device.
1098215976Sjmallett *                  Normally should be CVMX_SRIO_READ_MODE_NORMAL.
1099215976Sjmallett * @param read_priority
1100215976Sjmallett *                  SRIO priority of reads (0-3)
1101215976Sjmallett * @param srcid_index
1102215976Sjmallett *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
1103215976Sjmallett * @param destid    RapidIO device ID.
1104215976Sjmallett * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
1105215976Sjmallett *                  if transactions should use 8bit device IDs.
1106215976Sjmallett * @param base      Device base address to start the mapping
1107215976Sjmallett * @param size      Size of the mapping in bytes
1108215976Sjmallett *
1109215976Sjmallett * @return Octeon 64bit physical address that accesses the remote device,
1110215976Sjmallett *         or zero on failure.
1111215976Sjmallett */
1112215976Sjmallettuint64_t cvmx_srio_physical_map(int srio_port, cvmx_srio_write_mode_t write_op,
1113215976Sjmallett        int write_priority, cvmx_srio_read_mode_t read_op, int read_priority,
1114215976Sjmallett        int srcid_index, int destid, int is16bit, uint64_t base, uint64_t size)
1115215976Sjmallett{
1116215976Sjmallett    cvmx_sriox_s2m_typex_t needed_s2m_type;
1117215976Sjmallett    cvmx_sli_mem_access_subidx_t needed_subid;
1118215976Sjmallett    int s2m_index;
1119215976Sjmallett    int subdid;
1120215976Sjmallett    cvmx_sli_address_t sli_address;
1121215976Sjmallett
1122215976Sjmallett    /* We currently don't support mapping regions that span a 34 bit boundary.
1123215976Sjmallett        Keeping track of multiple regions to span 34 bits is hard and not
1124215976Sjmallett        likely to be needed */
1125215976Sjmallett    if (((base+size-1)>>34) != (base>>34))
1126215976Sjmallett    {
1127215976Sjmallett        cvmx_dprintf("SRIO%d: Failed to map range 0x%llx-0x%llx spanning a 34bit boundary\n",
1128215976Sjmallett            srio_port, (ULL)base, (ULL)base+size-1);
1129215976Sjmallett        return 0;
1130215976Sjmallett    }
1131215976Sjmallett
1132215976Sjmallett    /* Build the S2M_TYPE we are going to need */
1133215976Sjmallett    needed_s2m_type.u64 = 0;
1134215976Sjmallett    needed_s2m_type.s.wr_op = write_op;
1135215976Sjmallett    needed_s2m_type.s.rd_op = read_op;
1136215976Sjmallett    needed_s2m_type.s.wr_prior = write_priority;
1137215976Sjmallett    needed_s2m_type.s.rd_prior = read_priority;
1138215976Sjmallett    needed_s2m_type.s.src_id = srcid_index;
1139215976Sjmallett    needed_s2m_type.s.id16 = !!is16bit;
1140215976Sjmallett
1141215976Sjmallett    /* Build the needed SubID config */
1142215976Sjmallett    needed_subid.u64 = 0;
1143215976Sjmallett    needed_subid.s.port = srio_port;
1144215976Sjmallett    needed_subid.s.nmerge = 1;
1145215976Sjmallett
1146215976Sjmallett    /* FIXME: We might want to use the device ID swapping modes so the device
1147215976Sjmallett        ID is part of the lower address bits. This would allow many more
1148215976Sjmallett        devices to share S2M_TYPE indexes. This would require "base+size-1"
1149215976Sjmallett        to fit in bits [17:0] or bits[25:0] for 8 bits of device ID */
1150215976Sjmallett    if (base < (1ull<<34))
1151215976Sjmallett    {
1152215976Sjmallett        needed_subid.s.ba = destid;
1153215976Sjmallett        needed_s2m_type.s.iaow_sel = 0;
1154215976Sjmallett    }
1155215976Sjmallett    else if (base < (1ull<<42))
1156215976Sjmallett    {
1157215976Sjmallett        needed_subid.s.ba = (base>>34) & 0xff;
1158215976Sjmallett        needed_subid.s.ba |= ((uint64_t)destid & 0xff) << (42-34);
1159215976Sjmallett        needed_subid.s.ba |= (((uint64_t)destid>>8) & 0xff) << (51-34);
1160215976Sjmallett        needed_s2m_type.s.iaow_sel = 1;
1161215976Sjmallett    }
1162215976Sjmallett    else
1163215976Sjmallett    {
1164215976Sjmallett        if (destid>>8)
1165215976Sjmallett        {
1166215976Sjmallett            cvmx_dprintf("SRIO%d: Attempt to map 16bit device ID 0x%x using 66bit addressing\n", srio_port, destid);
1167215976Sjmallett            return 0;
1168215976Sjmallett        }
1169215976Sjmallett        if (base>>50)
1170215976Sjmallett        {
1171215976Sjmallett            cvmx_dprintf("SRIO%d: Attempt to map address 0x%llx using 66bit addressing\n", srio_port, (ULL)base);
1172215976Sjmallett            return 0;
1173215976Sjmallett        }
1174215976Sjmallett        needed_subid.s.ba = (base>>34) & 0xffff;
1175215976Sjmallett        needed_subid.s.ba |= ((uint64_t)destid & 0xff) << (51-34);
1176215976Sjmallett        needed_s2m_type.s.iaow_sel = 2;
1177215976Sjmallett    }
1178215976Sjmallett
1179215976Sjmallett    /* Find a S2M_TYPE index to use. If this fails return 0 */
1180215976Sjmallett    s2m_index = __cvmx_srio_alloc_s2m(srio_port, needed_s2m_type);
1181215976Sjmallett    if (s2m_index == -1)
1182215976Sjmallett        return 0;
1183215976Sjmallett
1184215976Sjmallett    /* Attach the SubID to the S2M_TYPE index */
1185215976Sjmallett    needed_subid.s.rtype = s2m_index & 3;
1186215976Sjmallett    needed_subid.s.wtype = s2m_index & 3;
1187215976Sjmallett    needed_subid.s.ba |= (((uint64_t)s2m_index >> 2) & 1) << (50-34);
1188215976Sjmallett    needed_subid.s.ba |= (((uint64_t)s2m_index >> 3) & 1) << (59-34);
1189215976Sjmallett
1190215976Sjmallett    /* Allocate a SubID for use */
1191215976Sjmallett    subdid = __cvmx_srio_alloc_subid(needed_subid);
1192215976Sjmallett    if (subdid == -1)
1193215976Sjmallett    {
1194215976Sjmallett        /* Free the s2m_index as we aren't using it */
1195215976Sjmallett        __cvmx_srio_free_s2m(srio_port, s2m_index);
1196215976Sjmallett        return 0;
1197215976Sjmallett    }
1198215976Sjmallett
1199215976Sjmallett    /* Build the final core physical address */
1200215976Sjmallett    sli_address.u64 = 0;
1201215976Sjmallett    sli_address.mem.io = 1;
1202215976Sjmallett    sli_address.mem.did = 3;
1203215976Sjmallett    sli_address.mem.subdid = subdid>>2;
1204215976Sjmallett    sli_address.mem.se = subdid & 3;
1205215976Sjmallett    sli_address.mem.address = base; /* Bits[33:0] of full address */
1206215976Sjmallett    return sli_address.u64;
1207215976Sjmallett}
1208215976Sjmallett
1209215976Sjmallett
1210215976Sjmallett/**
1211215976Sjmallett * Unmap a physical address window created by cvmx_srio_phys_map().
1212215976Sjmallett *
1213215976Sjmallett * @param physical_address
1214215976Sjmallett *               Physical address returned by cvmx_srio_phys_map().
1215215976Sjmallett * @param size   Size used on original call.
1216215976Sjmallett *
1217215976Sjmallett * @return Zero on success, negative on failure.
1218215976Sjmallett */
1219215976Sjmallettint cvmx_srio_physical_unmap(uint64_t physical_address, uint64_t size)
1220215976Sjmallett{
1221215976Sjmallett    cvmx_sli_mem_access_subidx_t subid;
1222215976Sjmallett    int subdid = (physical_address >> 40) & 7;
1223215976Sjmallett    int extender = (physical_address >> 34) & 3;
1224215976Sjmallett    int mem_index = subdid * 4 + extender;
1225215976Sjmallett    int read_s2m_type;
1226215976Sjmallett
1227215976Sjmallett    /* Get the subid setup so we can figure out where this mapping was for */
1228215976Sjmallett    subid.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(mem_index));
1229215976Sjmallett    /* Type[0] is mapped to the Relaxed Ordering
1230215976Sjmallett       Type[1] is mapped to the No Snoop
1231215976Sjmallett       Type[2] is mapped directly to bit 50 of the SLI address
1232215976Sjmallett       Type[3] is mapped directly to bit 59 of the SLI address */
1233215976Sjmallett    read_s2m_type = ((subid.s.ba>>(50-34))&1<<2) | ((subid.s.ba>>(59-34))&1<<3);
1234215976Sjmallett    read_s2m_type |= subid.s.rtype;
1235215976Sjmallett    __cvmx_srio_free_subid(mem_index);
1236215976Sjmallett    __cvmx_srio_free_s2m(subid.s.port, read_s2m_type);
1237215976Sjmallett    return 0;
1238215976Sjmallett}
1239215976Sjmallett#endif
1240