/**
 * tiescbsp.c
 *
*/
/*
 * Copyright (c) 2015, Texas Instruments Incorporated
 * 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 Texas Instruments Incorporated 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 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 OWNER 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.
 **/
#include <string.h> // For memset/memcpy
#include "tiesc_eeprom.h" // header equivalent of ESI bin file
#include "tiescutils.h"
#include "types.h"
#include "hw_types.h"
#include "hw_icss.h"
#include "device.h"
#include <ti/sysbios/gates/GateAll.h>
#include <ti/sysbios/knl/Semaphore.h>
#ifndef USE_ECAT_TIMER
    #include <xdc/runtime/Timestamp.h>
#endif

#include <xdc/runtime/Types.h>

#include <ti/sysbios/knl/Task.h>

#include "tiesc_pruss_intc_mapping.h"
#include "osdrv_mdio.h"
#include "board_phy.h"

//TBD - #include "utils_plt.h"
#include <ti/sysbios/hal/Hwi.h>

#include "tieschw.h"
#include "tiesc_fw_cir_buff.h"

#include "tiescutils.h"

#include "gpio.h"
#ifdef AM43XX_FAMILY_BUILD
    #include "am437x.h"
    #include "hw_cm_per.h"
#elif defined(AM335X_FAMILY_BUILD)
    #include "soc_am335x.h"
    #include "board_spiflash.h"
#endif


#include "hw_icss_iep.h"
#include "hw_icss_mii_mdio.h"

static t_sm_properties sm_properties[MAX_SYNC_MAN];

static Semaphore_Handle semcmdlow_handle;

#ifndef USE_ECAT_TIMER
    volatile Uint32 ecat_timer_inc_p_ms;
#endif
volatile Uint32 *pru_frame_proc = NULL;
volatile Uint32 *pru_host_proc = NULL;
volatile Uint32 pru_frame_proc_len = 0;
volatile Uint32 pru_host_proc_len = 0;

extern Uint8 uartInstance;
#ifdef ENABLE_ONLINE_FIRMWARE_UPGRADE
    static Uint32 fw_download_flag;
    static Uint32 fw_write_offset;
#endif
static Uint32 current_low, prev_low;//Current and previous IEP time stamps

Uint32 pd_read_addr_err, pd_write_addr_err;
Uint32 pdi_read_fail_cnt, pdi_write_fail_cnt;

extern Uint8 *pEEPROM;
#ifdef EEPROM_SPI
    static Uint8 eeprom_updated = 0;
    static Uint32 eeprom_updated_time = 0;
#endif
Uint8 eeprom_cache[TIESC_EEPROM_SIZE];
extern boardId_t boardType;
extern PRUICSS_Handle pruIcss1Handle;
extern PRUICSS_Handle pruIcss0Handle;

/** pointer for ISR Args */
PRUICSS_IrqArgs *ecatIsrArgs;
/** pointer for ISR Args */
PRUICSS_IrqArgs *escCmdLowAckIsrArgs;
/** pointer for ISR Args */
PRUICSS_IrqArgs *sync0IsrArgs;
/** pointer for ISR Args */
PRUICSS_IrqArgs *sync1IsrArgs;

#ifdef ENABLE_PDI_REG_PERMISSIONS
    Uint8 pdi_reg_perm_array[4096];
#endif

#if ECAT_TIMER_INT
    void APPL_1MsTimerIsr(void);
#endif


/////////////////////////////////////////////////////////////////////////////////////////
/**
 \brief Interrupt service routin    e for the interrupts from the EtherCAT Slave Controller
*////////////////////////////////////////////////////////////////////////////////////////

void EcatIsr(void *args)
{
    #ifndef ENABLE_PDI_TASK
    #ifndef ENABLE_PDI_SWI
    PDI_Isr();
    #else
    PDI_Swi();
    #endif
    #endif
    bsp_clear_digio_out((PRUICSS_Handle)args, PDI_ISR_EDIO_NUM);
    PRUICSS_pruClearEvent((PRUICSS_Handle)args, PRU_ARM_EVENT0);
    ASSERT_DMB();
    ASSERT_DSB();
}

#ifndef SUPPORT_CMDACK_POLL_MODE
void EscCmdLowAckIsr(void *args)
{
    PRUICSS_pruClearEvent((PRUICSS_Handle)args, PRU_ARM_EVENT2);
    ASSERT_DMB();
    ASSERT_DSB();
}
#endif

void Sync0Isr(void *args)
{
    PRUICSS_pruClearEvent((PRUICSS_Handle)args, SYNC0_OUT_EVENT);
    ASSERT_DMB();
    ASSERT_DSB();
    #ifndef ENABLE_SYNC_TASK
    Sync0_Isr();
    #endif
    //bsp_pruss_iepreg_write((PRUICSS_Handle)args, 1, ICSS_IEP_SYNC0_STATUS_REG);
}

inline void Sync1Isr(void *args)
{
    PRUICSS_pruClearEvent((PRUICSS_Handle)args, SYNC1_OUT_EVENT);
    ASSERT_DMB();
    ASSERT_DSB();
    #ifndef ENABLE_SYNC_TASK
    Sync1_Isr();
    #endif
}

inline Uint32 bsp_get_timer_register(void)
{
    Uint32 ret;
    #ifdef USE_ECAT_TIMER
    bsp_get_local_sys_time(&current_low, 0);
    #else
    current_low = Timestamp_get32();
    #endif

    if(current_low > prev_low)
    {
        ret = current_low - prev_low;
    }

    else
    {
        ret = (0xFFFFFFFF - prev_low) + current_low;
    }

    return ret;
}

inline void bsp_clear_timer_register(void)
{
    #ifdef USE_ECAT_TIMER
    bsp_get_local_sys_time(&prev_low, 0);
    #else
    prev_low = Timestamp_get32();
    #endif
}

void bsp_get_local_sys_time(Uint32 *systime_low, Uint32 *systime_high)
{
    Uint32 ecat_systime_low, ecat_systime_high;
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcss1Handle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));

    if(systime_high)
    {
        bsp_send_command_to_firmware(pruIcss1Handle, CMD_DL_USER_READ_SYS_TIME, 0, 0);
        bsp_global_mutex_lock();
        ecat_systime_low = pHost2PruIntfc->system_time_low;
        ecat_systime_high = pHost2PruIntfc->system_time_high;
        bsp_global_mutex_unlock();
    }

    else
    {
        ecat_systime_low = bsp_pruss_iepreg_read(pruIcss1Handle, HW_ICSS_IEP_COUNT);
    }

    if(systime_low)
    {
        *systime_low =  ecat_systime_low;
    }

    if(systime_high)
    {
        *systime_high = ecat_systime_high;
    }
}

void bsp_get_latch0_posedge_time(PRUICSS_Handle pruIcssHandle,
                                 Uint32 *systime_low, Uint32 *systime_high)
{
    if(0 == bsp_pdi_access_perm_array(ESC_ADDR_LATCH0_POS_EDGE, TIESC_PERM_READ,
                                      8))
    {
        pdi_read_fail_cnt++;
        return;
    }

    while(bsp_hwspinlock_lock(0));

    bsp_global_mutex_lock();

    if(systime_low)
    {
        *systime_low  = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH0_POS_EDGE) >> 2)]);
    }

    if(systime_high)
    {
        *systime_high = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH0_POS_EDGE + 4) >> 2)]);
    }

    bsp_global_mutex_unlock();
    bsp_hwspinlock_unlock(0);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                 LATCH0_POS_EDGE, 0);
}

void bsp_get_latch0_negedge_time(PRUICSS_Handle pruIcssHandle,
                                 Uint32 *systime_low, Uint32 *systime_high)
{
    if(0 == bsp_pdi_access_perm_array(ESC_ADDR_LATCH0_NEG_EDGE, TIESC_PERM_READ,
                                      8))
    {
        pdi_read_fail_cnt++;
        return;
    }

    while(bsp_hwspinlock_lock(0));

    bsp_global_mutex_lock();

    if(systime_low)
    {
        *systime_low  = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH0_NEG_EDGE) >> 2)]);
    }

    if(systime_high)
    {
        *systime_high = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH0_NEG_EDGE + 4) >> 2)]);
    }

    bsp_global_mutex_unlock();
    bsp_hwspinlock_unlock(0);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                 LATCH0_NEG_EDGE, 0);
}
void bsp_get_latch1_posedge_time(PRUICSS_Handle pruIcssHandle,
                                 Uint32 *systime_low, Uint32 *systime_high)
{
    if(0 == bsp_pdi_access_perm_array(ESC_ADDR_LATCH1_POS_EDGE, TIESC_PERM_READ,
                                      8))
    {
        pdi_read_fail_cnt++;
        return;
    }

    while(bsp_hwspinlock_lock(0));

    bsp_global_mutex_lock();

    if(systime_low)
    {
        *systime_low  = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH1_POS_EDGE) >> 2)]);
    }

    if(systime_high)
    {
        *systime_high = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH1_POS_EDGE + 4) >> 2)]);
    }

    bsp_global_mutex_unlock();
    bsp_hwspinlock_unlock(0);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                 LATCH1_POS_EDGE, 0);
}
void bsp_get_latch1_negedge_time(PRUICSS_Handle pruIcssHandle,
                                 Uint32 *systime_low, Uint32 *systime_high)
{
    if(0 == bsp_pdi_access_perm_array(ESC_ADDR_LATCH1_NEG_EDGE, TIESC_PERM_READ,
                                      8))
    {
        pdi_read_fail_cnt++;
        return;
    }

    while(bsp_hwspinlock_lock(0));

    bsp_global_mutex_lock();

    if(systime_low)
    {
        *systime_low  = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH1_NEG_EDGE) >> 2)]);
    }

    if(systime_high)
    {
        *systime_high = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                          pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                                  ESC_ADDR_LATCH1_NEG_EDGE + 4) >> 2)]);
    }

    bsp_global_mutex_unlock();
    bsp_hwspinlock_unlock(0);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                 LATCH1_NEG_EDGE, 0);
}

#if defined(SYSTEM_TIME_PDI_CONTROLLED) || defined(FORCE_SYSTEM_TIME_PDI_CONTROLLED_API)
void bsp_pdi_write_system_time(PRUICSS_Handle pruIcssHandle, Uint32 systime)
{
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));
    *(Uint32 *)(&pHost2PruIntfc->resp1low) = systime;
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_SYSTIME_PDI_CONTROL,
                                 WRITE_SYSTIME, 0);
}
void bsp_pdi_write_system_timeoffset(PRUICSS_Handle pruIcssHandle,
                                     unsigned long long systime)
{
    bsp_write(pruIcssHandle, (Uint8 *)&systime, ESC_ADDR_SYSTIME_OFFSET, 8);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_SYSTIME_PDI_CONTROL,
                                 WRITE_SYSTIME_OFFSET, 0);
}
void bsp_pdi_write_systime_delay(PRUICSS_Handle pruIcssHandle,
                                 Uint32 systime)
{
    bsp_write_dword(pruIcssHandle, systime, ESC_ADDR_SYSTIME_DELAY);
}
void bsp_pdi_write_filterconfig(PRUICSS_Handle pruIcssHandle,
                                Uint16 speedcount_start, Uint8 speedcount_filtdepth, Uint8 systime_filtdepth)
{
    bsp_write_word(pruIcssHandle, speedcount_start, ESC_ADDR_SPEEDCOUNTER_START);
    bsp_write_word(pruIcssHandle,
                   (speedcount_filtdepth << 8 | systime_filtdepth),
                   ESC_ADDR_TIMEDIFF_FILTDEPTH);
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_SYSTIME_PDI_CONTROL,
                                 WRITE_FILTER_CONFIG, 0);
}
#endif
inline void bsp_set_pdi_wd_trigger_mode(PRUICSS_Handle pruIcssHandle,
                                        Uint32 mode)
{
    //PDI WD trigger also depends on DIGIO h/w events in ICSS and by default triggered on RX SOF events on both ports
    //This function can be used to override this behaviour in h/w - it is not possible to disable DIGIO dependency and make
    //PDI WD trigger manually in firmware for every command send - so allow user to configure - trigger mechansim
    //LATCH_IN  event or SYNC0/1_out - New application default is LATCH_IN event
    HWREG(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
          PRU_ICSS_IEP + HW_ICSS_IEP_DIGIO_CTRL) = mode;
}

