/***********************license start***************
 * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). All rights
 * reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.

 *   * Neither the name of Cavium Networks nor the names of
 *     its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written
 *     permission.

 * This Software, including technical data, may be subject to U.S. export  control
 * laws, including the U.S. Export Administration Act and its  associated
 * regulations, and may be subject to export or import  regulations in other
 * countries.

 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
 * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
 ***********************license end**************************************/



/**
 * @file
 *
 * Interface to SRIO
 *
 * <hr>$Revision: 41586 $<hr>
 */

#ifndef __CVMX_SRIO_H__
#define __CVMX_SRIO_H__

#ifdef	__cplusplus
extern "C" {
#endif

/**
 * Enumeration of the type of operations that can be performed
 * by a mapped write operation.
 */
typedef enum
{
    CVMX_SRIO_WRITE_MODE_NWRITE = 0,        /**< Only create NWrite operations */
    CVMX_SRIO_WRITE_MODE_NWRITE_RESP = 1,   /**< Create NWrite with response */
    CVMX_SRIO_WRITE_MODE_AUTO = 2,          /**< Intelligently breaks writes into multiple transactions based on alignment */
    CVMX_SRIO_WRITE_MODE_AUTO_RESP = 3,     /**< CVMX_SRIO_WRITE_MODE_WRITE followed with a response */
    CVMX_SRIO_WRITE_MODE_MAINTENANCE = 6,   /**< Create a MAINTENANCE transaction. Use cvmx_srio_config_write32() instead */
    CVMX_SRIO_WRITE_MODE_PORT = 7           /**< Port Write? */
} cvmx_srio_write_mode_t;

/**
 * Enumeration of the type of operations that can be performed
 * by a mapped read operation.
 */
typedef enum
{
    CVMX_SRIO_READ_MODE_NORMAL = 0,         /**< Perform a normal read */
    CVMX_SRIO_READ_MODE_ATOMIC_SET = 2,     /**< Atomically sets bits in data on remote device */
    CVMX_SRIO_READ_MODE_ATOMIC_CLEAR = 3,   /**< Atomically clears bits in data on remote device */
    CVMX_SRIO_READ_MODE_ATOMIC_INCREMENT = 4,/**< Atomically increments data on remote device */
    CVMX_SRIO_READ_MODE_ATOMIC_DECREMENT = 5,/**< Atomically decrements data on remote device */
    CVMX_SRIO_READ_MODE_MAINTENANCE = 6     /**< Create a MAINTENANCE transaction. Use cvmx_srio_config_read32() instead */
} cvmx_srio_read_mode_t;

/**
 * Initialization flags for SRIO
 */
typedef enum
{
    CVMX_SRIO_INITIALIZE_DEBUG = 1,
} cvmx_srio_initialize_flags_t;

/**
 * The possible results from a doorbell operation
 */
typedef enum
{
    CVMX_SRIO_DOORBELL_DONE,    /**< The doorbell is complete */
    CVMX_SRIO_DOORBELL_NONE,    /**< There wasn't an outstanding doorbell */
    CVMX_SRIO_DOORBELL_BUSY,    /**< The doorbell is still processing */
    CVMX_SRIO_DOORBELL_RETRY,   /**< The doorbell needs to be retried */
    CVMX_SRIO_DOORBELL_ERROR    /**< The doorbell failed with an error */
} cvmx_srio_doorbell_status_t;

/**
 * This structure represents the SRIO header received from SRIO on
 * the top of every received message. This header passes through
 * IPD/PIP unmodified.
 */
typedef struct
{
    union
    {
        uint64_t u64;
        struct
        {
#if __BYTE_ORDER == __BIG_ENDIAN
            uint64_t prio   : 2; /**< The sRIO prio (priority) field in the
                                    first sRIO message segment received for the
                                    message. */
            uint64_t tt     : 1; /**< When set, indicates that the first sRIO
                                    message segment received for the message had
                                    16-bit source and destination ID's. When
                                    clear, indicates 8-bit ID were present. */
            uint64_t dis    : 1; /**< When set, indicates that the destination
                                    ID in the first sRIO message segment received
                                    for the message matched the 63xx's secondary
                                    ID. When clear, indicates that the destination
                                    ID in the first sRIO message segment
                                    received for the message matched the 63xx's
                                    primary ID. Note that the full destination
                                    ID in the received sRIO message can be
                                    determined via the combination of
                                    WORD0[DIS] in the sRIO inbound message
                                    header and WORD1[iprt] in the work queue
                                    entry created by PIP/IPD. */
            uint64_t ssize  : 4; /**< The RIO ssize (standard message packet data
                                    size) field used for the message. */
            uint64_t sid    : 16; /**< The source ID in the first sRIO message
                                    segment received for the message. When TT is
                                    clear, the most-significant 8 bits are zero. */
            uint64_t xmbox  : 4; /**< The RIO xmbox (recipient mailbox extension)
                                    field in the first sRIO message segment
                                    received for the message. Always zero for
                                    multi-segment messages. */
            uint64_t mbox   : 2; /**< The RIO mbox (recipient mailbox) field in
                                    the first sRIO message segment received for
                                    the message. */
            uint64_t letter : 2; /**< The RIO letter (slot within a mailbox)
                                    field in the first sRIO message segment
                                    received for the message. */
            uint64_t seq    : 32; /**< A sequence number. Whenever the OCTEON
                                    63xx sRIO hardware accepts the first sRIO
                                    segment of either a message or doorbell, it
                                    samples the current value of a counter
                                    register and increments the counter
                                    register. SEQ is the value sampled for the
                                    message. The counter increments once per
                                    message/doorbell. SEQ can be used to
                                    determine the relative order of
                                    packets/doorbells. Note that the SEQ-implied
                                    order may differ from the order that the
                                    WQE's are received by software for a number
                                    of reasons, including the fact that the WQE
                                    is not created until the end of the message,
                                    while SEQ is sampled when the first segment. */
#else
            uint64_t seq    : 32;
            uint64_t letter : 2;
            uint64_t mbox   : 2;
            uint64_t xmbox  : 4;
            uint64_t sid    : 16;
            uint64_t ssize  : 4;
            uint64_t dis    : 1;
            uint64_t tt     : 1;
            uint64_t prio   : 2;
#endif
        } s;
    } word0;
    union
    {
        uint64_t u64;
        struct
        {
#if __BYTE_ORDER == __BIG_ENDIAN
            uint64_t r      : 1; /**< When set, WORD1[R]/PKT_INST_HDR[R] selects
                                    either RAWFULL or RAWSCHED special PIP
                                    instruction form. WORD1[R] may commonly be
                                    set so that WORD1[QOS,GRP] will be directly
                                    used by the PIP hardware. */
            uint64_t reserved_62_58 : 5;
            uint64_t pm     : 2; /**< WORD1[PM]/PKT_INST_HDR[PM] selects the PIP
                                    parse mode (uninterpreted, skip-to-L2,
                                    skip-to-IP), and chooses between
                                    RAWFULL/RAWSCHED when WORD1[R] is set. */
            uint64_t reserved_55 : 1;
            uint64_t sl     : 7; /**< WORD1[SL]/PKT_INST_HDR[SL] selects the
                                    skip II length. WORD1[SL] may typically be
                                    set to 8 (or larger) so that PIP skips this
                                    WORD1. */
            uint64_t reserved_47_46 : 2;
            uint64_t nqos   : 1; /**< WORD1[NQOS] must not be set when WORD1[R]
                                    is clear and PIP interprets WORD1 as a
                                    PKT_INST_HDR. When set, WORD1[NQOS]/PKT_INST_HDR[NQOS]
                                    prevents PIP from directly using
                                    WORD1[QOS]/PKT_INST_HDR[QOS] for the QOS
                                    value in the work queue entry created by
                                    PIP. WORD1[NQOS] may commonly be clear so
                                    that WORD1[QOS] will be directly used by the
                                    PIP hardware. PKT_INST_HDR[NQOS] is new to
                                    63xx - this functionality did not exist in
                                    prior OCTEON's. */
            uint64_t ngrp   : 1; /**< WORD1[NGRP] must not be set when WORD1[R]
                                    is clear and PIP interprets WORD1 as a
                                    PKT_INST_HDR. When set, WORD1[NGRP]/PKT_INST_HDR[NGRP]
                                    prevents PIP from directly using
                                    WORD1[GRP]/PKT_INST_HDR[GRP] for the GRP
                                    value in the work queue entry created by
                                    PIP. WORD1[NGRP] may commonly be clear so
                                    that WORD1[GRP] will be directly used by the
                                    PIP hardware. PKT_INST_HDR[NGRP] is new to
                                    63xx - this functionality did not exist in
                                    prior OCTEON's. */
            uint64_t ntt    : 1; /**< WORD1[NTT] must not be set when WORD1[R]
                                    is clear and PIP interprets WORD1 as a
                                    PKT_INST_HDR. When set, WORD1[NTT]/PKT_INST_HDR[NTT]
                                    prevents PIP from directly using
                                    WORD1[TT]/PKT_INST_HDR[TT] for the TT value
                                    in the work queue entry created by PIP.
                                    PKT_INST_HDR[NTT] is new to 63xx - this
                                    functionality did not exist in prior OCTEON's. */
            uint64_t ntag   : 1; /**< WORD1[NTAG] must not be set when WORD1[R]
                                    is clear and PIP interprets WORD1 as a
                                    PKT_INST_HDR. When set, WORD1[NTAG]/PKT_INST_HDR[NTAG]
                                    prevents PIP from directly using
                                    WORD1[TAG]/PKT_INST_HDR[TAG] for the TAG
                                    value in the work queue entry created by PIP.
                                    PKT_INST_HDR[NTAG] is new to 63xx - this
                                    functionality did not exist in prior OCTEON's. */
            uint64_t qos    : 3; /**< Created by the hardware from an entry in a
                                    256-entry table. The 8-bit value
                                    WORD0[PRIO,TT,DIS,MBOX,LETTER] selects the
                                    table entry. When WORD1[R] is set and WORD1[NQOS]
                                    is clear, WORD1[QOS] becomes the QOS value
                                    in the work queue entry created by PIP. The
                                    QOS value in the work queue entry determines
                                    the priority that SSO/POW will schedule the
                                    work, and can also control how/if the sRIO
                                    message gets dropped by PIP/IPD. The 256-entry
                                    table is unique to each sRIO core, but
                                    shared by the two controllers associated
                                    with the sRIO core. */
            uint64_t grp    : 4; /**< Created by the hardware from an entry in a
                                    256-entry table. The 8-bit value
                                    WORD0[PRIO,TT,DIS,MBOX,LETTER] selects the
                                    table entry. When WORD1[R] is set and WORD1[NGRP]
                                    is clear, WORD1[GRP] becomes the GRP value
                                    in the work queue entry created by PIP. The
                                    GRP value in the work queue entry can direct
                                    the work to particular cores or particular
                                    groups of cores. The 256-entry table is
                                    unique to each sRIO core, but shared by the
                                    two controllers associated with the sRIO core. */
            uint64_t rs     : 1; /**< In some configurations, enables the sRIO
                                    message to be buffered solely in the work
                                    queue entry, and not otherwise in L2/DRAM. */
            uint64_t tt     : 2; /**< When WORD1[R] is set and WORD1[NTT] is
                                    clear, WORD1[TT]/PKT_INST_HDR[TT] becomes
                                    the TT value in the work queue entry created
                                    by PIP. The TT and TAG values in the work
                                    queue entry determine the scheduling/synchronization
                                    constraints for the work (no constraints,
                                    tag order, atomic tag order). */
            uint64_t tag    : 32; /**< Created by the hardware from a CSR
                                    associated with the sRIO inbound message
                                    controller. When WORD1[R] is set and WORD1[NTAG]
                                    is clear, WORD1[TAG]/PKT_INST_HDR[TAG]
                                    becomes the TAG value in the work queue
                                    entry created by PIP. The TT and TAG values
                                    in the work queue entry determine the
                                    scheduling/synchronization constraints for
                                    the work (no constraints, tag order, atomic
                                    tag order). */
#else
            uint64_t tag    : 32;
            uint64_t tt     : 2;
            uint64_t rs     : 1;
            uint64_t grp    : 4;
            uint64_t qos    : 3;
            uint64_t ntag   : 1;
            uint64_t ntt    : 1;
            uint64_t ngrp   : 1;
            uint64_t nqos   : 1;
            uint64_t reserved_47_46 : 2;
            uint64_t sl     : 7;
            uint64_t reserved_55 : 1;
            uint64_t pm     : 2;
            uint64_t reserved_62_58 : 5;
            uint64_t r      : 1;
#endif
        } s;
    } word1;
} cvmx_srio_rx_message_header_t;

/**
 * This structure represents the SRIO header required on the front
 * of PKO packets destine for SRIO message queues.
 */
typedef union
{
    uint64_t u64;
    struct
    {
#if __BYTE_ORDER == __BIG_ENDIAN
        uint64_t prio   : 2;    /**< The sRIO prio (priority) field for all
                                    segments in the message. */
        uint64_t tt     : 1;    /**< When set, the sRIO message segments use a
                                    16-bit source and destination ID for all the
                                    segments in the message. When clear, the
                                    message segments use an 8-bit ID. */
        uint64_t sis    : 1;    /**< When set, the sRIO message segments use the
                                    63xx's secondary ID as the source ID. When
                                    clear, the sRIO message segments use the
                                    primary ID as the source ID. */
        uint64_t ssize  : 4;    /**< The RIO ssize (standard message segment
                                    data size) field used for the message. */
        uint64_t did    : 16;   /**< The destination ID in the sRIO message
                                    segments of the message. When TT is clear,
                                    the most-significant 8 bits must be zero. */
        uint64_t xmbox  : 4;    /**< The RIO xmbox (recipient mailbox extension)
                                    field in the sRIO message segment for a
                                    single-segment message. Must be zero for
                                    multi-segment messages. */
        uint64_t mbox   : 2;    /**< The RIO mbox (recipient mailbox) field in
                                    the sRIO message segments of the message. */
        uint64_t letter : 2;    /**< The RIO letter (slot within mailbox) field
                                    in the sRIO message segments of the message
                                    when LNS is clear. When LNS is set, this
                                    LETTER field is not used and must be zero. */
        uint64_t reserved_31_2 : 30;
        uint64_t lns    : 1;    /**< When set, the outbound message controller
                                    will dynamically selects an sRIO letter
                                    field for the message (based on LETTER_SP or
                                    LETTER_MP - see appendix A), and the LETTER
                                    field in this sRIO outbound message
                                    descriptor is unused. When clear, the LETTER
                                    field in this sRIO outbound message
                                    descriptor selects the sRIO letter used for
                                    the message. */
        uint64_t intr   : 1;    /**< When set, the outbound message controller
                                    will set an interrupt bit after all sRIO
                                    segments of the message receive a message
                                    DONE response. If the message transfer has
                                    errors, the interrupt bit is not set (but
                                    others are). */
#else
        uint64_t intr   : 1;
        uint64_t lns    : 1;
        uint64_t reserved_31_2 : 30;
        uint64_t letter : 2;
        uint64_t mbox   : 2;
        uint64_t xmbox  : 4;
        uint64_t did    : 16;
        uint64_t ssize  : 4;
        uint64_t sis    : 1;
        uint64_t tt     : 1;
        uint64_t prio   : 2;
#endif
    } s;
} cvmx_srio_tx_message_header_t;

/**
 * Initialize a SRIO port for use.
 *
 * @param srio_port SRIO port to initialize
 * @param flags     Optional flags
 *
 * @return Zero on success
 */
int cvmx_srio_initialize(int srio_port, cvmx_srio_initialize_flags_t flags);

/**
 * Read 32bits from a Device's config space
 *
 * @param srio_port SRIO port the device is on
 * @param srcid_index
 *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
 * @param destid    RapidIO device ID, or -1 for the local Octeon.
 * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
 *                  if transactions should use 8bit device IDs.
 * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
 * @param offset    Offset in config space. This must be a multiple of 32 bits.
 * @param result    Result of the read. This will be unmodified on failure.
 *
 * @return Zero on success, negative on failure.
 */
int cvmx_srio_config_read32(int srio_port, int srcid_index, int destid,
                            int is16bit, uint8_t hopcount, uint32_t offset,
                            uint32_t *result);

/**
 * Write 32bits to a Device's config space
 *
 * @param srio_port SRIO port the device is on
 * @param srcid_index
 *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
 * @param destid    RapidIO device ID, or -1 for the local Octeon.
 * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
 *                  if transactions should use 8bit device IDs.
 * @param hopcount  Number of hops to the remote device. Use 0 for the local Octeon.
 * @param offset    Offset in config space. This must be a multiple of 32 bits.
 * @param data      Data to write.
 *
 * @return Zero on success, negative on failure.
 */
int cvmx_srio_config_write32(int srio_port, int srcid_index, int destid,
                             int is16bit, uint8_t hopcount, uint32_t offset,
                             uint32_t data);

/**
 * Send a RapidIO doorbell to a remote device
 *
 * @param srio_port SRIO port the device is on
 * @param srcid_index
 *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
 * @param destid    RapidIO device ID.
 * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
 *                  if transactions should use 8bit device IDs.
 * @param priority  Doorbell priority (0-3)
 * @param data      Data for doorbell.
 *
 * @return Zero on success, negative on failure.
 */
int cvmx_srio_send_doorbell(int srio_port, int srcid_index, int destid,
                            int is16bit, int priority, uint16_t data);

/**
 * Get the status of the last doorbell sent. If the dooorbell
 * hardware is done, then the status is cleared to get ready for
 * the next doorbell (or retry).
 *
 * @param srio_port SRIO port to check doorbell on
 *
 * @return Doorbell status
 */
cvmx_srio_doorbell_status_t cvmx_srio_send_doorbell_status(int srio_port);

/**
 * Read a received doorbell and report data about it.
 *
 * @param srio_port SRIO port to check for the received doorbell
 * @param destid_index
 *                  Which Octeon destination ID was the doorbell for
 * @param sequence_num
 *                  Sequence number of doorbell (32bits)
 * @param srcid     RapidIO source ID of the doorbell sender
 * @param priority  Priority of the doorbell (0-3)
 * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
 *                  if transactions should use 8bit device IDs.
 * @param data      Data in the doorbell (16 bits)
 *
 * @return Doorbell status. Either DONE, NONE, or ERROR.
 */
cvmx_srio_doorbell_status_t cvmx_srio_receive_doorbell(int srio_port,
        int *destid_index, uint32_t *sequence_num, int *srcid, int *priority,
        int *is16bit, uint16_t *data);

/**
 * Receive a packet from the Soft Packet FIFO (SPF).
 *
 * @param srio_port SRIO port to read the packet from.
 * @param buffer    Buffer to receive the packet.
 * @param buffer_length
 *                  Length of the buffer in bytes.
 *
 * @return Returns the length of the packet read. Negative on failure.
 *         Zero if no packets are available.
 */
int cvmx_srio_receive_spf(int srio_port, void *buffer, int buffer_length);

/**
 * Map a remote device's memory region into Octeon's physical
 * address area. The caller can then map this into a core using
 * the TLB or XKPHYS.
 *
 * @param srio_port SRIO port to map the device on
 * @param write_op  Type of operation to perform on a write to the device.
 *                  Normally should be CVMX_SRIO_WRITE_MODE_AUTO.
 * @param write_priority
 *                  SRIO priority of writes (0-3)
 * @param read_op   Type of operation to perform on reads to the device.
 *                  Normally should be CVMX_SRIO_READ_MODE_NORMAL.
 * @param read_priority
 *                  SRIO priority of reads (0-3)
 * @param srcid_index
 *                  Which SRIO source ID to use. 0 = Primary, 1 = Secondary
 * @param destid    RapidIO device ID.
 * @param is16bit   Non zero if the transactions should use 16bit device IDs. Zero
 *                  if transactions should use 8bit device IDs.
 * @param base      Device base address to start the mapping
 * @param size      Size of the mapping in bytes
 *
 * @return Octeon 64bit physical address that accesses the remote device,
 *         or zero on failure.
 */
uint64_t cvmx_srio_physical_map(int srio_port, cvmx_srio_write_mode_t write_op,
        int write_priority, cvmx_srio_read_mode_t read_op, int read_priority,
        int srcid_index, int destid, int is16bit, uint64_t base, uint64_t size);

/**
 * Unmap a physical address window created by cvmx_srio_phys_map().
 *
 * @param physical_address
 *               Physical address returned by cvmx_srio_phys_map().
 * @param size   Size used on original call.
 *
 * @return Zero on success, negative on failure.
 */
int cvmx_srio_physical_unmap(uint64_t physical_address, uint64_t size);

#ifdef	__cplusplus
}
#endif

#endif
