/* Copyright 2013 Freescale Semiconductor, Inc.
 * Copyright 2023 NXP
 *
 * 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 the above-listed copyright holders nor the
 * names of any contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 *
 * ALTERNATIVELY, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") as published by the Free Software
 * Foundation, either version 2 of that License or (at your option) any
 * later version.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**************************************************************************//**

 @File          endian.h

 @Description   Big/little endian swapping routines.
*//***************************************************************************/

#ifndef __FSL_ENDIAN_H
#define __FSL_ENDIAN_H

#include "common/types.h"
#include "common/fsl_core.h"



/**************************************************************************//**
 @Group         fsl_lib_endian_g Big/Little-Endian Conversion

 @Description   Routines and macros for Big/Little-Endian conversion and
                general byte swapping.

                All routines and macros are expecting unsigned values as
                parameters, but will generate the correct result also for
                signed values. Therefore, signed/unsigned casting is allowed.
 @{
*//***************************************************************************/

/**************************************************************************//**
 @Collection    Byte-Swap Macros

                Macros for swapping byte order.

 @Cautions      The parameters of these macros are evaluated multiple times.
                For calculated expressions or expressions that contain function
                calls it is recommended to use the byte-swap routines.

 @{
*//***************************************************************************/

/**************************************************************************//**
 @Description   Swaps the byte order of a given 16-bit value.

 @Param[in]     val - The 16-bit value to swap.

 @Return        The byte-swapped value..

 @Cautions      The given value is evaluated multiple times by this macro.
                For calculated expressions or expressions that contain function
                calls it is recommended to use the swap_uint16() routine.

 @hideinitializer
*//***************************************************************************/
#define SWAP_UINT16(val) \
    ((uint16_t)((((val) & 0x00ff) << 8) | (((val) & 0xff00) >> 8)))

/**************************************************************************//**
 @Description   Swaps the byte order of a given 32-bit value.

 @Param[in]     val - The 32-bit value to swap.

 @Return        The byte-swapped value..

 @Cautions      The given value is evaluated multiple times by this macro.
                For calculated expressions or expressions that contain function
                calls it is recommended to use the swap_uint32() routine.

 @hideinitializer
*//***************************************************************************/
#define SWAP_UINT32(val) \
    ((uint32_t)((((val) & 0x000000ff) << 24) | \
                (((val) & 0x0000ff00) <<  8) | \
                (((val) & 0x00ff0000) >>  8) | \
                (((val) & 0xff000000) >> 24)))

/**************************************************************************//**
 @Description   Swaps the byte order of a given 64-bit value.

 @Param[in]     val - The 64-bit value to swap.

 @Return        The byte-swapped value..

 @Cautions      The given value is evaluated multiple times by this macro.
                For calculated expressions or expressions that contain function
                calls it is recommended to use the swap_uint64() routine.

 @hideinitializer
*//***************************************************************************/
#define SWAP_UINT64(val) \
    ((uint64_t)((((val) & 0x00000000000000ffULL) << 56) | \
                (((val) & 0x000000000000ff00ULL) << 40) | \
                (((val) & 0x0000000000ff0000ULL) << 24) | \
                (((val) & 0x00000000ff000000ULL) <<  8) | \
                (((val) & 0x000000ff00000000ULL) >>  8) | \
                (((val) & 0x0000ff0000000000ULL) >> 24) | \
                (((val) & 0x00ff000000000000ULL) >> 40) | \
                (((val) & 0xff00000000000000ULL) >> 56)))

/* @} */

/**************************************************************************//**
 @Collection    Byte-Swap Routines

                Routines for swapping the byte order of a given parameter and
                returning the swapped value.

                These inline routines are safer than the byte-swap macros,
                because they evaluate the parameter expression only once.
 @{
*//***************************************************************************/

/**************************************************************************//**
 @Function      swap_uint16

 @Description   Returns the byte-swapped value of a given 16-bit value.

 @Param[in]     val - The 16-bit value.

 @Return        The byte-swapped value of the parameter.
*//***************************************************************************/
static inline uint16_t swap_uint16(uint16_t val)
{
    return (uint16_t)(((val & 0x00ff) << 8) |
                      ((val & 0xff00) >> 8));
}

/**************************************************************************//**
 @Function      swap_uint32

 @Description   Returns the byte-swapped value of a given 32-bit value.

 @Param[in]     val - The 32-bit value.

 @Return        The byte-swapped value of the parameter.
*//***************************************************************************/
static inline uint32_t swap_uint32(uint32_t val)
{
    return (uint32_t)(((val & 0x000000ff) << 24) |
                      ((val & 0x0000ff00) <<  8) |
                      ((val & 0x00ff0000) >>  8) |
                      ((val & 0xff000000) >> 24));
}

/**************************************************************************//**
 @Function      swap_uint64

 @Description   Returns the byte-swapped value of a given 64-bit value.

 @Param[in]     val - The 64-bit value.

 @Return        The byte-swapped value of the parameter.
*//***************************************************************************/
static inline uint64_t swap_uint64(uint64_t val)
{
    return (uint64_t)(((val & 0x00000000000000ffULL) << 56) |
                      ((val & 0x000000000000ff00ULL) << 40) |
                      ((val & 0x0000000000ff0000ULL) << 24) |
                      ((val & 0x00000000ff000000ULL) <<  8) |
                      ((val & 0x000000ff00000000ULL) >>  8) |
                      ((val & 0x0000ff0000000000ULL) >> 24) |
                      ((val & 0x00ff000000000000ULL) >> 40) |
                      ((val & 0xff00000000000000ULL) >> 56));
}