inline void bsp_set_digio_sw_dataout_enable(PRUICSS_Handle pruIcssHandle)
{
    HWREG(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
          PRU_ICSS_IEP + HW_ICSS_IEP_DIGIO_EXP) |= 0x1;
}

inline void bsp_set_digio_out(PRUICSS_Handle pruIcssHandle, Uint8 num)
{
    HWREG(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
          PRU_ICSS_IEP + HW_ICSS_IEP_DIGIO_DATA_OUT) |= (1 << num);
}

inline void bsp_clear_digio_out(PRUICSS_Handle pruIcssHandle, Uint8 num)
{
    HWREG(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
          PRU_ICSS_IEP + HW_ICSS_IEP_DIGIO_DATA_OUT) &= ~(1 << num);
}

void bsp_eeprom_emulation_init(void)
{
    Uint32 itr = 0;

    #ifdef EEPROM_SPI
    Uint16 u16Crc = 0x00FF, i, j;
    int invalid_crc_flag = 0;

    Board_readFlashStorage(SPI_EEPROM_DATA_OFFSET, TIESC_EEPROM_SIZE,
                           (uint8_t *)eeprom_cache);

    if(E_FAIL == Board_readFlashStorage(SPI_EEPROM_DATA_OFFSET, TIESC_EEPROM_SIZE,
                                        (uint8_t *)eeprom_cache))
    {
        invalid_crc_flag = 1;
    }

    else
    {
        Uint32 temp_reg = 0;

        for(i = 0; i < 14; i++)
        {
            u16Crc ^= eeprom_cache[i];

            for(j = 0; j < 8; j++)
            {
                if(u16Crc & 0x80)
                {
                    u16Crc = (u16Crc << 1) ^ 0x07;
                }

                else
                {
                    u16Crc <<= 1;
                }
            }
        }

        /*only low Byte shall be written*/
        u16Crc &= 0x00FF;

        if(u16Crc != eeprom_cache[14])
        {
            invalid_crc_flag = 1;
        }

        temp_reg = *(Uint32 *)((Uint8 *)(eeprom_cache + (0xC << 1)));

        temp_reg = SWAPDWORD(temp_reg);

        if(temp_reg != (Uint32)TIESC_REVISION_NUMBER)
        {
            invalid_crc_flag = 1;
        }
    }

    if(1 == invalid_crc_flag)
    {
    #endif

        for(itr = 0; itr < TIESC_EEPROM_SIZE; itr++)
        {
            eeprom_cache[itr] = tiesc_eeprom[itr];
        }

        #ifdef EEPROM_SPI
    }

        #endif
    pEEPROM = eeprom_cache;
}

Int32 bsp_eeprom_load_esc_registers(PRUICSS_Handle pruIcssHandle,
                                    Int32 reload_flag)
{
    //Validate CRC before loading to ESC registers
    Uint16 u16Crc = 0x00FF, i, j;
    Int32 invalid_crc_flag = 0;

    for(i = 0; i < 14; i++)
    {
        u16Crc ^= eeprom_cache[i];

        for(j = 0; j < 8; j++)
        {
            if(u16Crc & 0x80)
            {
                u16Crc = (u16Crc << 1) ^ 0x07;
            }

            else
            {
                u16Crc <<= 1;
            }
        }
    }

    /*only low Byte shall be written*/
    u16Crc &= 0x00FF;

    if(u16Crc != eeprom_cache[14])
    {
        //printf("Error: EEPROM validation failed for config area\n");
        invalid_crc_flag = 1;
    }

    /*write new claculated Crc to Esc Config area*/
    if(!reload_flag)
    {
        //Not a reload operation - but initial loading
        //0x150 and 0x152 not reloaded according to beckhoff
        if(!invalid_crc_flag)
        {
            bsp_write_byte(pruIcssHandle, eeprom_cache[8], ESC_ADDR_CONFIG_STATION_ALIAS);
            bsp_write_byte(pruIcssHandle, eeprom_cache[9],
                           ESC_ADDR_CONFIG_STATION_ALIAS + 1);
            bsp_write_byte(pruIcssHandle, eeprom_cache[0], ESC_ADDR_PDI_CONTROL);
            bsp_write_byte(pruIcssHandle, eeprom_cache[1], ESC_ADDR_PDI_CONTROL + 1);
        }

        else
        {
            return -1;
        }
    }

    if(!invalid_crc_flag)
    {
        bsp_write_byte(pruIcssHandle, eeprom_cache[4], ESC_ADDR_SYNC_PULSE_LENGTH);
        bsp_write_byte(pruIcssHandle, eeprom_cache[5],
                       ESC_ADDR_SYNC_PULSE_LENGTH + 1);
    }

    else
    {
        return -1;
    }

    return 0;
}
Int32 bsp_eeprom_emulation_reload(PRUICSS_Handle pruIcssHandle)
{
    return bsp_eeprom_load_esc_registers(pruIcssHandle, 1);
}

void bsp_eeprom_emulation_command_ack(PRUICSS_Handle pruIcssHandle)
{
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_EEPROM_CMD_ACK, 0, 0);
}

void bsp_eeprom_emulation_flush(void)
{
    #ifdef EEPROM_SPI
    Board_writeFlashStorage(SPI_EEPROM_DATA_OFFSET, TIESC_EEPROM_SIZE,
                            (uint8_t *)eeprom_cache, 1);
    #endif
}

void bsp_eeprom_emulation_exit(void)
{
    bsp_eeprom_emulation_flush();
}

void bsp_esc_reg_perm_init(PRUICSS_Handle pruIcssHandle)
{
    int i;
    volatile t_register_properties *pRegPerm = (volatile t_register_properties *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(1));
    #if 0
    pRegPerm->reg_properties[0x0] = TIESC_PERM_READ_ONLY; //Type
    pRegPerm->reg_properties[0x1] = TIESC_PERM_READ_ONLY; //Revision
    pRegPerm->reg_properties[0x2] = TIESC_PERM_READ_ONLY; //Build
    pRegPerm->reg_properties[0x3] = TIESC_PERM_READ_ONLY; //Build
    pRegPerm->reg_properties[0x4] = TIESC_PERM_READ_ONLY; //FMMUs
    pRegPerm->reg_properties[0x5] = TIESC_PERM_READ_ONLY; //SMs
    pRegPerm->reg_properties[0x6] = TIESC_PERM_READ_ONLY; //RAM size
    pRegPerm->reg_properties[0x7] = TIESC_PERM_READ_ONLY; //Port descriptor
    pRegPerm->reg_properties[0x8] = TIESC_PERM_READ_ONLY; //ESC features
    pRegPerm->reg_properties[0x9] = TIESC_PERM_READ_ONLY; //ESC features
    #else

    for(i = 0; i < 10; i++)
    {
        pRegPerm->reg_properties[i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    pRegPerm->reg_properties[0x10] = TIESC_PERM_RW; //Configured Station address
    pRegPerm->reg_properties[0x11] = TIESC_PERM_RW; //Configured Station address
    pRegPerm->reg_properties[0x12] =
        TIESC_PERM_READ_ONLY; //Configured Station alias
    pRegPerm->reg_properties[0x13] =
        TIESC_PERM_READ_ONLY; //Configured Station alias
    pRegPerm->reg_properties[0x100] = TIESC_PERM_RW; //DL control
    pRegPerm->reg_properties[0x101] = TIESC_PERM_RW; //DL control
    pRegPerm->reg_properties[0x102] = TIESC_PERM_RW; //DL control
    pRegPerm->reg_properties[0x103] = TIESC_PERM_RW; //DL control
    pRegPerm->reg_properties[0x108] = TIESC_PERM_RW; //Physical RW offset
    pRegPerm->reg_properties[0x109] = TIESC_PERM_RW; //Physical RW offset
    pRegPerm->reg_properties[0x110] = TIESC_PERM_READ_ONLY; //ESC DL status
    pRegPerm->reg_properties[0x111] = TIESC_PERM_READ_ONLY; //ESC DL status
    pRegPerm->reg_properties[0x120] = TIESC_PERM_RW; //AL control
    pRegPerm->reg_properties[0x121] = TIESC_PERM_RW; //AL control
    pRegPerm->reg_properties[0x130] = TIESC_PERM_READ_ONLY; //ESC AL status
    pRegPerm->reg_properties[0x131] = TIESC_PERM_READ_ONLY; //ESC AL status
    pRegPerm->reg_properties[0x134] = TIESC_PERM_READ_ONLY; //ESC AL status code
    pRegPerm->reg_properties[0x135] = TIESC_PERM_READ_ONLY; //ESC AL status code
    pRegPerm->reg_properties[0x140] = TIESC_PERM_READ_ONLY; //ESC PDI control
    pRegPerm->reg_properties[0x141] = TIESC_PERM_READ_ONLY; //ESC configuration
    pRegPerm->reg_properties[0x150] = TIESC_PERM_READ_ONLY; //Onchip configuration
    pRegPerm->reg_properties[0x151] = TIESC_PERM_READ_ONLY; //SYNC/LATCH PDI configuration
    pRegPerm->reg_properties[0x152] = TIESC_PERM_READ_ONLY; //Onchip extended configuration
    pRegPerm->reg_properties[0x153] = TIESC_PERM_READ_ONLY; //Onchip extended configuration
    pRegPerm->reg_properties[0x200] = TIESC_PERM_RW; //ECAT event mask
    pRegPerm->reg_properties[0x201] = TIESC_PERM_RW; //ECAT event mask
    pRegPerm->reg_properties[0x204] = TIESC_PERM_READ_ONLY; //AL event mask
    pRegPerm->reg_properties[0x205] = TIESC_PERM_READ_ONLY; //AL event mask
    pRegPerm->reg_properties[0x206] = TIESC_PERM_READ_ONLY; //AL event mask
    pRegPerm->reg_properties[0x207] = TIESC_PERM_READ_ONLY; //AL event mask
    pRegPerm->reg_properties[0x210] = TIESC_PERM_READ_ONLY; //ECAT event request
    pRegPerm->reg_properties[0x211] = TIESC_PERM_READ_ONLY; //ECAT event request
    pRegPerm->reg_properties[0x220] = TIESC_PERM_READ_ONLY; //AL event request
    pRegPerm->reg_properties[0x221] = TIESC_PERM_READ_ONLY; //AL event request
    pRegPerm->reg_properties[0x222] = TIESC_PERM_READ_ONLY; //AL event request
    pRegPerm->reg_properties[0x223] = TIESC_PERM_READ_ONLY; //AL event request
    pRegPerm->reg_properties[0x300] = TIESC_PERM_RW; //Invalid frame counter Port0
    pRegPerm->reg_properties[0x301] = TIESC_PERM_RW; //RX_ERR counter Port0
    pRegPerm->reg_properties[0x302] = TIESC_PERM_RW; //Invalid frame counter Port1
    pRegPerm->reg_properties[0x303] = TIESC_PERM_RW; //RX_ERR counter Port1
    pRegPerm->reg_properties[0x308] = TIESC_PERM_RW; //Forwarded Error Port0
    pRegPerm->reg_properties[0x309] = TIESC_PERM_RW; //Forwarded Error Port1
    pRegPerm->reg_properties[0x30C] = TIESC_PERM_RW; //ECAT processing unit counter
    pRegPerm->reg_properties[0x310] = TIESC_PERM_RW; //Link lost counter Port0
    pRegPerm->reg_properties[0x311] = TIESC_PERM_RW; //Link lost counter Port1
    pRegPerm->reg_properties[0x400] = TIESC_PERM_RW; //Watchdog divider
    pRegPerm->reg_properties[0x401] = TIESC_PERM_RW; //Watchdog divider
    pRegPerm->reg_properties[0x410] = TIESC_PERM_RW; //Watchdog time PDI
    pRegPerm->reg_properties[0x411] = TIESC_PERM_RW; //Watchdog time PDI
    pRegPerm->reg_properties[0x420] = TIESC_PERM_RW; //Watchdog time PD
    pRegPerm->reg_properties[0x421] = TIESC_PERM_RW; //Watchdog time PD
    pRegPerm->reg_properties[0x440] = TIESC_PERM_READ_ONLY; //Watchdog process data
    pRegPerm->reg_properties[0x441] = TIESC_PERM_READ_ONLY; //Watchdog process data
    pRegPerm->reg_properties[0x442] = TIESC_PERM_RW; //Watchdog counter PD
    pRegPerm->reg_properties[0x443] = TIESC_PERM_RW; //Watchdog counter PDI
    pRegPerm->reg_properties[0x500] = TIESC_PERM_RW; //EEPROM configuration
    pRegPerm->reg_properties[0x501] = TIESC_PERM_READ_ONLY; //EEPROM PDI access state
    #if 0
    pRegPerm->reg_properties[0x502] = TIESC_PERM_RW; //EEPROM control/status
    pRegPerm->reg_properties[0x503] = TIESC_PERM_RW; //EEPROM control/status
    pRegPerm->reg_properties[0x504] = TIESC_PERM_RW; //EEPROM address
    pRegPerm->reg_properties[0x505] = TIESC_PERM_RW; //EEPROM address
    pRegPerm->reg_properties[0x506] = TIESC_PERM_RW; //EEPROM address
    pRegPerm->reg_properties[0x507] = TIESC_PERM_RW; //EEPROM address
    pRegPerm->reg_properties[0x508] = TIESC_PERM_RW; //EEPROM data0
    pRegPerm->reg_properties[0x509] = TIESC_PERM_RW; //EEPROM data0
    #else

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x502 + i] = TIESC_PERM_RW;
    }

    #endif
    #if 0
    pRegPerm->reg_properties[0x50A] = TIESC_PERM_READ_ONLY; //EEPROM data1
    pRegPerm->reg_properties[0x50B] = TIESC_PERM_READ_ONLY; //EEPROM data1
    pRegPerm->reg_properties[0x50C] = TIESC_PERM_READ_ONLY; //EEPROM data2
    pRegPerm->reg_properties[0x50D] = TIESC_PERM_READ_ONLY; //EEPROM data2
    pRegPerm->reg_properties[0x50E] = TIESC_PERM_READ_ONLY; //EEPROM data3
    pRegPerm->reg_properties[0x50F] = TIESC_PERM_READ_ONLY; //EEPROM data3
    #else

    for(i = 0; i < 6; i++)
    {
        pRegPerm->reg_properties[0x50A + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #if 0
    pRegPerm->reg_properties[0x510] = TIESC_PERM_RW; //MII management control and status
    pRegPerm->reg_properties[0x511] = TIESC_PERM_RW; //MII management control and status
    pRegPerm->reg_properties[0x512] = TIESC_PERM_RW; //MII management PHY address
    pRegPerm->reg_properties[0x513] = TIESC_PERM_RW; //MII management PHY register address
    pRegPerm->reg_properties[0x514] = TIESC_PERM_RW; //MII management PHY data
    pRegPerm->reg_properties[0x515] = TIESC_PERM_RW; //MII management PHY data
    #else

    for(i = 0; i < 6; i++)
    {
        pRegPerm->reg_properties[0x510 + i] = TIESC_PERM_RW;
    }

    #endif

    for(i = 0; i < 8; i++)    //8 FMMUs
    {
        memset((void *)&pRegPerm->reg_properties[0x600 + i * 16], TIESC_PERM_RW,
               13);
        //memset((void*)&pRegPerm->reg_properties[0x60D+i*16], TIESC_PERM_READ_ONLY, 3);//Mark reserved bytes read only
    }

    for(i = 0; i < 8; i++)    //8 SMs
    {
        memset((void *)&pRegPerm->reg_properties[0x800 + i * 8], TIESC_PERM_RW, 5);
        memset((void *)&pRegPerm->reg_properties[0x805 + i * 8], TIESC_PERM_READ_ONLY, 1);
        memset((void *)&pRegPerm->reg_properties[0x806 + i * 8], TIESC_PERM_RW, 1);
        memset((void *)&pRegPerm->reg_properties[0x807 + i * 8], TIESC_PERM_READ_ONLY, 1);
    }

    #if 0
    pRegPerm->reg_properties[0x900] = TIESC_PERM_RW; //Receive Time Port0
    pRegPerm->reg_properties[0x901] = TIESC_PERM_READ_ONLY; //Receive Time Port0
    pRegPerm->reg_properties[0x902] = TIESC_PERM_READ_ONLY; //Receive Time Port0
    pRegPerm->reg_properties[0x903] = TIESC_PERM_READ_ONLY; //Receive Time Port0
    #else
    pRegPerm->reg_properties[0x900] = TIESC_PERM_RW;
    #endif

    #if 0
    pRegPerm->reg_properties[0x904] = TIESC_PERM_READ_ONLY; //Receive Time Port1
    pRegPerm->reg_properties[0x905] = TIESC_PERM_READ_ONLY; //Receive Time Port1
    pRegPerm->reg_properties[0x906] = TIESC_PERM_READ_ONLY; //Receive Time Port1
    pRegPerm->reg_properties[0x907] = TIESC_PERM_READ_ONLY; //Receive Time Port1
    pRegPerm->reg_properties[0x908] = TIESC_PERM_READ_ONLY; //Receive Time Port2
    pRegPerm->reg_properties[0x909] = TIESC_PERM_READ_ONLY; //Receive Time Port2
    pRegPerm->reg_properties[0x90A] = TIESC_PERM_READ_ONLY; //Receive Time Port2
    pRegPerm->reg_properties[0x90B] = TIESC_PERM_READ_ONLY; //Receive Time Port2
    pRegPerm->reg_properties[0x90C] = TIESC_PERM_READ_ONLY; //Receive Time Port3
    pRegPerm->reg_properties[0x90D] = TIESC_PERM_READ_ONLY; //Receive Time Port3
    pRegPerm->reg_properties[0x90E] = TIESC_PERM_READ_ONLY; //Receive Time Port3
    pRegPerm->reg_properties[0x90F] = TIESC_PERM_READ_ONLY; //Receive Time Port3
    #else

    for(i = 0; i < 15; i++)
    {
        pRegPerm->reg_properties[0x901 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #if 0
    pRegPerm->reg_properties[0x910] = TIESC_PERM_RW; //System Time
    pRegPerm->reg_properties[0x911] = TIESC_PERM_RW; //System Time
    pRegPerm->reg_properties[0x912] = TIESC_PERM_RW; //System Time
    pRegPerm->reg_properties[0x913] = TIESC_PERM_RW; //System Time
    pRegPerm->reg_properties[0x914] = TIESC_PERM_READ_ONLY; //System Time
    pRegPerm->reg_properties[0x915] = TIESC_PERM_READ_ONLY; //System Time
    pRegPerm->reg_properties[0x916] = TIESC_PERM_READ_ONLY; //System Time
    pRegPerm->reg_properties[0x917] = TIESC_PERM_READ_ONLY; //System Time
    #else
    #ifndef SYSTEM_TIME_PDI_CONTROLLED

    for(i = 0; i < 4; i++)
    {
        pRegPerm->reg_properties[0x910 + i] = TIESC_PERM_RW;
    }

    for(i = 0; i < 4; i++)
    {
        pRegPerm->reg_properties[0x914 + i] = TIESC_PERM_READ_ONLY;
    }

    #else

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x910 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #endif

    #if 0
    pRegPerm->reg_properties[0x918] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x919] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91A] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91B] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91C] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91D] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91E] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    pRegPerm->reg_properties[0x91F] =
        TIESC_PERM_READ_ONLY; //Receive Time ECAT processing
    #else

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x918 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif

    #if 0
    pRegPerm->reg_properties[0x920] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x921] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x922] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x923] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x924] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x925] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x926] = TIESC_PERM_RW; //System Time Offset
    pRegPerm->reg_properties[0x927] = TIESC_PERM_RW; //System Time Offset

    pRegPerm->reg_properties[0x928] = TIESC_PERM_RW; //System Time Delay
    pRegPerm->reg_properties[0x929] = TIESC_PERM_RW; //System Time Delay
    pRegPerm->reg_properties[0x92A] = TIESC_PERM_RW; //System Time Delay
    pRegPerm->reg_properties[0x92B] = TIESC_PERM_RW; //System Time Delay
    #else
    #ifndef SYSTEM_TIME_PDI_CONTROLLED

    for(i = 0; i < 12; i++)
    {
        pRegPerm->reg_properties[0x920 + i] = TIESC_PERM_RW;
    }

    #else

    for(i = 0; i < 12; i++)
    {
        pRegPerm->reg_properties[0x920 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #endif
    pRegPerm->reg_properties[0x92C] = TIESC_PERM_READ_ONLY; //System Time Difference
    pRegPerm->reg_properties[0x92D] = TIESC_PERM_READ_ONLY; //System Time Difference
    pRegPerm->reg_properties[0x92E] = TIESC_PERM_READ_ONLY; //System Time Difference
    pRegPerm->reg_properties[0x92F] = TIESC_PERM_READ_ONLY; //System Time Difference
    #ifndef SYSTEM_TIME_PDI_CONTROLLED
    pRegPerm->reg_properties[0x930] = TIESC_PERM_RW; //Speed counter Start
    pRegPerm->reg_properties[0x931] = TIESC_PERM_RW; //Speed counter Start
    #else
    pRegPerm->reg_properties[0x930] = TIESC_PERM_READ_ONLY; //Speed counter Start
    pRegPerm->reg_properties[0x931] = TIESC_PERM_READ_ONLY; //Speed counter Start
    #endif
    pRegPerm->reg_properties[0x932] = TIESC_PERM_READ_ONLY; //Speed counter Diff
    pRegPerm->reg_properties[0x933] = TIESC_PERM_READ_ONLY; //Speed counter Diff

    #ifndef SYSTEM_TIME_PDI_CONTROLLED
    pRegPerm->reg_properties[0x934] =
        TIESC_PERM_RW; //System Time Difference Filter Depth
    pRegPerm->reg_properties[0x935] = TIESC_PERM_RW; //Speed counter Filter Depth
    #else
    pRegPerm->reg_properties[0x934] =
        TIESC_PERM_READ_ONLY; //System Time Difference Filter Depth
    pRegPerm->reg_properties[0x935] =
        TIESC_PERM_READ_ONLY; //Speed counter Filter Depth
    #endif
    pRegPerm->reg_properties[0x980] = TIESC_PERM_RW;
    #ifndef SYSTEM_TIME_PDI_CONTROLLED
    pRegPerm->reg_properties[0x981] = TIESC_PERM_RW; //Sync Activation
    #else
    pRegPerm->reg_properties[0x981] = TIESC_PERM_READ_ONLY; //Sync Activation
    #endif

    pRegPerm->reg_properties[0x982] =
        TIESC_PERM_READ_ONLY; //Pulse length of Sync Signals
    pRegPerm->reg_properties[0x983] =
        TIESC_PERM_READ_ONLY; //Pulse length of Sync Signals
    //pRegPerm->reg_properties[0x984]= TIESC_PERM_READ_ONLY;//SYNC Activation status
    pRegPerm->reg_properties[0x98E] = TIESC_PERM_READ_ONLY; //SYNC0 status
    pRegPerm->reg_properties[0x98F] = TIESC_PERM_READ_ONLY; //SYNC1 status

    #if 0
    pRegPerm->reg_properties[0x990] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x991] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x992] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x993] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x994] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x995] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x996] = TIESC_PERM_RW; //Start Time Cyclic Operation
    pRegPerm->reg_properties[0x997] = TIESC_PERM_RW; //Start Time Cyclic Operation
    #else
    #ifndef SYSTEM_TIME_PDI_CONTROLLED

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x990 + i] = TIESC_PERM_RW;
    }

    #else

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x990 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #endif
    #if 0
    pRegPerm->reg_properties[0x998] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x999] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99A] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99B] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99C] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99D] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99E] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    pRegPerm->reg_properties[0x99F] = TIESC_PERM_READ_ONLY; //Next SYNC1 pulse
    #else

    for(i = 0; i < 8; i++)
    {
        pRegPerm->reg_properties[0x998 + i] = TIESC_PERM_READ_ONLY;
    }

    #endif
    #if 0
    pRegPerm->reg_properties[0x9A0] = TIESC_PERM_RW; //SYNC0 Cycle Time
    pRegPerm->reg_properties[0x9A1] = TIESC_PERM_RW; //SYNC0 Cycle Time
    pRegPerm->reg_properties[0x9A2] = TIESC_PERM_RW; //SYNC0 Cycle Time
    pRegPerm->reg_properties[0x9A3] = TIESC_PERM_RW; //SYNC0 Cycle Time

    pRegPerm->reg_properties[0x9A4] = TIESC_PERM_RW; //SYNC1 Cycle Time
    pRegPerm->reg_properties[0x9A5] = TIESC_PERM_RW; //SYNC1 Cycle Time
    pRegPerm->reg_properties[0x9A6] = TIESC_PERM_RW; //SYNC1 Cycle Time
    pRegPerm->reg_properties[0x9A7] = TIESC_PERM_RW; //SYNC1 Cycle Time
    pRegPerm->reg_properties[0x9A8] = TIESC_PERM_RW; //Latch0 Control
    pRegPerm->reg_properties[0x9A9] = TIESC_PERM_RW; //Latch1 Control

    #else
    #ifndef SYSTEM_TIME_PDI_CONTROLLED

    for(i = 0; i < 10; i++)
    {
        pRegPerm->reg_properties[0x9A0 + i] = TIESC_PERM_RW;
    }

    #else

	#if 1
	pRegPerm->reg_properties[0x9A0] = TIESC_PERM_READ_ONLY; //SYNC0 Cycle Time
	pRegPerm->reg_properties[0x9A1] = TIESC_PERM_READ_ONLY; //SYNC0 Cycle Time
	pRegPerm->reg_properties[0x9A2] = TIESC_PERM_READ_ONLY; //SYNC0 Cycle Time
	pRegPerm->reg_properties[0x9A3] = TIESC_PERM_READ_ONLY; //SYNC0 Cycle Time

	pRegPerm->reg_properties[0x9A4] = TIESC_PERM_READ_ONLY; //SYNC1 Cycle Time
	pRegPerm->reg_properties[0x9A5] = TIESC_PERM_READ_ONLY; //SYNC1 Cycle Time
	pRegPerm->reg_properties[0x9A6] = TIESC_PERM_READ_ONLY; //SYNC1 Cycle Time
	pRegPerm->reg_properties[0x9A7] = TIESC_PERM_READ_ONLY; //SYNC1 Cycle Time
	pRegPerm->reg_properties[0x9A8] = TIESC_PERM_RW; //Latch0 Control
	pRegPerm->reg_properties[0x9A9] = TIESC_PERM_RW; //Latch1 Control

	#else
    for(i = 0; i < 10; i++)
    {
        pRegPerm->reg_properties[0x9A0 + i] = TIESC_PERM_READ_ONLY;
    }
	#endif
    #endif
    #endif
    #if 0
    pRegPerm->reg_properties[0x9AE] = TIESC_PERM_READ_ONLY; //LATCH0 status
    pRegPerm->reg_properties[0x9AF] = TIESC_PERM_READ_ONLY; //LATCH1 status

    pRegPerm->reg_properties[0x9B0] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Positive Edge
    pRegPerm->reg_properties[0x9B1] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Positive Edge
    pRegPerm->reg_properties[0x9B2] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Positive Edge
    pRegPerm->reg_properties[0x9B3] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Positive Edge

    pRegPerm->reg_properties[0x9B8] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Negative Edge
    pRegPerm->reg_properties[0x9B9] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Negative Edge
    pRegPerm->reg_properties[0x9BA] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Negative Edge
    pRegPerm->reg_properties[0x9BB] =
        TIESC_PERM_READ_ONLY; //Latch0 Time Negative Edge

    pRegPerm->reg_properties[0x9C0] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Positive Edge
    pRegPerm->reg_properties[0x9C1] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Positive Edge
    pRegPerm->reg_properties[0x9C2] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Positive Edge
    pRegPerm->reg_properties[0x9C3] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Positive Edge

    pRegPerm->reg_properties[0x9C8] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Negative Edge
    pRegPerm->reg_properties[0x9C9] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Negative Edge
    pRegPerm->reg_properties[0x9CA] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Negative Edge
    pRegPerm->reg_properties[0x9CB] =
        TIESC_PERM_READ_ONLY; //Latch1 Time Negative Edge
    #else

    for(i = 0; i < 34; i++)
    {
        pRegPerm->reg_properties[i + 0x9AE] = TIESC_PERM_READ_ONLY;
    }

    #endif

    //TI vendor specific registers
    for(i = 0; i < 16; i++)
    {
        pRegPerm->reg_properties[0xE00 + i] = TIESC_PERM_READ_ONLY;
    }

    #if 0
    pRegPerm->reg_properties[0xE10] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE11] = TIESC_PERM_RW;

    pRegPerm->reg_properties[0xE12] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE13] = TIESC_PERM_RW;

    pRegPerm->reg_properties[0xE14] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE15] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE16] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE17] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE18] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE19] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1A] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1B] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1C] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1D] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1E] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE1F] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE20] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE21] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE22] = TIESC_PERM_RW;
    pRegPerm->reg_properties[0xE23] = TIESC_PERM_RW;
    #else

    //TI vendor specific registers
    for(i = 0; i < 20; i++)
    {
        pRegPerm->reg_properties[0xE10 + i] = TIESC_PERM_RW;
    }

    #endif

    pRegPerm->reg_properties[0xEE0] = TIESC_PERM_RW; //APP_RELOAD_FLAG_REG

    //For debug only
    //memset ((void*)&pRegPerm->reg_properties[0x14], TIESC_PERM_RW, 32);
    //memset ((void*)&pRegPerm->reg_properties[0xE24], TIESC_PERM_RW, 12);
    #ifdef ENABLE_PDI_REG_PERMISSIONS
    memset(&pdi_reg_perm_array[0], 3, 4096);

    for(i = 0; i < 10; i++)
    {
        pdi_reg_perm_array[i] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x10] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x12] = TIESC_PERM_RW;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x100] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x108] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x110] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x120] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x130] = TIESC_PERM_RW;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x134] = TIESC_PERM_RW;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x140] = TIESC_PERM_RW;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x150] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x200] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x204] = TIESC_PERM_RW;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x210] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x220] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 13; i++)
    {
        pdi_reg_perm_array[i + 0x300] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x310] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x400] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x410] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x420] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x440] = TIESC_PERM_READ_ONLY;
    }

    pdi_reg_perm_array[0x500] = TIESC_PERM_READ_ONLY;

    for(i = 0; i < 15; i++)
    {
        pdi_reg_perm_array[i + 0x501] = TIESC_PERM_RW;
    }

    pdi_reg_perm_array[0x510] = TIESC_PERM_READ_ONLY;

    for(i = 0; i < 6; i++)
    {
        pdi_reg_perm_array[i + 0x511] = TIESC_PERM_RW;
    }

    pdi_reg_perm_array[0x516] = TIESC_PERM_READ_ONLY;
    pdi_reg_perm_array[0x517] = TIESC_PERM_RW;

    for(i = 0; i < 8; i++)    //8 FMMUs
    {
        memset((void *)&pdi_reg_perm_array[0x600 + i * 16], TIESC_PERM_READ_ONLY,
               16);
    }

    for(i = 0; i < 8; i++)    //8 SMs
    {
        memset((void *)&pdi_reg_perm_array[0x800 + i * 8], TIESC_PERM_READ_ONLY, 7);
        memset((void *)&pdi_reg_perm_array[0x807 + i * 8], TIESC_PERM_RW, 1);
    }

    #ifndef SYSTEM_TIME_PDI_CONTROLLED

    for(i = 0; i < 54; i++)
    {
        pdi_reg_perm_array[i + 0x900] = TIESC_PERM_READ_ONLY;
    }

    #else

    for(i = 0; i < 16; i++)
    {
        pdi_reg_perm_array[i + 0x900] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 8; i++)
    {
        pdi_reg_perm_array[i + 0x910] = TIESC_PERM_RW;
    }

    for(i = 0; i < 8; i++)
    {
        pdi_reg_perm_array[i + 0x918] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 12; i++)
    {
        pdi_reg_perm_array[i + 0x920] = TIESC_PERM_RW;
    }

    for(i = 0; i < 4; i++)
    {
        pdi_reg_perm_array[i + 0x92c] = TIESC_PERM_READ_ONLY;
    }

    pdi_reg_perm_array[0x930] = TIESC_PERM_RW;
    pdi_reg_perm_array[0x931] = TIESC_PERM_RW;
    pdi_reg_perm_array[0x932] = TIESC_PERM_READ_ONLY;
    pdi_reg_perm_array[0x933] = TIESC_PERM_READ_ONLY;
    pdi_reg_perm_array[0x934] = TIESC_PERM_RW;
    pdi_reg_perm_array[0x935] = TIESC_PERM_RW;
    #endif

    pdi_reg_perm_array[0x981] = TIESC_PERM_READ_ONLY;

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x982] = TIESC_PERM_RW;
    }

    pdi_reg_perm_array[0x984] = TIESC_PERM_READ_ONLY;

    for(i = 0; i < 2; i++)
    {
        pdi_reg_perm_array[i + 0x98E] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 26; i++)
    {
        pdi_reg_perm_array[i + 0x990] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 34; i++)
    {
        pdi_reg_perm_array[i + 0x9AE] = TIESC_PERM_READ_ONLY;
    }

    //TI vendor specific registers
    for(i = 0; i < 8; i++)
    {
        pdi_reg_perm_array[i + 0xE00] = TIESC_PERM_READ_ONLY;
    }

    for(i = 0; i < 28; i++)
    {
        pdi_reg_perm_array[i + 0xE08] = TIESC_PERM_RW;
    }

    #endif
}