/* @} */

/**************************************************************************//**
 @Collection    In-place Byte-Swap-And-Set Routines

                Routines for swapping the byte order of a given variable and
                setting the swapped value back to the same variable.
 @{
*//***************************************************************************/

/**************************************************************************//**
 @Function      swap_uint16_p

 @Description   Swaps the byte order of a given 16-bit variable.

 @Param[in]     p_Val - Pointer to the 16-bit variable.

 @Return        None.
*//***************************************************************************/
static inline void swap_uint16_p(uint16_t *p_val)
{
    *p_val = swap_uint16(*p_val);
}

/**************************************************************************//**
 @Function      swap_uint32_p

 @Description   Swaps the byte order of a given 32-bit variable.

 @Param[in]     p_Val - Pointer to the 32-bit variable.

 @Return        None.
*//***************************************************************************/
static inline void swap_uint32_p(uint32_t *p_val)
{
    *p_val = swap_uint32(*p_val);
}

/**************************************************************************//**
 @Function      swap_uint64_p

 @Description   Swaps the byte order of a given 64-bit variable.

 @Param[in]     p_Val - Pointer to the 64-bit variable.

 @Return        None.
*//***************************************************************************/
static inline void swap_uint64_p(uint64_t *p_val)
{
    *p_val = swap_uint64(*p_val);
}

/* @} */


/**************************************************************************//**
 @Collection    Little-Endian Conversion Macros

                These macros convert given parameters to or from Little-Endian
                format. Use these macros when you want to read or write a specific
                Little-Endian value in memory, without a-priori knowing the CPU
                byte order.

                These macros use the byte-swap routines. For conversion of
                constants in initialization structures, you may use the CONST
                versions of these macros (see below), which are using the
                byte-swap macros instead.
 @{
*//***************************************************************************/

#ifdef CORE_IS_BIG_ENDIAN

#define CPU_TO_LE16(val)        swap_uint16(val)
#define CPU_TO_LE32(val)        swap_uint32(val)
#define CPU_TO_LE64(val)        swap_uint64(val)

#define CPU_TO_BE16(val)	((uint16_t)(val))
#define CPU_TO_BE32(val)	((uint32_t)(val))
#define CPU_TO_BE64(val)	((uint64_t)(val))

#else  /* CORE_IS_LITTLE_ENDIAN */

#define CPU_TO_LE16(val)	((uint16_t)(val))
#define CPU_TO_LE32(val)	((uint32_t)(val))
#define CPU_TO_LE64(val)	((uint64_t)(val))

#define CPU_TO_BE16(val)        swap_uint16(val)
#define CPU_TO_BE32(val)        swap_uint32(val)
#define CPU_TO_BE64(val)        swap_uint64(val)

#endif /* CORE_IS_LITTLE_ENDIAN */

#define LE16_TO_CPU(val)        CPU_TO_LE16(val)
#define LE32_TO_CPU(val)        CPU_TO_LE32(val)
#define LE64_TO_CPU(val)        CPU_TO_LE64(val)

#define BE16_TO_CPU(val)        CPU_TO_BE16(val)
#define BE32_TO_CPU(val)        CPU_TO_BE32(val)
#define BE64_TO_CPU(val)        CPU_TO_BE64(val)

/* @} */

/**************************************************************************//**
 @Collection    Little-Endian Constant Conversion Macros

                These macros convert given constants to or from Little-Endian
                format. Use these macros when you want to read or write a specific
                Little-Endian constant in memory, without a-priori knowing the
                CPU byte order.

                These macros use the byte-swap macros, therefore can be used for
                conversion of constants in initialization structures.

 @Cautions      The parameters of these macros are evaluated multiple times.
                For non-constant expressions, use the non-CONST macro versions.

 @{
*//***************************************************************************/
#ifdef CORE_IS_BIG_ENDIAN

#define CONST_CPU_TO_LE16(val)  SWAP_UINT16(val)
#define CONST_CPU_TO_LE32(val)  SWAP_UINT32(val)
#define CONST_CPU_TO_LE64(val)  SWAP_UINT64(val)

#define CONST_CPU_TO_BE16(val)  ((uint16_t)(val))
#define CONST_CPU_TO_BE32(val)  ((uint32_t)(val))
#define CONST_CPU_TO_BE64(val)  ((uint64_t)(val))

#else  /* CORE_IS_LITTLE_ENDIAN */

#define CONST_CPU_TO_LE16(val)  ((uint16_t)(val))
#define CONST_CPU_TO_LE32(val)  ((uint32_t)(val))
#define CONST_CPU_TO_LE64(val)  ((uint64_t)(val))

#define CONST_CPU_TO_BE16(val)  SWAP_UINT16(val)
#define CONST_CPU_TO_BE32(val)  SWAP_UINT32(val)
#define CONST_CPU_TO_BE64(val)  SWAP_UINT64(val)

#endif /* CORE_IS_LITTLE_ENDIAN */

#define CONST_LE16_TO_CPU(val)  CONST_CPU_TO_LE16(val)
#define CONST_LE32_TO_CPU(val)  CONST_CPU_TO_LE32(val)
#define CONST_LE64_TO_CPU(val)  CONST_CPU_TO_LE64(val)

#define CONST_BE16_TO_CPU(val)  CONST_CPU_TO_BE16(val)
#define CONST_BE32_TO_CPU(val)  CONST_CPU_TO_BE32(val)
#define CONST_BE64_TO_CPU(val)  CONST_CPU_TO_BE64(val)

/* @} */

/** @} */ /* end of fsl_lib_endian_g group */


#endif /* __FSL_ENDIAN_H */