Int16 bsp_pruss_mdio_phy_read(PRUICSS_Handle pruIcssHandle, Uint8 phyaddr,
                              Uint8 regoffset, Uint16 *regval)
{
    if((bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_ECAT_ACCESS) & 0x1)
            || (bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_PDI_ACCESS) & 0x2))
    {
        return -1;
    }

    //Acquire PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, bsp_read_byte(pruIcssHandle,
                   ESC_ADDR_MI_PDI_ACCESS) | 1, ESC_ADDR_MI_PDI_ACCESS);
    MDIO_regRead((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
                  PRU_ICSS_MDIO), phyaddr, regoffset, regval, NULL);
    //Release PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, bsp_read_byte(pruIcssHandle,
                   ESC_ADDR_MI_PDI_ACCESS) & ~1, ESC_ADDR_MI_PDI_ACCESS);
    return 0;
}

Int16 bsp_pruss_mdio_phy_write(PRUICSS_Handle pruIcssHandle, Uint8 phyaddr,
                               Uint8 regoffset, Uint16 regval)
{
    if((bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_ECAT_ACCESS) & 0x1)
            || (bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_PDI_ACCESS) & 0x2))
    {
        return -1;
    }

    //Acquire PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, bsp_read_byte(pruIcssHandle,
                   ESC_ADDR_MI_PDI_ACCESS) | 1, ESC_ADDR_MI_PDI_ACCESS);
    MDIO_regWrite((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
                   PRU_ICSS_MDIO), phyaddr, regoffset, regval);
    //Release PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, bsp_read_byte(pruIcssHandle,
                   ESC_ADDR_MI_PDI_ACCESS) & ~1, ESC_ADDR_MI_PDI_ACCESS);
    return 0;
}
#ifdef AM43XX_FAMILY_BUILD
void bsp_tlk105_init(PRUICSS_Handle pruIcssHandle, Uint8 phy0addr,
                     Uint8 phy1addr, Uint8 enhancedlink_enable)
{
    if(TIESC_MDIO_RX_LINK_ENABLE == enhancedlink_enable)
    {
        Board_phyMLEDConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, PHY_MLED_100,
                            NULL);
        Board_phyMLEDConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, PHY_MLED_100,
                            NULL);
    }

    while(!MDIO_getPhyIdentifyStat((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL))
    {
    }

    while(!MDIO_getPhyIdentifyStat((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL))
    {
    }

    //SWSCR2
    //Bit2: Enable RXERR during IDLE detection
    //Bit1: Disable detection of transmit error in odd-nibble boundary for odd nibble insertion)
    //Bit5: Force Full-Duplex while working with link partner in forced 100B-TX. When the
    //PHY is set to Auto-Negotiation or Force 100B-TX and the link partner is operated
    //in Force 100B-TX, the link is always Full Duplex
    //For EtherCAT : Disable enhanced LED link function

    Board_phyExtFDEnable((((PRUICSS_HwAttrs *)(
                               pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phyExtFDEnable((((PRUICSS_HwAttrs *)(
                               pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
    Board_phyODDNibbleDetEnable((((PRUICSS_HwAttrs *)(
                                      pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phyODDNibbleDetEnable((((PRUICSS_HwAttrs *)(
                                      pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
    Board_phyRxErrIdleEnable((((PRUICSS_HwAttrs *)(
                                   pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phyRxErrIdleEnable((((PRUICSS_HwAttrs *)(
                                   pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);

    //Enable enhanced link detection in TLK110 for EtherCAT
    //Bit3: Drop the link based on RX Error count of the MII interface, when a predefined number
    // of 32 RX Error occurrences in a 10us interval is reached, the link will be dropped
    // Bit0: Drop the link based on Signal/Energy loss indication, when the Energy detector
    //indicates Energy Loss, the link will be dropped. Typical reaction time is 10us.
    Board_phyLedConfig((((PRUICSS_HwAttrs *)(
                             pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, LED_CFG_MODE2,
                       NULL);
    Board_phyLedConfig((((PRUICSS_HwAttrs *)(
                             pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, LED_CFG_MODE2,
                       NULL);
    Board_phyLedBlinkConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, LED_BLINK_200,
                            NULL);
    Board_phyLedBlinkConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, LED_BLINK_200,
                            NULL);

    Board_phyFastLinkDownDetEnable((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr,
                                   FAST_LINKDOWN_SIGENERGY | FAST_LINKDOWN_RXERR, NULL);
    Board_phyFastLinkDownDetEnable((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr,
                                   FAST_LINKDOWN_SIGENERGY | FAST_LINKDOWN_RXERR, NULL);

    /*Board_phyFastRXDVDetEnable( ( ( ( PRUICSS_HwAttrs * )(
                                        pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy0addr, NULL );
    Board_phyFastRXDVDetEnable( ( ( ( PRUICSS_HwAttrs * )(
                                        pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy1addr, NULL );*/
}

#elif defined(AM335X_FAMILY_BUILD)
void bsp_tlk110_configure_leds(PRUICSS_Handle pruIcssHandle, Uint8 phy0addr,
                               Uint8 phy1addr)
{
    Board_phyLedConfig((((PRUICSS_HwAttrs *)(
                             pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, LED_CFG_MODE3,
                       NULL);
    Board_phyLedConfig((((PRUICSS_HwAttrs *)(
                             pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, LED_CFG_MODE3,
                       NULL);
    Board_phyLedBlinkConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, LED_BLINK_200,
                            NULL);
    Board_phyLedBlinkConfig((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, LED_BLINK_200,
                            NULL);
}

void bsp_tlk110_init(PRUICSS_Handle pruIcssHandle, Uint8 phy0addr,
                     Uint8 phy1addr, Uint8 enhancedlink_enable)
{
    while(!MDIO_getPhyIdentifyStat((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL))
    {
    }

    while(!MDIO_getPhyIdentifyStat((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL))
    {
    }

    //SWSCR2
    //Bit2: Enable RXERR during IDLE detection
    //Bit1: Disable detection of transmit error in odd-nibble boundary for odd nibble insertion)
    //Bit5: Force Full-Duplex while working with link partner in forced 100B-TX. When the
    //PHY is set to Auto-Negotiation or Force 100B-TX and the link partner is operated
    //in Force 100B-TX, the link is always Full Duplex

    //For EtherCAT : Enable enhanced LED link function
    //LED Link is ON only when link is established in 100B-TX Full Duplex mode.
    //Note that SWCSCR2[4] overrides PHYCR[6:5] configuration and hence setting LED_CFG of PHYCR will not have any effect.
    //Enable Enhanced LED LINK bit and Disable detection of transmit error in odd-nibble boundary for odd nibble insertion
    //For EtherCAT : Disable enhanced LED link function
    if(BOARD_ICEV2 != boardType)
    {
        if(TIESC_MDIO_RX_LINK_ENABLE == enhancedlink_enable)
        {
            Board_phyEnhLEDLinkEnable((((PRUICSS_HwAttrs *)(
                                            pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
            Board_phyEnhLEDLinkEnable((((PRUICSS_HwAttrs *)(
                                            pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
        }
    }

    Board_phyExtFDEnable((((PRUICSS_HwAttrs *)(
                               pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phyExtFDEnable((((PRUICSS_HwAttrs *)(
                               pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
    Board_phyODDNibbleDetEnable((((PRUICSS_HwAttrs *)(
                                      pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phyODDNibbleDetEnable((((PRUICSS_HwAttrs *)(
                                      pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
    /*Board_phyRxErrIdleEnable( ( ( ( PRUICSS_HwAttrs * )(
                                      pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy0addr, NULL );
    Board_phyRxErrIdleEnable( ( ( ( PRUICSS_HwAttrs * )(
                                      pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy1addr, NULL );*/

    if(BOARD_ICEV2 == boardType)
    {
        bsp_tlk110_configure_leds(pruIcssHandle, phy0addr, phy1addr);
    }

    //Enable enhanced link detection in TLK110 for EtherCAT
    //Bit3: Drop the link based on RX Error count of the MII interface, when a predefined number
    // of 32 RX Error occurrences in a 10us interval is reached, the link will be dropped
    // Bit0: Drop the link based on Signal/Energy loss indication, when the Energy detector
    //indicates Energy Loss, the link will be dropped. Typical reaction time is 10us.
    Board_phyFastLinkDownDetEnable((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr,
                                   FAST_LINKDOWN_SIGENERGY | FAST_LINKDOWN_RXERR, NULL);
    Board_phyFastLinkDownDetEnable((((PRUICSS_HwAttrs *)(
                                         pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr,
                                   FAST_LINKDOWN_SIGENERGY | FAST_LINKDOWN_RXERR, NULL);

    /*Board_phyFastRXDVDetEnable( ( ( ( PRUICSS_HwAttrs * )(
                                        pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy0addr, NULL );
    Board_phyFastRXDVDetEnable( ( ( ( PRUICSS_HwAttrs * )(
                                        pruIcssHandle->hwAttrs ) )->baseAddr + PRU_ICSS_MDIO ), phy1addr, NULL );*/
    Board_phySwStrapConfigDone((((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy0addr, NULL);
    Board_phySwStrapConfigDone((((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), phy1addr, NULL);
}
#endif
Int16 bsp_pruss_mdio_init(PRUICSS_Handle pruIcssHandle,
                          t_mdio_params *pmdio_params)
{
    if((bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_ECAT_ACCESS) & 0x1)
            || (bsp_read_byte(pruIcssHandle, ESC_ADDR_MI_PDI_ACCESS) & 0x2))
    {
        return -1;
    }

    //Acquire PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, bsp_read_byte(pruIcssHandle,
                   ESC_ADDR_MI_PDI_ACCESS) | 1, ESC_ADDR_MI_PDI_ACCESS);
    //Configure MDIO clock = 200/(clkdiv+1)
    // Disable preamble , enable fault detection

    MDIO_osDrvInit((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr
                    + PRU_ICSS_MDIO), 200000000, 2200000u, 0);

    //Indicate PHY address to firmware via vendor specfic registers
    bsp_write_byte(pruIcssHandle, pmdio_params->addr0, ESC_ADDR_TI_PORT0_PHYADDR);
    bsp_write_byte(pruIcssHandle, pmdio_params->addr1, ESC_ADDR_TI_PORT1_PHYADDR);
    bsp_write_byte(pruIcssHandle, (1 << PDI_ISR_EDIO_NUM),
                   ESC_ADDR_TI_PDI_ISR_PINSEL);

    bsp_write_dword(pruIcssHandle,
                    (pmdio_params->link0pol << pmdio_params->addr0) | (pmdio_params->link1pol <<
                            pmdio_params->addr1),
                    ESC_ADDR_TI_PHY_LINK_POLARITY);
    Board_phyReset();
    Board_enablePhyAutoMDIX((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), pmdio_params->addr0,
                            NULL);
    Board_enablePhyAutoMDIX((((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), pmdio_params->addr1,
                            NULL);

    #ifdef AM43XX_FAMILY_BUILD
    /*  AM437x  */
    bsp_tlk105_init(pruIcssHandle, pmdio_params->addr0, pmdio_params->addr1,
                    pmdio_params->enhancedlink_enable);
    #elif defined(AM335X_FAMILY_BUILD)
    //Below code is only valid for TLK110 (ICE and IDK) to enable enhanced link detection modes and fast link detect
    bsp_tlk110_init(pruIcssHandle, pmdio_params->addr0, pmdio_params->addr1,
                    pmdio_params->enhancedlink_enable);
    #endif /*AM335X_FAMILY_BUILD*/


    //Select PHY address enable link change interrupt at MDIOLinkIntMasked and MDIOLinkIntRaw
    if(pmdio_params->enhancedlink_enable == 0)
    {
        MDIO_enableLinkInterrupt((((PRUICSS_HwAttrs *)(
                                       pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), 0, pmdio_params->addr0,
                                 MDIO_LINKSEL_DISABLE);
    }

    else
    {
        MDIO_enableLinkInterrupt((((PRUICSS_HwAttrs *)(
                                       pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), 0, pmdio_params->addr0,
                                 MDIO_LINKSEL_ENABLE);
    }

    if(pmdio_params->enhancedlink_enable == 0)
    {
        MDIO_enableLinkInterrupt((((PRUICSS_HwAttrs *)(
                                       pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), 1, pmdio_params->addr1,
                                 MDIO_LINKSEL_DISABLE);
    }

    else
    {
        MDIO_enableLinkInterrupt((((PRUICSS_HwAttrs *)(
                                       pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO), 1, pmdio_params->addr1,
                                 MDIO_LINKSEL_ENABLE);
    }

    //Release PDI access over MDIO/MI interface
    bsp_write_byte(pruIcssHandle, (bsp_read_byte(pruIcssHandle,
                                   ESC_ADDR_MI_PDI_ACCESS) & ~1), ESC_ADDR_MI_PDI_ACCESS);
    return 0;
}

Uint32 bsp_pruss_mdio_phy_link_state(PRUICSS_Handle pruIcssHandle,
                                     Uint8 phyaddr)
{
    volatile Uint32 regval;
    regval = bsp_pruss_mdioreg_read(pruIcssHandle, HW_ICSS_MII_MDIO_LINK);
    #if TIESC_MDIO_RX_LINK_ENABLE
    regval ^= bsp_read_dword(pruIcssHandle, ESC_ADDR_TI_PHY_LINK_POLARITY);
    #endif
    return (regval & (1 << phyaddr));
}
#ifdef AM43XX_FAMILY_BUILD
    PRUICSS_IntcInitData pruss0_intc_initdata = PRU_ICSS0_INTC_INITDATA;
#endif
PRUICSS_IntcInitData pruss1_intc_initdata = PRU_ICSS1_INTC_INITDATA;

void bsp_init(PRUICSS_Handle pruIcssHandle)
{
    Semaphore_Params semParams;
    #ifndef USE_ECAT_TIMER
    Types_FreqHz  frg;
    #endif
    t_mdio_params mdioParamsInit;

    // init timer data
    current_low = 0;
    pd_read_addr_err = pd_write_addr_err = 0;
    pdi_read_fail_cnt = pdi_write_fail_cnt = 0;
    prev_low = 0;
    #ifndef USE_ECAT_TIMER
    BIOS_getCpuFreq(&frg);
    ecat_timer_inc_p_ms = (frg.lo / 1000);
    #endif

    volatile uint8_t *pEsc = (volatile Uint8 *)(((PRUICSS_HwAttrs *)(
                                 pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));
    volatile t_register_properties *pRegPerm = (volatile t_register_properties *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(1));

    #ifdef ENABLE_ONLINE_FIRMWARE_UPGRADE
    fw_download_flag = 0;
    fw_write_offset = FOE_APPL_BIN_OFFSET;
    #endif
    PRUICSS_enableOCPMasterAccess(pruIcssHandle);
    bsp_hwspinlock_init();

    PRUICSS_pruIntcInit(pruIcssHandle, &pruss1_intc_initdata);
    #ifdef AM43XX_FAMILY_BUILD
    PRUICSS_pruIntcInit(pruIcss0Handle, &pruss0_intc_initdata);
    #endif

    /* initialize ESC DPRAM pointer microcontroller specific to the beginning of the physical memory of the ESC,
       the macro MAKE_PTR_TO_ESC should be defined in tieschw.h */
    memset((void *)sm_properties, 0, sizeof(sm_properties));

    memset((void *)pEsc, 0, 12 * 1024);      //Init ICSS shared ram
    memset((void *)pHost2PruIntfc, 0, 8 * 1024);      //Init PRU0 data ram
    memset((void *)pRegPerm, 0, 1024);      //Init PRU1 data ram
    memset((void *)&pRegPerm->reg_properties, 3,
           4 * 1024);  //Init PRU1 data ram

    bsp_pruss_cmd_intfc_write_word(0xFF, &pHost2PruIntfc->cmdlow);

    bsp_write_word(pruIcssHandle, TIESC_PORT0_TX_DELAY,
                   ESC_ADDR_TI_PORT0_TX_START_DELAY);
    bsp_write_word(pruIcssHandle, TIESC_PORT1_TX_DELAY,
                   ESC_ADDR_TI_PORT1_TX_START_DELAY);

    mdioParamsInit.clkdiv = TIESC_MDIO_CLKDIV * 2;

    mdioParamsInit.addr0 = BOARDGetDeviceDataModId(DEVICE_ID_ENET_PHY_MII, 0);
    mdioParamsInit.addr1 = BOARDGetDeviceDataModId(DEVICE_ID_ENET_PHY_MII, 1);

    mdioParamsInit.enhancedlink_enable =
        TIESC_MDIO_RX_LINK_ENABLE;//TIESC_MDIO_RX_LINK_DISABLE;

    if(TIESC_MDIO_RX_LINK_ENABLE == mdioParamsInit.enhancedlink_enable)
    {
        //Enhanced link detection enabled
        if(BOARD_IDKEVM == boardType)
        {
            mdioParamsInit.link0pol = TIESC_LINK_POL_ACTIVE_HIGH;
        }

        else
        {
            mdioParamsInit.link0pol = TIESC_LINK_POL_ACTIVE_LOW;
        }

        mdioParamsInit.link1pol = TIESC_LINK_POL_ACTIVE_LOW;
    }

    else
    {
        //Enhanced link detection disabled
        mdioParamsInit.link0pol = TIESC_LINK_POL_ACTIVE_HIGH;
        mdioParamsInit.link1pol = TIESC_LINK_POL_ACTIVE_HIGH;
    }

    bsp_pruss_mdio_init(pruIcssHandle, &mdioParamsInit);

    bsp_esc_reg_perm_init(pruIcssHandle);
    //Trigger PDI WD on  LATCH_IN or every command send to firmware
    bsp_set_pdi_wd_trigger_mode(pruIcssHandle, PDI_WD_TRIGGER_LATCH_IN);
    bsp_set_digio_sw_dataout_enable(pruIcssHandle);
    PRUICSS_pruReset(pruIcssHandle, 0);
    PRUICSS_pruReset(pruIcssHandle, 1);

    ASSERT_DMB();

    /* PRU firmwares are loaded as header files in appliation  */
    PRUICSS_setPRUBuffer(pruIcssHandle, 0, (Uint32 *)pru_frame_proc,
                         pru_frame_proc_len);
    PRUICSS_setPRUBuffer(pruIcssHandle, 1, (Uint32 *)pru_host_proc,
                         pru_host_proc_len);

    PRUICSS_pruExecProgram(pruIcssHandle, 1);
    PRUICSS_pruExecProgram(pruIcssHandle, 0);

    bsp_eeprom_emulation_init();        //Load eeprom file to memory

    if(bsp_eeprom_load_esc_registers(pruIcssHandle, 0) == -1)
    {
        Uint16 EEPROMReg = 0;
        HW_EscReadWord(EEPROMReg, ESC_ADDR_EEPROM_CTRL);
        EEPROMReg = SWAPWORD(EEPROMReg);
        EEPROMReg |= ESC_EEPROM_ERROR_CRC;
        EEPROMReg = SWAPWORD(EEPROMReg);
        bsp_write_word(pruIcssHandle, EEPROMReg, ESC_ADDR_EEPROM_CTRL);
    }

    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    semcmdlow_handle = Semaphore_create(1, &semParams, NULL);
}

void bsp_exit(PRUICSS_Handle pruIcssHandle)
{
    Semaphore_delete(&semcmdlow_handle);

    bsp_eeprom_emulation_exit();        //Flush the EEPROM cache to file

    PRUICSS_pruDisable(pruIcssHandle, 0);
    PRUICSS_pruDisable(pruIcssHandle, 1);
}


void bsp_start_esc_isr(PRUICSS_Handle pruIcssHandle)
{
    /* enable the ESC-interrupt microcontroller specific,
       the makro ENABLE_ESC_INT should be defined in ecat_def.h */
    // enable RTOS int
    uint32_t evtOutNum;
    #ifdef ENABLE_PDI_TASK
    uint32_t pruIsrNum = 0;
    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_AL_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_AL_EVENT;
    #endif
    evtOutNum = HOST_AL_EVENT - 20;
    ecatIsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    ecatIsrArgs->handle = pruIcssHandle;
    PRUICSS_registerIrqHandler(ecatIsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,
                               1,
                               &EcatIsr);

    #else
    PRUSSDRVRegisterIrqHandler(HOST_AL_EVENT, 0, &EcatIsr, PRUSS_INSTANCE_IN_USE);
    #endif
    #ifndef SUPPORT_CMDACK_POLL_MODE
    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_CMD_LOW_ACK_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_CMD_LOW_ACK_EVENT;
    #endif
    escCmdLowAckIsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    escCmdLowAckIsrArgs->handle = pruIcssHandle;
    evtOutNum = HOST_CMD_LOW_ACK_EVENT - 20;
    PRUICSS_registerIrqHandler(escCmdLowAckIsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,
                               1,
                               &EscCmdLowAckIsr);

    #endif
    #ifdef ENABLE_SYNC_TASK
    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_SYNC0_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_SYNC0_EVENT;
    #endif
    evtOutNum = HOST_SYNC0_EVENT - 20;
    sync0IsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    sync0IsrArgs->handle = pruIcssHandle;
    PRUICSS_registerIrqHandler(sync0IsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,
                               1,
                               &Sync0Isr);

    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_SYNC1_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_SYNC1_EVENT;
    #endif
    evtOutNum = HOST_SYNC1_EVENT - 20;
    sync1IsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    sync1IsrArgs->handle = pruIcssHandle;
    PRUICSS_registerIrqHandler(sync1IsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,
                               1,
                               &Sync1Isr);
    #else
    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_SYNC0_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_SYNC0_EVENT;
    #endif
    evtOutNum = HOST_SYNC0_EVENT - 20;
    sync0IsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    sync0IsrArgs->handle = pruIcssHandle;
    PRUICSS_registerIrqHandler(sync0IsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,           /* Used for C66x */
                               0,
                               &Sync0Isr);

    #ifdef AM43XX_FAMILY_BUILD
    pruIsrNum = HOST_SYNC1_EVENT + 32;
    #elif defined(AM335X_FAMILY_BUILD)
    pruIsrNum = HOST_SYNC1_EVENT;
    #endif
    evtOutNum = HOST_SYNC1_EVENT - 20;
    sync1IsrArgs = (PRUICSS_IrqArgs *)malloc(sizeof(PRUICSS_IrqArgs));
    sync1IsrArgs->handle = pruIcssHandle;
    PRUICSS_registerIrqHandler(sync1IsrArgs,
                               evtOutNum,
                               pruIsrNum,
                               1,           /* Used for C66x */
                               0,
                               &Sync1Isr);
    #endif

}

void bsp_send_command_to_firmware(PRUICSS_Handle pruIcssHandle, Uint32 command,
                                  Uint16 param1, Uint16 param2)
{
    uint32_t evtoutNum = 0;
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));
    {
        #if defined(ENABLE_PDI_TASK) || defined(ENABLE_PDI_SWI)
        Semaphore_pend(semcmdlow_handle, BIOS_WAIT_FOREVER);

        #else
        Hwi_disable();
        #endif
        bsp_pruss_cmd_intfc_write_word(command, &pHost2PruIntfc->cmdlow);
        bsp_pruss_cmd_intfc_write_word(param1, &pHost2PruIntfc->param1low);
        bsp_pruss_cmd_intfc_write_word(param2, &pHost2PruIntfc->param2low);
        #ifdef SUPPORT_CMDACK_POLL_MODE
        bsp_pruss_cmd_intfc_write_word(1, &pHost2PruIntfc->cmdlow_ack);
        #endif
        PRUICSS_pruSendEvent(pruIcss1Handle, ARM_PRU_EVENT1);
        ASSERT_DMB();
        ASSERT_DSB();
        {
            #ifdef SUPPORT_CMDACK_POLL_MODE
            volatile Uint16 ack;

            do
            {
                ack = bsp_pruss_cmd_intfc_read_word(&pHost2PruIntfc->cmdlow_ack);
            }
            while(ack);

            #else
            evtoutNum = HOST_CMD_LOW_ACK_EVENT - 20;
            PRUICSS_pruWaitEvent((PRUICSS_Handle)pruIcss1Handle, evtoutNum);
            #endif
        }
        bsp_pruss_cmd_intfc_write_word(0xFF,    &pHost2PruIntfc->cmdlow);
        #if defined(ENABLE_PDI_TASK) || defined(ENABLE_PDI_SWI)
        Semaphore_post(semcmdlow_handle);
        #else
        Hwi_enable();
        #endif
    }
}

void bsp_pdi_post_read_indication(PRUICSS_Handle pruIcssHandle,
                                  Uint16 address)
{
    switch(address)
    {
        case ESC_ADDR_SM_WD_STATUS:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_PD_WD_STATUS, 0,
                                             0);
            }
            break;

        case ESC_ADDR_SYNC_STATUS:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_SYNC_STATUS,
                                             SYNC0, 0);
            }
            break;

        case ESC_ADDR_SYNC_STATUS + 1:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_SYNC_STATUS,
                                             SYNC1, 0);
            }
            break;

        case ESC_ADDR_ALCONTROL:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_AL_CONTROL, 0,
                                             0);
            }
            break;

        case ESC_ADDR_SM0_ACTIVATE:
        case ESC_ADDR_SM1_ACTIVATE:
        case ESC_ADDR_SM2_ACTIVATE:
        case ESC_ADDR_SM3_ACTIVATE:
        case ESC_ADDR_SM4_ACTIVATE:
        case ESC_ADDR_SM5_ACTIVATE:
        case ESC_ADDR_SM6_ACTIVATE:
        case ESC_ADDR_SM7_ACTIVATE:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_SM_ACTIVATE,
                                             (address - ESC_ADDR_SYNCMAN) >> 3, 0);
            }
            break;

        case ESC_ADDR_LATCH0_POS_EDGE:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                             LATCH0_POS_EDGE, 0);
            }
            break;

        case ESC_ADDR_LATCH0_NEG_EDGE:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                             LATCH0_NEG_EDGE, 0);
            }
            break;

        case ESC_ADDR_LATCH1_POS_EDGE:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                             LATCH1_POS_EDGE, 0);
            }
            break;

        case ESC_ADDR_LATCH1_NEG_EDGE:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_READ_LATCH_TIME,
                                             LATCH1_NEG_EDGE, 0);
            }
            break;

        default:
            break;
    }

    if(address == sm_properties[MAILBOX_WRITE].physical_start_addr)
    {
        bsp_pdi_mbx_read_start(pruIcssHandle);
    }

}


void bsp_pdi_write_indication(PRUICSS_Handle pruIcssHandle, Uint16 address,
                              Uint16 value)
{
    Uint16 regval = 0;

    switch(address)
    {
        case ESC_ADDR_ALSTATUS:
            {
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_WRITE_AL_STATUS, 0,
                                             0);
            }
            break;

        case ESC_ADDR_SM0_PDI_CONTROL:
        case ESC_ADDR_SM1_PDI_CONTROL:
        case ESC_ADDR_SM2_PDI_CONTROL:
        case ESC_ADDR_SM3_PDI_CONTROL:
        case ESC_ADDR_SM4_PDI_CONTROL:
        case ESC_ADDR_SM5_PDI_CONTROL:
        case ESC_ADDR_SM6_PDI_CONTROL:
        case ESC_ADDR_SM7_PDI_CONTROL:
            {
                Uint8 channel = (address - ESC_ADDR_SYNCMAN) >> 3;
                Uint16 sm_address = ESC_ADDR_SYNCMAN + (channel * SIZEOF_SM_REGISTER);
                bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_WRITE_SM_PDI_CTRL,
                                             (channel << 8) | value, 0);

                while(bsp_pdi_sm_config_ongoing(pruIcssHandle));

                bsp_set_sm_properties(channel, bsp_read_word(pruIcssHandle, sm_address),
                                      bsp_read_word(pruIcssHandle, (sm_address + 2)));
            }
            break;

        case ESC_ADDR_EEPROM_CTRL:
            {
                /* Note - Here we are assuming that, Command is always two byte  */
                regval = SWAPWORD(value);

                if((regval & ESC_EEPROM_CMD_WRITE_MASK) &&
                        !(regval & ESC_EEPROM_ERROR_CMD_ACK))
                {
                    bsp_set_eeprom_update_status(1);
                    bsp_set_eeprom_updated_time();
                }

                bsp_eeprom_emulation_command_ack(pruIcssHandle);
            }
            break;

        default:
            break;
    }

    if(address == sm_properties[MAILBOX_READ].physical_start_addr)
    {
        bsp_pdi_mbx_write_start(pruIcssHandle);
    }

}

void bsp_pdi_mbx_read_start(PRUICSS_Handle pruIcssHandle)
{
    Uint16  ALEvent = HW_GetALEventRegister_Isr();

    if(ALEvent & MBX_WRITE_EVENT)
    {
        bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_CLEAR_AL_EVENT_LOW,
                                     ~MBX_WRITE_EVENT, 0);
    }
}

void bsp_pdi_mbx_read_complete(PRUICSS_Handle pruIcssHandle)
{
    /* get address of the receive mailbox sync manager */
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_ACK_MBX_READ,
                                 sm_properties[MAILBOX_WRITE].physical_start_addr,
                                 sm_properties[MAILBOX_WRITE].length);
}
void bsp_pdi_mbx_write_start(PRUICSS_Handle pruIcssHandle)
{
    Uint16  ALEvent = HW_GetALEventRegister_Isr();

    if(ALEvent & MBX_READ_EVENT)
    {
        bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_CLEAR_AL_EVENT_LOW,
                                     ~MBX_READ_EVENT, 0);
    }
}
void bsp_pdi_mbx_write_complete(PRUICSS_Handle pruIcssHandle)
{
    /* get address of the send mailbox sync manager */
    bsp_send_command_to_firmware(pruIcssHandle, CMD_DL_USER_ACK_MBX_WRITE,
                                 sm_properties[MAILBOX_READ].physical_start_addr,
                                 sm_properties[MAILBOX_READ].length);
}

__inline Int16 bsp_get_sm_index(Uint16 address, Uint16 len)
{
    Int16 sm_index = -1, i;

    for(i = 2 ; i < MAX_SYNC_MAN; i++)
    {
        if((address >= sm_properties[i].physical_start_addr)
                && (address + len <= sm_properties[i].physical_start_addr +
                    sm_properties[i].length))
        {
            sm_index = i;
            break;
        }
    }

    return sm_index;
}

__inline Uint16 bsp_get_process_data_address(PRUICSS_Handle pruIcssHandle,
        Uint16 address, Uint16 len, Int16 *p_sm_index)
{
    Uint16 addr = 0;
    Int16 sm_index = bsp_get_sm_index(address, len);
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));

    //Find corresponding SYNC manager and store index in sm_index
    if(sm_index == -1)
    {
        return 0;
    }

    if(p_sm_index)
    {
        *p_sm_index = sm_index;
    }

    /* called while SM is disabled ?! should never happen; just in case... */
    if(sm_properties[sm_index].physical_start_addr == 0)
    {
        return 0;
    }

    /* are we already accessing this sm ?! in this case "lock_state" will be
     * "LOCK_PD_BUF_HOST_ACCESS_START" and we do not need the "while()"-loop... */
    if(pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state !=
            LOCK_PD_BUF_HOST_ACCESS_START)
    {
        do
        {
            /* May we access the buffer (LOCK_PD_BUF_AVAILABLE_FOR_HOST)? */
            if(pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state ==
                    LOCK_PD_BUF_AVAILABLE_FOR_HOST)
            {
                pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state =
                    LOCK_PD_BUF_HOST_ACCESS_START;
                ASSERT_DMB();
                break;
            }

            else
            {
                Task_yield();
            }
        }
        while(1);
    }

    if(pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state ==
            LOCK_PD_BUF_HOST_ACCESS_START)
    {
        addr = pHost2PruIntfc->sm_processdata[sm_index - 2].addr;
        addr = addr + (address - sm_properties[sm_index].physical_start_addr);
    }

    return addr;
}

__inline void bsp_process_data_access_complete(PRUICSS_Handle pruIcssHandle,
        Uint16 address, Uint16 len, Int16 sm_index)
{
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));

    //Find correspodning SYNC manager and store index in sm_index
    if(((sm_index < 0) || (sm_index >= MAX_SYNC_MAN)))
    {
        return;
    }

    if((address >= sm_properties[sm_index].physical_start_addr) &&
            (address + len == sm_properties[sm_index].  physical_start_addr +
             sm_properties[sm_index].length))
    {
        if(pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state ==
                LOCK_PD_BUF_HOST_ACCESS_START)
        {
            pHost2PruIntfc->sm_processdata[sm_index - 2].lock_state =
                LOCK_PD_BUF_HOST_ACCESS_FINISH;
            ASSERT_DMB();
        }
    }
}

inline void bsp_set_sm_properties(Uint8 sm, Uint16 address, Uint16 length)
{
    sm_properties[sm].physical_start_addr = address;
    sm_properties[sm].length = length;
}

inline t_sm_properties *bsp_get_sm_properties(Uint8 sm)
{
    return &sm_properties[sm];
}


inline Uint32 bsp_get_pdi_read_access_fail_cnt()
{
    return pdi_read_fail_cnt;
}

inline Uint32 bsp_get_pdi_write_access_fail_cnt()
{
    return pdi_write_fail_cnt;
}


inline Uint8  bsp_get_pdi_access_perm(Uint16 address, Uint8 access)
{
    #ifdef ENABLE_PDI_REG_PERMISSIONS
    Uint8 retval = 1;

    if(address < 4096)
        retval = ((pdi_reg_perm_array[address] == TIESC_PERM_RW) |
                  (pdi_reg_perm_array[address] == access));

    return retval;
    #else
    return 1;
    #endif
}

inline Uint8  bsp_pdi_access_perm_word(Uint16 address, Uint8 access)
{
    #ifdef ENABLE_PDI_REG_PERMISSIONS
    Uint8 retval = 1;

    if((address < 4095) && (address + 1 < 4096))
    {
        Uint8 t_perm = (~pdi_reg_perm_array[address]) & (~pdi_reg_perm_array[address
                       + 1]) & 0x3;
        retval = ((t_perm  & (~access)) == (~access & 0x3));
    }

    return retval;
    #else
    return 1;
    #endif

}

inline Uint8  bsp_pdi_access_perm_dword(Uint16 address, Uint8 access)
{
    #ifdef ENABLE_PDI_REG_PERMISSIONS
    Uint8 retval = 1;

    if((address < 4093) && (address + 3 < 4096))
    {
        Uint8 t_perm = (~pdi_reg_perm_array[address]) & (~pdi_reg_perm_array[address
                       + 1]) &
                       (~pdi_reg_perm_array[address + 2]) & (~pdi_reg_perm_array[address + 3]) &
                       0x3;
        retval = ((t_perm  & (~access)) == (~access & 0x3));
    }

    return retval;
    #else
    return 1;
    #endif


}

inline Uint8  bsp_pdi_access_perm_array(Uint16 address, Uint8 access,
                                        Uint16 size)
{
    #ifdef ENABLE_PDI_REG_PERMISSIONS
    Uint8 retval = 1;

    if((address < 4096 - size) && ((address + size - 1) < 4096))
    {
        Uint16 itr = 1;
        Uint8 t_perm = 0;
        t_perm = (~pdi_reg_perm_array[address]) & 0x3;

        for(; itr < size ; itr++)
        {
            t_perm &= (~pdi_reg_perm_array[address + itr]);
        }

        retval = ((t_perm  & (~access)) == (~access & 0x3));
    }

    return retval;
    #else
    return 1;
    #endif

}


Uint32 bsp_read_dword(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint32 DWordValue, end_addr = sm_properties[MAILBOX_WRITE].physical_start_addr +
                                  sm_properties[MAILBOX_WRITE].length;

    if(0 == bsp_pdi_access_perm_dword(address, TIESC_PERM_READ))
    {
        pdi_read_fail_cnt++;
        return 0;
    }

    DWordValue = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                   pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                           address) >> 2)]);

    if((address >= (end_addr - 4)) &&
            (address < end_addr))
    {
        bsp_pdi_mbx_read_complete(pruIcssHandle);
    }

    else
    {
        bsp_pdi_post_read_indication(pruIcssHandle, address);
    }

    return DWordValue;
}

Uint32 bsp_read_dword_isr(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint32 DWordValue;
    DWordValue = (((Uint32 *)(((PRUICSS_HwAttrs *)(
                                   pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                           address) >> 2)]);
    return DWordValue;
}

Uint16 bsp_read_word(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint16 WordValue, end_addr = sm_properties[MAILBOX_WRITE].physical_start_addr +
                                 sm_properties[MAILBOX_WRITE].length;

    if(0 == bsp_pdi_access_perm_word(address, TIESC_PERM_READ))
    {
        pdi_read_fail_cnt++;
        return 0;
    }

    WordValue = (((Uint16 *)(((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                          address) >> 1)]);

    if((address >= (end_addr - 2)) &&
            (address < end_addr))
    {
        bsp_pdi_mbx_read_complete(pruIcssHandle);
    }

    else
    {
        bsp_pdi_post_read_indication(pruIcssHandle, address);
    }

    return WordValue;
}

Uint16 bsp_read_word_isr(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint16 WordValue;
    WordValue = (((Uint16 *)(((PRUICSS_HwAttrs *)(
                                  pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM))[((
                                          address) >> 1)]);
    return WordValue;
}

Uint8 bsp_read_byte(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint8 ByteValue;

    if(0 == bsp_get_pdi_access_perm(address, TIESC_PERM_READ))
    {
        pdi_read_fail_cnt++;
        return 0;
    }

    uint8_t *pEsc = (uint8_t *)(((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    ByteValue = pEsc[address];

    if(address == (sm_properties[MAILBOX_WRITE].physical_start_addr +
                   sm_properties[MAILBOX_WRITE].length - 1))
    {
        bsp_pdi_mbx_read_complete(pruIcssHandle);
    }

    else
    {
        bsp_pdi_post_read_indication(pruIcssHandle, address);
    }

    return ByteValue;
}

inline Uint8 bsp_read_byte_isr(PRUICSS_Handle pruIcssHandle, Uint16 address)
{
    Uint8 ByteValue;
    uint8_t *pEsc = (uint8_t *)(((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    ByteValue = pEsc[address];
    return ByteValue;
}

void bsp_read(PRUICSS_Handle pruIcssHandle, Uint8 *pdata, Uint16 address,
              Uint16 len)
{
    if(0 == bsp_pdi_access_perm_array(address, TIESC_PERM_READ, len))
    {
        pdi_read_fail_cnt++;
        return;
    }

    uint8_t *pEsc = (uint8_t *)(((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    memcpy(pdata, &pEsc[address], len);
}
void bsp_write_dword(PRUICSS_Handle pruIcssHandle, Uint32 val, Uint16 address)
{
    if(0 == bsp_pdi_access_perm_dword(address, TIESC_PERM_WRITE))
    {
        pdi_write_fail_cnt++;
        return;
    }

    (((Uint32 *)(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr
                 + PRU_ICSS_SHARED_RAM))[((address) >> 2)]) = val;
    ASSERT_DMB();
}
void bsp_write_word(PRUICSS_Handle pruIcssHandle, Uint16 val, Uint16 address)
{
    if(0 == bsp_pdi_access_perm_word(address, TIESC_PERM_WRITE))
    {
        pdi_write_fail_cnt++;
        return;
    }

    (((Uint16 *)(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr
                 + PRU_ICSS_SHARED_RAM))[((address) >> 1)]) = val;
    ASSERT_DMB();
}
void bsp_write_byte(PRUICSS_Handle pruIcssHandle, Uint8 val, Uint16 address)
{
    if(0 == bsp_get_pdi_access_perm(address, TIESC_PERM_WRITE))
    {
        pdi_write_fail_cnt++;
        return;
    }

    uint8_t *pEsc = (uint8_t *)(((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    pEsc[address] = val;
    ASSERT_DMB();
}
void bsp_write(PRUICSS_Handle pruIcssHandle, Uint8 *pdata, Uint16 address,
               Uint16 len)
{
    if(0 == bsp_pdi_access_perm_array(address, TIESC_PERM_WRITE, len))
    {
        pdi_write_fail_cnt++;
        return;
    }

    uint8_t *pEsc = (uint8_t *)(((PRUICSS_HwAttrs *)(
                                     pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_SHARED_RAM);
    memcpy(&pEsc[address], pdata, len);
    ASSERT_DMB();
    ASSERT_DSB();
}
inline Uint32 bsp_pruss_mdioreg_read(PRUICSS_Handle pruIcssHandle,
                                     Uint32 regoffset)
{
    Uint32 regval;
    regval = HWREG((Uint32)(((PRUICSS_HwAttrs *)(
                                 pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_MDIO) + regoffset);
    return regval;
}
inline void bsp_pruss_mdioreg_write(PRUICSS_Handle pruIcssHandle, Uint32 val,
                                    Uint32 regoffset)
{
    HWREG((Uint32)(((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr
                   + PRU_ICSS_MDIO) + regoffset) = val;
    ASSERT_DMB();
}
Uint32 bsp_pruss_iepreg_read(PRUICSS_Handle pruIcssHandle, Uint32 regoffset)
{
    Uint32 regval;
    regval = HWREG((Uint32)((PRUICSS_HwAttrs *)(
                                pruIcssHandle->hwAttrs))->baseAddr + PRU_ICSS_IEP + regoffset);
    return regval;
}
inline void bsp_pruss_iepreg_write(PRUICSS_Handle pruIcssHandle, Uint32 val,
                                   Uint32 regoffset)
{
    HWREG((Uint32)((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr +
          PRU_ICSS_IEP + regoffset) = val;
    ASSERT_DMB();
}
inline Uint16 bsp_pruss_cmd_intfc_read_word(volatile Uint16 *ptr)
{
    Uint16 val;
    val = *ptr;
    return val;
}
inline void bsp_pruss_cmd_intfc_write_word(Uint16 val, volatile Uint16 *ptr)
{
    *ptr = val;
    ASSERT_DMB();
}

inline Uint8 bsp_pdi_sm_config_ongoing(PRUICSS_Handle pruIcssHandle)
{
    volatile t_host_interface *pHost2PruIntfc = (volatile t_host_interface *)
            ((((PRUICSS_HwAttrs *)(pruIcssHandle->hwAttrs))->baseAddr) +
             PRU_ICSS_DATARAM(0));
    return pHost2PruIntfc->sm_config_ongoing;
}
inline void bsp_hwspinlock_init(void)
{
    Uint32 regval;
    #ifdef AM43XX_FAMILY_BUILD
    HWREG(SOC_CM_PER_REG + PRCM_CM_PER_SPINLOCK_CLKCTRL) =
        2; //Enable spinlock clock in CM_PER_SPINLOCK_CLKCTRL
    #elif defined(AM335X_FAMILY_BUILD)
    HWREG(CM_PER_SPINLOCK_CLKCTRL_OFFSET) =
        2; //Enable spinlock clock in CM_PER_SPINLOCK_CLKCTRL
    #endif

    for(regval = 0; regval < 8; regval++)
    {
        bsp_hwspinlock_unlock(regval);
    }
}

inline Uint32 bsp_hwspinlock_lock(int num)
{
    return HWREG(SPINLOCK_LOCKREG0_OFFSET + (num <<
                 2));   //0: succcess 1: already locked
}

inline void bsp_hwspinlock_unlock(int num)
{
    HWREG(SPINLOCK_LOCKREG0_OFFSET + (num << 2)) = 0;
}

void bsp_global_mutex_lock(void)
{
    //escGlobalIArg = GateAll_enter (escGlobalGateHandle);
    //Disable PDI and SYNC0 ISR at ARM INTC (rather than global IRQ disable)
    #ifdef AM43XX_FAMILY_BUILD
    Hwi_disableInterrupt(HOST_AL_EVENT + 32);
    Hwi_disableInterrupt(HOST_SYNC0_EVENT + 32);
    #elif defined(AM335X_FAMILY_BUILD)
    Hwi_disableInterrupt(HOST_AL_EVENT);
    Hwi_disableInterrupt(HOST_SYNC0_EVENT);
    #endif
}

void bsp_global_mutex_unlock(void)
{
    //GateAll_leave (escGlobalGateHandle, escGlobalIArg);
    //Enable back PDI and SYNC0 ISR at ARM INTC
    #ifdef AM43XX_FAMILY_BUILD
    Hwi_enableInterrupt(HOST_AL_EVENT + 32);
    Hwi_enableInterrupt(HOST_SYNC0_EVENT + 32);
    #elif defined(AM335X_FAMILY_BUILD)
    Hwi_enableInterrupt(HOST_AL_EVENT);
    Hwi_enableInterrupt(HOST_SYNC0_EVENT);
    #endif
}

void bsp_set_eeprom_update_status(Uint8 status)
{
    #ifdef EEPROM_SPI
    eeprom_updated = status;
    #endif
}

inline Uint8 bsp_get_eeprom_update_status(void)
{
    #ifdef EEPROM_SPI
    return eeprom_updated;
    #else
    return 0;
    #endif
}

inline Uint8 *bsp_get_eeprom_cache_base(void)
{
    return eeprom_cache;
}

inline void bsp_set_eeprom_updated_time()
{
    #ifdef EEPROM_SPI
    #ifdef USE_ECAT_TIMER
    bsp_get_local_sys_time(&eeprom_updated_time, NULL);
    #else
    eeprom_updated_time = Timestamp_get32();
    #endif
    #endif
}

inline Uint32 bsp_get_eeprom_updated_time()
{
    #ifdef EEPROM_SPI
    return eeprom_updated_time;
    #else
    return 0;
    #endif
}

inline void bsp_set_pru_firmware(Uint32 *frameProc, Uint32 frameProcLen,
                                 Uint32 *hostProc, Uint32 hostProcLen)
{
    pru_frame_proc = frameProc;
    pru_host_proc = hostProc;
    pru_frame_proc_len = frameProcLen;
    pru_host_proc_len = hostProcLen;
}

#ifdef ENABLE_ONLINE_FIRMWARE_UPGRADE

void bsp_start_fw_download(Uint32 password)
{
    #if !defined (EXEC_FROM_IRAM) && !defined (XIP_NOR)
    fw_download_flag = 1;
    #ifndef NO_UART_MSG_APP
    CONSOLEUtilsPrintf("\n\r FW downlaod started");
    #endif
    #endif
}

#include "board_mcspi.h"
#ifdef AM43XX_FAMILY_BUILD
    #include "board_qspi.h"
    extern qspiObj_t *gQSPIFlashObj;
#endif
extern mcspiCfgObj_t *gSPIFlashObj;

void bsp_store_fw_data(Uint16 *pData, Uint16 Size)
{
    #if !defined (EXEC_FROM_IRAM) && !defined (XIP_NOR)

    Uint32 itr1 = 0;
    Uint8 *temp_ptr = (Uint8 *)pData;
    Uint8 data_buff[256];

    for(itr1 = 0 ; itr1 < Size  ; itr1++)
    {
        write_to_cir_buff(temp_ptr[itr1]);
    }

    while(get_cir_buff_avail_bytes() >= 256)
    {

        #ifdef AM335X_FAMILY_BUILD

        //Call Flash write code from here
        if((fw_write_offset & 0xFFF) == 0)
        {
            //Erase Flash sector

            gSPIFlashObj->dataLength = 256;
            Board_eraseSpiFlash(fw_write_offset, gSPIFlashObj);
        #elif defined(AM43XX_FAMILY_BUILD)

        //Call Flash write code from here
        if((fw_write_offset & 0xFFFF) == 0)
        {
            //Erase Flash sector
            uint32_t blockNumber = (fw_write_offset) /
                                   gQSPIFlashObj->qspiLibInfo.qspiLibFlashInfo.blockSize;
            QSPILibBlockErase(&(gQSPIFlashObj->qspiLibInfo), blockNumber);
        #endif
        }

        if(read_from_cir_buff(data_buff, 256) >= 256)
        {
            Board_writeFlashStorage(fw_write_offset, 256, data_buff, 0);
            fw_write_offset += 256;
        }
    }

    #endif

}

void bsp_boot_2_init_handler()
{
    #if !defined (EXEC_FROM_IRAM) && !defined (XIP_NOR)

    uint8_t data_buff[256];

    /*
     * Make sure that firware is completely written to SPI flash
     */
    while(get_cir_buff_avail_bytes() >= 256)
    {

        #ifdef AM335X_FAMILY_BUILD

        //Call Flash write code from here
        if((fw_write_offset & 0xFFF) == 0)
        {
            //Erase Flash sector

            gSPIFlashObj->dataLength = 256;
            Board_eraseSpiFlash(fw_write_offset, gSPIFlashObj);
        #elif defined(AM43XX_FAMILY_BUILD)

        //Call Flash write code from here
        if((fw_write_offset & 0xFFFF) == 0)
        {
            //Erase Flash sector
            uint32_t blockNumber = (fw_write_offset) /
                                   gQSPIFlashObj->qspiLibInfo.qspiLibFlashInfo.blockSize;
            QSPILibBlockErase(&(gQSPIFlashObj->qspiLibInfo), blockNumber);
        #endif
        }

        if(read_from_cir_buff(data_buff, 256) >= 256)
        {
            Board_writeFlashStorage(fw_write_offset, 256, data_buff, 0);
            fw_write_offset += 256;
        }
    }

    /*
     * Set FW reload flag from here if a new binary is recieved
     */
    if(fw_download_flag)
    {
        #ifndef NO_UART_MSG_APP
        CONSOLEUtilsPrintf("\n\r FW Download completed\n\r");
        #endif
        //reset the flag
        fw_download_flag = 0;
        //Set Restart flag
    }

    #endif
}

#endif
