This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM4376: Multistage booting and restarting SYSBIOS app on A9

Part Number: AM4376
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Hi all

We are making an application Running on AM4376 TI-RTOS. Application's base is 0x80000000, Boot loader runs from 0x90000000 so that it doesn't step on the application.

It's main file is : 

/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
*
* 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 Files */
/* ========================================================================== */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/a8/Mmu.h>

#include <ti/ndk/inc/stkmain.h>

#include <ti/drv/emac/emac_drv.h>
#include <ti/drv/emac/src/v4/emac_drv_v4.h>

#include <ti/starterware/include/types.h>
#include <ti/starterware/include/hw/hw_types.h>
#include <ti/starterware/include/hw/hw_control_am43xx.h>
#include <ti/starterware/include/hw/am437x.h>
#include <ti/starterware/include/ethernet.h>

#include <ti/board/board.h>

/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/UART_stdio.h>

/* GPIO Header files */
#include "FG_gpio.h"

/* GPMC Header files */
#include <ti/csl/src/ip/gpmc/V1/hw_gpmc.h>
#include <ti/drv/gpmc/GPMC.h>
#include <ti/drv/gpmc/src/V1/GPMC_v1.h>

#include <netmain.h>
#include <_stack.h>
#include <_oskern.h>

#include "FGComm.h"
#include "FG_gpmc.h"
#include "FG_edma.h"
#include "GeneralDef.h"
#include "CommandsApi.h"
#include "FgPcCommonDef.h"
#include "FG_FrameServer.h"
#include "ComStateMachine.h"

extern char *LocalIPAddr;

/* Enable the below macro to have prints on the IO Console */
//#define IO_CONSOLE

#ifndef IO_CONSOLE
#define NIMU_log UART_printf
#else
#define NIMU_log printf
#endif

/* ========================================================================== */
/* Macros */
/* ========================================================================== */

/**Phy address of the CPSW port 1*/
#define EMAC_CPSW_PORT0_PHY_ADDR_SK 4
/**Phy address of the CPSW port 2*/
#define EMAC_CPSW_PORT1_PHY_ADDR_SK 5

#define MAX_TABLE_ENTRIES 3

/* ========================================================================== */
/* Global Variables */
/* ========================================================================== */

/**Task handle for EIP*/
Task_Handle main_task;

static int nimu_device_index = 0U;


NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];

void TaskFxn(UArg a0, UArg a1);
extern int CpswEmacInit (STKEVENT_Handle hEvent);

/* ========================================================================== */
/* Function Definitions */
/* ========================================================================== */

void CpswPortMacModeSelect(uint32_t portNum, uint32_t macMode)
{
uint32_t regVal = 0U;

regVal = HW_RD_REG32(SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL);

switch(macMode)
{
case ETHERNET_MAC_TYPE_MII:
case ETHERNET_MAC_TYPE_GMII:
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

case ETHERNET_MAC_TYPE_RMII: /* RMII */
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 1U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 1U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

case ETHERNET_MAC_TYPE_RGMII: /* RGMII */
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 2U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 2U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

default:
break;
}

HW_WR_REG32((SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL), regVal);
}


#define SYS_MMU_BUFFERABLE 1
#define SYS_MMU_CACHEABLE 2
#define SYS_MMU_SHAREABLE 4
#define SYS_MMU_NO_EXECUTE 8
typedef struct _sys_mmu_entry
{

void* address;
/**< Address to be entered in MMU table. */
unsigned int attributes;
/**< Attributes of the memory. */
}SYS_MMU_ENTRY;


SYS_MMU_ENTRY applMmuEntries[] = {
{(void*)0x01000000,SYS_MMU_NO_EXECUTE}, //GPMC Altera cs0 mem space
{(void*)0x02000000,SYS_MMU_NO_EXECUTE}, //GPMC Altera cs1 mem space
{(void*)0x30000000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30100000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30200000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30300000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x40300000,0}, //OCMCRAM - Cacheable
{(void*)0x44D00000, SYS_MMU_BUFFERABLE}, //PRCM - Non bufferable| Non Cacheable
{(void*)0x44E00000, SYS_MMU_BUFFERABLE}, //Clock Module, PRM, GPIO0, UART0, I2C0, - Non bufferable| Non Cacheable
{(void*)0x48800000, 0}, //GPIO1
{(void*)0x48300000, 0}, //GPIO5
{(void*)0x47900000,SYS_MMU_BUFFERABLE}, //QSPI MMR Maddr0space
{(void*)0x48000000, SYS_MMU_BUFFERABLE}, //UART1,UART2,I2C1,McSPI0,McASP0 CFG,McASP1 CFG,DMTIMER,GPIO1 -Non bufferable| Non Cacheable
{(void*)0x48100000, SYS_MMU_BUFFERABLE}, //I2C2,McSPI1,UART3,UART4,UART5, GPIO2,GPIO3,MMC1 - Non bufferable| Non Cacheable
{(void*)0x48200000, SYS_MMU_BUFFERABLE}, //
{(void*)0x48300000, SYS_MMU_BUFFERABLE}, //PWM - Non bufferable| Non Cacheable
{(void*)0x49000000, 0}, //EDMA3CC - Non bufferable| Non Cacheable
{(void*)0x4A000000, SYS_MMU_BUFFERABLE}, //L4 FAST CFG- Non bufferable| Non Cacheable
{(void*)0x4A100000, SYS_MMU_BUFFERABLE}, //CPSW - Non bufferable| Non Cacheable
{(void*)0x50000000, 0}, //GPMC - Non bufferable| Non Cacheable
{(void*)0x49800000, 0}, //EDMA TC0
{(void*)0x49900000, 0}, //EDMA TC1
{(void*)0x49A00000, 0}, //EDMA TC2
{(void*)0x54400000, SYS_MMU_BUFFERABLE}, //PRU-ICSS0/1 -Bufferable| Non Cacheable | Shareable
{(void*)0x80000000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0x80100000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0x80200000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0xB0000000, 0}, // image buffers

{(void*)0xFFFFFFFF,0xFFFFFFFF}
};
int SDKMMUInit(SYS_MMU_ENTRY mmuEntries[])
{
unsigned short itr = 0;
char *frameAddr = (char *)FRAME_BUFFER_START_ADDRESS;
int nMemBlocks;
Mmu_FirstLevelDescAttrs attrs;

if(NULL == mmuEntries)
return -1;

Mmu_disable();

Mmu_initDescAttrs(&attrs);

attrs.type = Mmu_FirstLevelDesc_SECTION;
attrs.domain = 0;
attrs.imp = 1;
attrs.accPerm = 3;


for(itr = 0 ; mmuEntries[itr].address != (void*)0xFFFFFFFF ; itr++)
{
attrs.bufferable = ((mmuEntries[itr].attributes) & SYS_MMU_BUFFERABLE) && 1 ;
attrs.cacheable = ((mmuEntries[itr].attributes) & SYS_MMU_CACHEABLE) && 1;
if (!attrs.bufferable && !attrs.cacheable)
attrs.tex = 0; //tex is initialized to 1 and need this to force strongly ordered
attrs.shareable = ((mmuEntries[itr].attributes) & SYS_MMU_SHAREABLE) && 1;
attrs.noexecute = ((mmuEntries[itr].attributes) & SYS_MMU_NO_EXECUTE) && 1;
Mmu_setFirstLevelDesc((Ptr)(mmuEntries[itr].address), (Ptr)(mmuEntries[itr].address) , &attrs); // PWM
}

// setup frame buffer memory access -
nMemBlocks = GetFrameBufferMemorySize() / 0x100000 + 1;
attrs.bufferable = 1;
attrs.cacheable = 1;
attrs.shareable = 0;
attrs.noexecute = 0;
for (itr = 0; itr < nMemBlocks; itr++) {
Mmu_setFirstLevelDesc((Ptr)frameAddr, (Ptr)frameAddr, &attrs);
frameAddr += 0x100000;
}

Mmu_enable();
return 0;
}

GPMC_Params gpmcParams; /* GPMC params structure */
GPMC_Handle hwGpmcHandle; /* GPMC handle */

void StartGpmc(void)
{
/* Init GPMC driver */
//GPMC_init();
/* Use default GPMC config params if no params provided */
//GPMC_Params_init(&gpmcParams);
//hwGpmcHandle = (GPMC_Handle)GPMC_open(0, &gpmcParams);
}

/**
* \name main
* \brief Main Function
* \param none
* \return none
*
*/
int main()
{
/* Call board init functions */
Board_initCfg boardCfg;
Task_Params taskParams;
EMAC_HwAttrs_V4 cfg;

SDKMMUInit(applMmuEntries);
//Mmu_disable();

boardCfg = BOARD_INIT_PINMUX_CONFIG |
BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
Board_init(boardCfg);

//int x = *(volatile uint32_t *)0x481AE000;
//if (x != 0x50600801)
// return 0;

FG_GpioInit();
FGgpmcInit();

/* Chip configuration MII/RMII selection */
CpswPortMacModeSelect(1, ETHERNET_MAC_TYPE_RGMII);
CpswPortMacModeSelect(2, ETHERNET_MAC_TYPE_RGMII);

EMAC_socGetInitCfg(0, &cfg);
cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
EMAC_socSetInitCfg(0, &cfg);

Task_Params_init(&taskParams);
taskParams.priority = 1;
taskParams.stackSize = 0x1400;
main_task = Task_create (TaskFxn, &taskParams, NULL);

NIMUDeviceTable[nimu_device_index++].init = &CpswEmacInit ;
NIMUDeviceTable[nimu_device_index].init = NULL ;

BIOS_start();

return -1;
}


/**
* \name TaskFxn
* \brief Task which do EIP initialization
* \param a0
* \param a1
* \return none
*
*/
void TaskFxn(UArg a0, UArg a1)
{
int i;
uint32_t baseAddr = 0x50000000 + GPMC_CONFIG1_N(0);
CI_IPNET NA;
char IPString[16];


//NIMU_log("\n\rSYS/BIOS Ethernet/IP (CPSW) Sample application, EVM IP address: %s\n\r", LocalIPAddr);
FG_edmaInit();

for (i=0; i<7; i++)
{
uint32_t val = *(volatile uint32_t *) (baseAddr + i * 4);
NIMU_log("CONFIG%d: %X\n",i + 1, val);
}

baseAddr = *(volatile uint32_t *) (0x0100003C);
NIMU_log("GPMC Date: %X\n",baseAddr);
NIMU_log("Enable GPMC debug mode\n");

// setup debug transfer of frames
//Write2GPMC(0x0100006C, 1); // debug mode
Write2GPMC(0x01000008, 10000); // 10 seconds frame rate
Write2GPMC(0x0100006E, 52); // 52us fifo fill rate
//Write2GPMC(0x01000012, 1); // start transfer

if (CfgGetImmediate( 0, CFGTAG_IPNET, 0, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA))
{
/* Yes the device was configured and we got the IP address/Mask */
NtIPN2Str (NA.IPAddr, IPString);
UART_printf ("IP Address : %s\n", IPString);
NtIPN2Str (NA.IPMask, IPString);
UART_printf ("IP Mask : %s\n", IPString);
}

memset(TxMessageBuffer, 0, sizeof(char) * MAX_TX_MESSAGE_SIZE);
for (i = 0; i < NUM_OF_REAL_CAMERAS; i++)
{
SensorInitialization((eCameras)i);
}
//SensorInitialization(CAMERA1);

// Start the frame server
FGInitFrameServer();
// test frame transfer
StartComm();
System_printf("test system printf\n");
printf("test printf\n");
}


// handle exceptions
void FG_Exeption(uint32_t *stack, uint32_t lr)
{
GPIO_write(GPIO_LED1, 1);
}

/*SOCKET TelnetCallback(PSA pSinClient)
{
NIMU_log("\nTelnet opened at socket %d\n", )
}
}*/

char *VerStr = "\nWelcome To EVS console\n";

We built a boot loader which gets the application image from TFTP server and saves it to memory to address 0x8000000 and jumps to it.

The code of boot loader main is:

/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
*
* 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 Files */
/* ========================================================================== */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/a8/Mmu.h>

#include <ti/ndk/inc/stkmain.h>
#include <ti/ndk/inc/netmain.h>

#include <ti/drv/emac/emac_drv.h>
#include <ti/drv/emac/src/v4/emac_drv_v4.h>

#include <ti/starterware/include/types.h>
#include <ti/starterware/include/hw/hw_types.h>
#include <ti/starterware/include/hw/hw_control_am43xx.h>
#include <ti/starterware/include/hw/am437x.h>
#include <ti/starterware/include/ethernet.h>

#include <ti/sysbios/hal/Hwi.h>

#include <ti/board/board.h>

/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/UART_stdio.h>

extern char *LocalIPAddr;

/* Enable the below macro to have prints on the IO Console */
//#define IO_CONSOLE

#ifndef IO_CONSOLE
#define NIMU_log UART_printf
#else
#define NIMU_log printf
#endif

/* ========================================================================== */
/* Macros */
/* ========================================================================== */

/**Phy address of the CPSW port 1*/
#define EMAC_CPSW_PORT0_PHY_ADDR_SK 4
/**Phy address of the CPSW port 2*/
#define EMAC_CPSW_PORT1_PHY_ADDR_SK 5

#define MAX_TABLE_ENTRIES 3

#define REMOTE_IP_ADDRESS "193.100.100.251"

#define FG_BASE_ADDRESS 0x80000000

#define MAX_BLOCK_SIZE 65464

/* ========================================================================== */
/* Global Variables */
/* ========================================================================== */

/**Task handle for EIP*/
Task_Handle main_task;

static int nimu_device_index = 0U;


NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];

static void (*pfnFGAppEntry)();
void TaskFxn(UArg a0, UArg a1);
extern int CpswEmacInit (STKEVENT_Handle hEvent);

/* ========================================================================== */
/* Function Definitions */
/* ========================================================================== */

void CpswPortMacModeSelect(uint32_t portNum, uint32_t macMode)
{
uint32_t regVal = 0U;

regVal = HW_RD_REG32(SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL);

switch(macMode)
{
case ETHERNET_MAC_TYPE_MII:
case ETHERNET_MAC_TYPE_GMII:
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

case ETHERNET_MAC_TYPE_RMII: /* RMII */
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 1U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 1U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

case ETHERNET_MAC_TYPE_RGMII: /* RGMII */
if(1U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 2U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
}
else if(2U == portNum)
{
HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 2U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
}
else
{
/* This error does not happen because of check done already */
}
break;

default:
break;
}

HW_WR_REG32((SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL), regVal);
}


#define SYS_MMU_BUFFERABLE 1
#define SYS_MMU_CACHEABLE 2
#define SYS_MMU_SHAREABLE 4
#define SYS_MMU_NO_EXECUTE 8
typedef struct _sys_mmu_entry
{

    void* address;
    /**< Address to be entered in MMU table. */
    unsigned int attributes;
    /**< Attributes of the memory. */
}SYS_MMU_ENTRY;


SYS_MMU_ENTRY applMmuEntries[] = {
{(void*)0x30000000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30100000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30200000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x30300000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Cacheable
{(void*)0x40300000,0}, //OCMCRAM - Cacheable
{(void*)0x44D00000, SYS_MMU_BUFFERABLE}, //PRCM - Non bufferable| Non Cacheable
{(void*)0x44E00000, SYS_MMU_BUFFERABLE}, //Clock Module, PRM, GPIO0, UART0, I2C0, - Non bufferable| Non Cacheable
{(void*)0x47900000,SYS_MMU_BUFFERABLE}, //QSPI MMR Maddr0space
{(void*)0x48000000, SYS_MMU_BUFFERABLE}, //UART1,UART2,I2C1,McSPI0,McASP0 CFG,McASP1 CFG,DMTIMER,GPIO1 -Non bufferable| Non Cacheable
{(void*)0x48100000,0}, //I2C2,McSPI1,UART3,UART4,UART5, GPIO2,GPIO3,MMC1 - Non bufferable| Non Cacheable
{(void*)0x48200000, SYS_MMU_BUFFERABLE}, //
{(void*)0x48300000, SYS_MMU_BUFFERABLE}, //PWM - Non bufferable| Non Cacheable
{(void*)0x49000000, SYS_MMU_BUFFERABLE}, //EDMA3CC - Non bufferable| Non Cacheable
{(void*)0x4A000000, SYS_MMU_BUFFERABLE}, //L4 FAST CFG- Non bufferable| Non Cacheable
{(void*)0x4A100000, SYS_MMU_BUFFERABLE}, //CPSW - Non bufferable| Non Cacheable
{(void*)0x54400000, SYS_MMU_BUFFERABLE}, //PRU-ICSS0/1 -Bufferable| Non Cacheable | Shareable
//{(void*)0x90000000,SYS_MMU_CACHEABLE}, //QSPI CS0 Maddr1space - Non bufferable| Non Cacheable
{(void*)0x80000000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE}, //App memory
{(void*)0x80100000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE}, //App memory
{(void*)0x80200000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE}, //App memory
{(void*)0x90000000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0x90100000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0x90200000, SYS_MMU_CACHEABLE}, //App memory
{(void*)0xFFFFFFFF,0xFFFFFFFF}
};
int SDKMMUInit(SYS_MMU_ENTRY mmuEntries[])
{
    unsigned short itr = 0;
    Mmu_FirstLevelDescAttrs attrs;

    if(NULL == mmuEntries)
        return -1;

    Mmu_disable();

    Mmu_initDescAttrs(&attrs);

    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.domain = 0;
    attrs.imp = 1;
    attrs.accPerm = 3;


    for(itr = 0 ; mmuEntries[itr].address != (void*)0xFFFFFFFF ; itr++)
    {
        attrs.bufferable = ((mmuEntries[itr].attributes) & SYS_MMU_BUFFERABLE) && 1 ;
        attrs.cacheable = ((mmuEntries[itr].attributes) & SYS_MMU_CACHEABLE) && 1;
        if (!attrs.bufferable && !attrs.cacheable)
            attrs.tex = 0; //tex is initialized to 1 and need this to force strongly ordered
        attrs.shareable = ((mmuEntries[itr].attributes) & SYS_MMU_SHAREABLE) && 1;
        attrs.noexecute = ((mmuEntries[itr].attributes) & SYS_MMU_NO_EXECUTE) && 1;
        Mmu_setFirstLevelDesc((Ptr)(mmuEntries[itr].address), (Ptr)(mmuEntries[itr].address) , &attrs); // PWM

    }
    Mmu_enable();
    return 0;

}

/**
* \name main
* \brief Main Function
* \param none
* \return none
*
*/
int main()
{
    /* Call board init functions */
    Board_initCfg boardCfg;
    Task_Params taskParams;
    EMAC_HwAttrs_V4 cfg;

    SDKMMUInit(applMmuEntries);

    boardCfg = BOARD_INIT_PINMUX_CONFIG |
    BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(boardCfg);

    /* Chip configuration MII/RMII selection */
    CpswPortMacModeSelect(1, ETHERNET_MAC_TYPE_RGMII);
    CpswPortMacModeSelect(2, ETHERNET_MAC_TYPE_RGMII);

    EMAC_socGetInitCfg(0, &cfg);
    cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
    cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
    EMAC_socSetInitCfg(0, &cfg);

    Task_Params_init(&taskParams);
    taskParams.priority = 1;
    taskParams.stackSize = 0x1400;
    main_task = Task_create (TaskFxn, &taskParams, NULL);

    NIMUDeviceTable[nimu_device_index++].init = &CpswEmacInit ;
    NIMUDeviceTable[nimu_device_index].init = NULL ;

    BIOS_start();

    return -1;
}

static void jumpStackPointer(uint32_t address)
{
        pfnFGAppEntry = (void (*)(void)) address;

       (*pfnFGAppEntry)( );
      /*__asm(" mov sp, r0\n" // sp is now *address
                    " bx r0\n" ); // jump to *address */
}

void jumpToApplication(UArg a0, UArg a1)
{
       /*
        * Disable interrupts
        */
        NIMU_log ("All interrupts are disabled\n");
        char *p = (char *)(FG_BASE_ADDRESS);
        NIMU_log("jump context = 0x%08X\n", *(unsigned int *)p);

       NIMU_log("Jumping... \n");
       jumpStackPointer(FG_BASE_ADDRESS);
}

/**
* \name TaskFxn
* \brief Task which do EIP initialization
* \param a0
* \param a1
* \return none
*
*/
void TaskFxn(UArg a0, UArg a1)
{
      CI_IPNET NA;
      char IPString[16];
      char *pBuf = (char *)FG_BASE_ADDRESS;
      int firmlen, res;
      uint16_t errcode;

     /* Allocate the file environment for this task */
     fdOpenSession( TaskSelf() );

     if (CfgGetImmediate( 0, CFGTAG_IPNET, 0, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA)) {
          /* Yes the device was configured and we got the IP address/Mask */
         NtIPN2Str (NA.IPAddr, IPString);
         NIMU_log ("IP Address : %s\n", IPString);
         NtIPN2Str (NA.IPMask, IPString);
         NIMU_log ("IP Mask : %s\n", IPString);
    }

    /* Wait for the link to come up */
   Task_sleep(10000);

    while (1) {
         firmlen = MAX_BLOCK_SIZE;

         res = NtTftpRecv(inet_addr(REMOTE_IP_ADDRESS), "FGBoardProto.bin", pBuf, (UINT32 *)&firmlen, &errcode); 
         if (res == 0 || res == 1) {
              NIMU_log ("Firmware file found with len %d, res is %d\n", firmlen, res);
              break;
         } else {
              NIMU_log ("Error (%d/%d) fetching firmware\n", res, (int)errcode);
         }
    }

    NIMU_log ("Firmware download is complete. Jumping to FW\n");
   {
        Task_Params taskParams;
        EMAC_HwAttrs_V4 cfg;
        EMAC_socGetInitCfg(0, &cfg);
        cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
        cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
        EMAC_socSetInitCfg(0, &cfg);

        Task_Params_init(&taskParams);
        taskParams.priority = 1;
        taskParams.stackSize = 0x1400;
        main_task = Task_create(jumpToApplication, &taskParams, NULL);
   }

   fdCloseSession( TaskSelf() )

   TaskDestroy( TaskSelf() );

}

// handle exceptions
void BL_Exception(uint32_t *stack, uint32_t lr)
{
      NIMU_log("Exception occurred \n");
}

Boot loader Config file is as such:

/**
* \file nimu_skam437x.cfg
*
* \brief This file is included in the ethernet switch example
*
*/

/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
* 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.
*
*/

/* ================ General configuration ================ */

var enableStaticIP = 1;

/* use modules */
var Defaults = xdc.useModule('xdc.runtime.Defaults');
var Diags = xdc.useModule('xdc.runtime.Diags');
var Error = xdc.useModule('xdc.runtime.Error');
var Main = xdc.useModule('xdc.runtime.Main');
var Memory = xdc.useModule('xdc.runtime.Memory')
var SysMin = xdc.useModule('xdc.runtime.SysMin');
var System = xdc.useModule('xdc.runtime.System');
var Text = xdc.useModule('xdc.runtime.Text');
var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var Timer = xdc.useModule('ti.sysbios.timers.dmtimer.Timer');
var Swi = xdc.useModule('ti.sysbios.knl.Swi');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
var ti_sysbios_hal_Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
var SysMin = xdc.useModule('xdc.runtime.SysMin');
var SemiHostSupport = xdc.useModule('ti.sysbios.rts.gnu.SemiHostSupport');

/* NDK modules */
var Global = xdc.useModule('ti.ndk.config.Global');
var Ip = xdc.useModule('ti.ndk.config.Ip');
var Tcp = xdc.useModule('ti.ndk.config.Tcp');
var Udp = xdc.useModule('ti.ndk.config.Udp');
var Telnet = xdc.useModule('ti.ndk.config.Telnet');
var Exception = xdc.useModule('ti.sysbios.family.arm.exc.Exception');


/*
* Program.argSize sets the size of the .args section.
* The examples don't use command line args so argSize is set to 0.
*/
//Program.argSize = 0x0;

/* System stack size (used by ISRs and Swis) */
Program.stack = 0x10000;

/*
* Uncomment this line to globally disable Asserts.
* All modules inherit the default from the 'Defaults' module. You
* can override these defaults on a per-module basis using Module.common$.
* Disabling Asserts will save code space and improve runtime performance.
Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
*/

/*
* Uncomment this line to keep module names from being loaded on the target.
* The module name strings are placed in the .const section. Setting this
* parameter to false will save space in the .const section. Error and
* Assert messages will contain an "unknown module" prefix instead
* of the actual module name.
Defaults.common$.namedModule = false;
*/

/*
* Minimize exit handler array in System. The System module includes
* an array of functions that are registered with System_atexit() to be
* called by System_exit().
*/
System.maxAtexitHandlers = 4;

/*
* Uncomment this line to disable the Error print function.
* We lose error information when this is disabled since the errors are
* not printed. Disabling the raiseHook will save some code space if
* your app is not using System_printf() since the Error_print() function
* calls System_printf().
Error.raiseHook = null;
*/

/*
* Uncomment this line to keep Error, Assert, and Log strings from being
* loaded on the target. These strings are placed in the .const section.
* Setting this parameter to false will save space in the .const section.
* Error, Assert and Log message will print raw ids and args instead of
* a formatted message.
Text.isLoaded = false;
*/

/*
* Uncomment this line to disable the output of characters by SysMin
* when the program exits. SysMin writes characters to a circular buffer.
* This buffer can be viewed using the SysMin Output view in ROV.
SysMin.flushAtExit = false;
*/

/* ================ BIOS configuration ================ */

var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.libType = BIOS.LibType_Custom;

/*
* The BIOS module will create the default heap for the system.
* Specify the size of this default heap.
*/
BIOS.heapSize = 0xA0000;

if (enableStaticIP)
{
    /* Settings for static IP configuration */
    Ip.ResolveIP = false;
    Ip.CallByIP = false;
    Ip.autoIp = false;
    Ip.address = "193.100.100.40";
    Ip.mask = "255.255.255.0";
    Ip.gatewayIpAddr = "193.100.100.251";
}
else
{
    Ip.dhcpClientMode = Ip.CIS_FLG_IFIDXVALID;
}

Global.ndkTickPeriod = 100;
Global.kernTaskPriLevel = 11;
Global.serviceReportHook = null;
Global.IPv6 = false;
Global.pktNumFrameBufs=384;

Tcp.transmitBufSize = 16384;
Tcp.receiveBufSize = 65536;
Tcp.receiveBufLimit = 65536;

Task.defaultStackSize = 4096;
Task.idleTaskStackSize = 4096;

System.SupportProxy = SysMin;

/* Circular buffer size for System_printf() */
SysMin.bufSize = 0x200;

/* ================ Driver configuration ================ */

var socType = "am437x";

/* Load the OSAL package */
var osType = "tirtos";
var Osal = xdc.useModule('ti.osal.Settings');
Osal.osType = osType;
Osal.socType = socType;


/* Load the CSL package */
/*use CSL package*/
var Csl = xdc.loadPackage('ti.csl');
Csl.Settings.deviceType = socType;

/* Load the UART package */
var UART = xdc.loadPackage('ti.drv.uart');
UART.Settings.socType = socType;

/* Load the I2C package */
var I2C = xdc.loadPackage('ti.drv.i2c');

/* Load the Board package and set the board name */
var Board = xdc.loadPackage('ti.board');
Board.Settings.boardName = "skAM437x";

/* Load the EMAC packages */
var Emac = xdc.loadPackage('ti.drv.emac');
Emac.Settings.socType = socType;


/* Load the NIMU packages */
var Nimu = xdc.loadPackage('ti.transport.ndk.nimu');
Nimu.Settings.socType = socType;
/* ================ Cache and MMU configuration ================ */

var Cache = xdc.useModule('ti.sysbios.family.arm.a9.Cache');
Cache.enableCache = true;

var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
Mmu.enableMMU = true;

BIOS.logsEnabled = true;
Exception.excHookFunc = "&BL_Exception";

nimu_skam437x.cfg

/*
 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  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 Files                                  */
/* ========================================================================== */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/a8/Mmu.h>

#include <ti/ndk/inc/stkmain.h>
#include <ti/ndk/inc/netmain.h>

#include <ti/drv/emac/emac_drv.h>
#include <ti/drv/emac/src/v4/emac_drv_v4.h>

#include <ti/starterware/include/types.h>
#include <ti/starterware/include/hw/hw_types.h>
#include <ti/starterware/include/hw/hw_control_am43xx.h>
#include <ti/starterware/include/hw/am437x.h>
#include <ti/starterware/include/ethernet.h>

#include <ti/sysbios/hal/Hwi.h>

#include <ti/board/board.h>

/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/UART_stdio.h>

extern char *LocalIPAddr;

/* Enable the below macro to have prints on the IO Console */
//#define IO_CONSOLE

#ifndef IO_CONSOLE
#define NIMU_log                UART_printf
#else
#define NIMU_log                printf
#endif

/* ========================================================================== */
/*                             Macros                                  */
/* ========================================================================== */

/**Phy address of the CPSW port 1*/
#define EMAC_CPSW_PORT0_PHY_ADDR_SK 4
/**Phy address of the CPSW port 2*/
#define EMAC_CPSW_PORT1_PHY_ADDR_SK 5

#define MAX_TABLE_ENTRIES   3

#define REMOTE_IP_ADDRESS              "193.100.100.251"

#define FG_BASE_ADDRESS                0x80000000

#define MAX_BLOCK_SIZE                 65464

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/**Task handle for EIP*/
Task_Handle main_task;

static int nimu_device_index = 0U;


NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];

static void (*pfnFGAppEntry)();
void TaskFxn(UArg a0, UArg a1);
extern int CpswEmacInit (STKEVENT_Handle hEvent);

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

void CpswPortMacModeSelect(uint32_t portNum, uint32_t macMode)
{
    uint32_t regVal = 0U;

    regVal = HW_RD_REG32(SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL);

    switch(macMode)
    {
        case ETHERNET_MAC_TYPE_MII:
        case ETHERNET_MAC_TYPE_GMII:
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

        case ETHERNET_MAC_TYPE_RMII: /* RMII */
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 1U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 1U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

        case ETHERNET_MAC_TYPE_RGMII: /* RGMII */
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 2U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 2U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

         default:
         break;
    }

    HW_WR_REG32((SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL), regVal);
}


#define SYS_MMU_BUFFERABLE      1
#define SYS_MMU_CACHEABLE       2
#define SYS_MMU_SHAREABLE       4
#define SYS_MMU_NO_EXECUTE      8
typedef struct _sys_mmu_entry
{

    void* address;
    /**< Address to be entered in MMU table. */
    unsigned int attributes;
    /**< Attributes of the memory. */
}SYS_MMU_ENTRY;


SYS_MMU_ENTRY applMmuEntries[] = {
    {(void*)0x30000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x40300000,0},  //OCMCRAM  - Cacheable
    {(void*)0x44D00000, SYS_MMU_BUFFERABLE},  //PRCM - Non bufferable| Non Cacheable
    {(void*)0x44E00000, SYS_MMU_BUFFERABLE},  //Clock Module, PRM, GPIO0, UART0, I2C0, - Non bufferable| Non Cacheable
    {(void*)0x47900000,SYS_MMU_BUFFERABLE},  //QSPI MMR Maddr0space
    {(void*)0x48000000, SYS_MMU_BUFFERABLE},  //UART1,UART2,I2C1,McSPI0,McASP0 CFG,McASP1 CFG,DMTIMER,GPIO1 -Non bufferable| Non Cacheable
    {(void*)0x48100000,0},  //I2C2,McSPI1,UART3,UART4,UART5, GPIO2,GPIO3,MMC1 - Non bufferable| Non Cacheable
    {(void*)0x48200000, SYS_MMU_BUFFERABLE},  //
    {(void*)0x48300000, SYS_MMU_BUFFERABLE},  //PWM - Non bufferable| Non Cacheable
    {(void*)0x49000000, SYS_MMU_BUFFERABLE},   //EDMA3CC - Non bufferable| Non Cacheable
    {(void*)0x4A000000, SYS_MMU_BUFFERABLE},  //L4 FAST CFG- Non bufferable| Non Cacheable
    {(void*)0x4A100000, SYS_MMU_BUFFERABLE},  //CPSW - Non bufferable| Non Cacheable
    {(void*)0x54400000, SYS_MMU_BUFFERABLE},  //PRU-ICSS0/1 -Bufferable| Non Cacheable | Shareable
    //{(void*)0x90000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Non bufferable| Non Cacheable
    {(void*)0x80000000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x80100000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x80200000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90000000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90100000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90200000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0xFFFFFFFF,0xFFFFFFFF}
};
int SDKMMUInit(SYS_MMU_ENTRY mmuEntries[])
{
    unsigned short itr = 0;
    Mmu_FirstLevelDescAttrs attrs;

    if(NULL == mmuEntries)
        return -1;

    Mmu_disable();

    Mmu_initDescAttrs(&attrs);

    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.domain = 0;
    attrs.imp = 1;
    attrs.accPerm = 3;


    for(itr = 0 ; mmuEntries[itr].address != (void*)0xFFFFFFFF ; itr++)
    {
        attrs.bufferable = ((mmuEntries[itr].attributes) & SYS_MMU_BUFFERABLE) && 1 ;
        attrs.cacheable  = ((mmuEntries[itr].attributes) & SYS_MMU_CACHEABLE) && 1;
        if (!attrs.bufferable && !attrs.cacheable)
            attrs.tex = 0; //tex is initialized to 1 and need this to force strongly ordered
        attrs.shareable  = ((mmuEntries[itr].attributes) & SYS_MMU_SHAREABLE) && 1;
        attrs.noexecute  = ((mmuEntries[itr].attributes) & SYS_MMU_NO_EXECUTE) && 1;
        Mmu_setFirstLevelDesc((Ptr)(mmuEntries[itr].address), (Ptr)(mmuEntries[itr].address) , &attrs);  // PWM
    }
    Mmu_enable();
    return 0;
}

/**
 *  \name main
 *  \brief Main Function
 *  \param none
 *  \return none
 *
 */
int main()
{
    /* Call board init functions */
    Board_initCfg boardCfg;
    Task_Params taskParams;
    EMAC_HwAttrs_V4 cfg;

    SDKMMUInit(applMmuEntries);

    boardCfg = BOARD_INIT_PINMUX_CONFIG |
        BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(boardCfg);

    /* Chip configuration MII/RMII selection */
    CpswPortMacModeSelect(1, ETHERNET_MAC_TYPE_RGMII);
    CpswPortMacModeSelect(2, ETHERNET_MAC_TYPE_RGMII);



    EMAC_socGetInitCfg(0, &cfg);
    cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
    cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
    EMAC_socSetInitCfg(0, &cfg);

    Task_Params_init(&taskParams);
    taskParams.priority = 1;
    taskParams.stackSize = 0x1400;
    main_task = Task_create (TaskFxn, &taskParams, NULL);

    NIMUDeviceTable[nimu_device_index++].init =  &CpswEmacInit ;
    NIMUDeviceTable[nimu_device_index].init =  NULL ;

    BIOS_start();

    return -1;
}

static void jumpStackPointer(uint32_t address)
{
    pfnFGAppEntry = (void (*)(void)) address;

    //Hwi_disable();
    //Mmu_disable();
    (*pfnFGAppEntry)( );
    /*__asm(" mov sp, r0\n"   // sp is now *address
          " bx r0\n" );     // jump to *address */
}

void jumpToApplication(UArg a0, UArg a1)
{
    /*
     * Disable interrupts
     */
    NIMU_log ("All interrupts are disabled\n");
    char *p = (char *)(FG_BASE_ADDRESS);
    NIMU_log("jump context = 0x%08X\n", *(unsigned int *)p);
	
    NIMU_log("Jumping... \n");
    jumpStackPointer(FG_BASE_ADDRESS);
}

/**
 *  \name TaskFxn
 *  \brief Task which do EIP initialization
 *  \param a0
 *  \param a1
 *  \return none
 *
 */
void TaskFxn(UArg a0, UArg a1)
{
    CI_IPNET    NA;
    char IPString[16];
    char *pBuf = (char *)FG_BASE_ADDRESS;
    int firmlen, res;
    uint16_t errcode;

    /* Allocate the file environment for this task */
    fdOpenSession( TaskSelf() );

    if (CfgGetImmediate( 0, CFGTAG_IPNET, 0, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA)) {
        /* Yes the device was configured and we got the IP address/Mask */
        NtIPN2Str (NA.IPAddr, IPString);
        NIMU_log ("IP Address    : %s\n", IPString);
        NtIPN2Str (NA.IPMask, IPString);
        NIMU_log ("IP Mask       : %s\n", IPString);
    }

    /* Wait for the link to come up */
    Task_sleep(10000);

    while (1) {
        firmlen = MAX_BLOCK_SIZE;

        res = NtTftpRecv(inet_addr(REMOTE_IP_ADDRESS), "FGBoardProto.bin", pBuf, (UINT32 *)&firmlen, &errcode);
        if (res == 0 || res == 1) {
            NIMU_log ("Firmware file found with len %d, res is %d\n", firmlen, res);
            break;
        } else {
            NIMU_log ("Error (%d/%d) fetching firmware\n", res, (int)errcode);
        }
    }

    NIMU_log ("Firmware download is complete. Jumping to FW\n");
    {
        Task_Params taskParams;
        EMAC_HwAttrs_V4 cfg;
        EMAC_socGetInitCfg(0, &cfg);
        cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
        cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
        EMAC_socSetInitCfg(0, &cfg);

        Task_Params_init(&taskParams);
        taskParams.priority = 1;
        taskParams.stackSize = 0x1400;
        main_task = Task_create(jumpToApplication, &taskParams, NULL);
    }

    fdCloseSession( TaskSelf() );

    TaskDestroy( TaskSelf() );
}

// handle exceptions
void BL_Exception(uint32_t *stack, uint32_t lr)
{
    NIMU_log("Exception occurred \n");
}

/*
 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  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 Files                                  */
/* ========================================================================== */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/a8/Mmu.h>

#include <ti/ndk/inc/stkmain.h>
#include <ti/ndk/inc/netmain.h>

#include <ti/drv/emac/emac_drv.h>
#include <ti/drv/emac/src/v4/emac_drv_v4.h>

#include <ti/starterware/include/types.h>
#include <ti/starterware/include/hw/hw_types.h>
#include <ti/starterware/include/hw/hw_control_am43xx.h>
#include <ti/starterware/include/hw/am437x.h>
#include <ti/starterware/include/ethernet.h>

#include <ti/sysbios/hal/Hwi.h>

#include <ti/board/board.h>

/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/UART_stdio.h>

extern char *LocalIPAddr;

/* Enable the below macro to have prints on the IO Console */
//#define IO_CONSOLE

#ifndef IO_CONSOLE
#define NIMU_log                UART_printf
#else
#define NIMU_log                printf
#endif

/* ========================================================================== */
/*                             Macros                                  */
/* ========================================================================== */

/**Phy address of the CPSW port 1*/
#define EMAC_CPSW_PORT0_PHY_ADDR_SK 4
/**Phy address of the CPSW port 2*/
#define EMAC_CPSW_PORT1_PHY_ADDR_SK 5

#define MAX_TABLE_ENTRIES   3

#define REMOTE_IP_ADDRESS              "193.100.100.251"

#define FG_BASE_ADDRESS                0x80000000

#define MAX_BLOCK_SIZE                 65464

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/**Task handle for EIP*/
Task_Handle main_task;

static int nimu_device_index = 0U;


NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];

static void (*pfnFGAppEntry)();
void TaskFxn(UArg a0, UArg a1);
extern int CpswEmacInit (STKEVENT_Handle hEvent);

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

void CpswPortMacModeSelect(uint32_t portNum, uint32_t macMode)
{
    uint32_t regVal = 0U;

    regVal = HW_RD_REG32(SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL);

    switch(macMode)
    {
        case ETHERNET_MAC_TYPE_MII:
        case ETHERNET_MAC_TYPE_GMII:
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

        case ETHERNET_MAC_TYPE_RMII: /* RMII */
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 1U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 1U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

        case ETHERNET_MAC_TYPE_RGMII: /* RGMII */
            if(1U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 2U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
            }
            else if(2U == portNum)
            {
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 2U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
            }
            else
            {
                /* This error does not happen because of check done already */
            }
            break;

         default:
         break;
    }

    HW_WR_REG32((SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL), regVal);
}


#define SYS_MMU_BUFFERABLE      1
#define SYS_MMU_CACHEABLE       2
#define SYS_MMU_SHAREABLE       4
#define SYS_MMU_NO_EXECUTE      8
typedef struct _sys_mmu_entry
{

    void* address;
    /**< Address to be entered in MMU table. */
    unsigned int attributes;
    /**< Attributes of the memory. */
}SYS_MMU_ENTRY;


SYS_MMU_ENTRY applMmuEntries[] = {
    {(void*)0x30000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x30300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    {(void*)0x40300000,0},  //OCMCRAM  - Cacheable
    {(void*)0x44D00000, SYS_MMU_BUFFERABLE},  //PRCM - Non bufferable| Non Cacheable
    {(void*)0x44E00000, SYS_MMU_BUFFERABLE},  //Clock Module, PRM, GPIO0, UART0, I2C0, - Non bufferable| Non Cacheable
    {(void*)0x47900000,SYS_MMU_BUFFERABLE},  //QSPI MMR Maddr0space
    {(void*)0x48000000, SYS_MMU_BUFFERABLE},  //UART1,UART2,I2C1,McSPI0,McASP0 CFG,McASP1 CFG,DMTIMER,GPIO1 -Non bufferable| Non Cacheable
    {(void*)0x48100000,0},  //I2C2,McSPI1,UART3,UART4,UART5, GPIO2,GPIO3,MMC1 - Non bufferable| Non Cacheable
    {(void*)0x48200000, SYS_MMU_BUFFERABLE},  //
    {(void*)0x48300000, SYS_MMU_BUFFERABLE},  //PWM - Non bufferable| Non Cacheable
    {(void*)0x49000000, SYS_MMU_BUFFERABLE},   //EDMA3CC - Non bufferable| Non Cacheable
    {(void*)0x4A000000, SYS_MMU_BUFFERABLE},  //L4 FAST CFG- Non bufferable| Non Cacheable
    {(void*)0x4A100000, SYS_MMU_BUFFERABLE},  //CPSW - Non bufferable| Non Cacheable
    {(void*)0x54400000, SYS_MMU_BUFFERABLE},  //PRU-ICSS0/1 -Bufferable| Non Cacheable | Shareable
    //{(void*)0x90000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Non bufferable| Non Cacheable
    {(void*)0x80000000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x80100000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x80200000, SYS_MMU_SHAREABLE | SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90000000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90100000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0x90200000, SYS_MMU_CACHEABLE},  //App memory
    {(void*)0xFFFFFFFF,0xFFFFFFFF}
};
int SDKMMUInit(SYS_MMU_ENTRY mmuEntries[])
{
    unsigned short itr = 0;
    Mmu_FirstLevelDescAttrs attrs;

    if(NULL == mmuEntries)
        return -1;

    Mmu_disable();

    Mmu_initDescAttrs(&attrs);

    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.domain = 0;
    attrs.imp = 1;
    attrs.accPerm = 3;


    for(itr = 0 ; mmuEntries[itr].address != (void*)0xFFFFFFFF ; itr++)
    {
        attrs.bufferable = ((mmuEntries[itr].attributes) & SYS_MMU_BUFFERABLE) && 1 ;
        attrs.cacheable  = ((mmuEntries[itr].attributes) & SYS_MMU_CACHEABLE) && 1;
        if (!attrs.bufferable && !attrs.cacheable)
            attrs.tex = 0; //tex is initialized to 1 and need this to force strongly ordered
        attrs.shareable  = ((mmuEntries[itr].attributes) & SYS_MMU_SHAREABLE) && 1;
        attrs.noexecute  = ((mmuEntries[itr].attributes) & SYS_MMU_NO_EXECUTE) && 1;
        Mmu_setFirstLevelDesc((Ptr)(mmuEntries[itr].address), (Ptr)(mmuEntries[itr].address) , &attrs);  // PWM
    }
    Mmu_enable();
    return 0;
}

/**
 *  \name main
 *  \brief Main Function
 *  \param none
 *  \return none
 *
 */
int main()
{
    /* Call board init functions */
    Board_initCfg boardCfg;
    Task_Params taskParams;
    EMAC_HwAttrs_V4 cfg;

    SDKMMUInit(applMmuEntries);

    boardCfg = BOARD_INIT_PINMUX_CONFIG |
        BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(boardCfg);

    /* Chip configuration MII/RMII selection */
    CpswPortMacModeSelect(1, ETHERNET_MAC_TYPE_RGMII);
    CpswPortMacModeSelect(2, ETHERNET_MAC_TYPE_RGMII);



    EMAC_socGetInitCfg(0, &cfg);
    cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
    cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
    EMAC_socSetInitCfg(0, &cfg);

    Task_Params_init(&taskParams);
    taskParams.priority = 1;
    taskParams.stackSize = 0x1400;
    main_task = Task_create (TaskFxn, &taskParams, NULL);

    NIMUDeviceTable[nimu_device_index++].init =  &CpswEmacInit ;
    NIMUDeviceTable[nimu_device_index].init =  NULL ;

    BIOS_start();

    return -1;
}

static void jumpStackPointer(uint32_t address)
{
    pfnFGAppEntry = (void (*)(void)) address;

    //Hwi_disable();
    //Mmu_disable();
    (*pfnFGAppEntry)( );
    /*__asm(" mov sp, r0\n"   // sp is now *address
          " bx r0\n" );     // jump to *address */
}

void jumpToApplication(UArg a0, UArg a1)
{
    /*
     * Disable interrupts
     */
    NIMU_log ("All interrupts are disabled\n");
    char *p = (char *)(FG_BASE_ADDRESS);
    NIMU_log("jump context = 0x%08X\n", *(unsigned int *)p);
	
    NIMU_log("Jumping... \n");
    jumpStackPointer(FG_BASE_ADDRESS);
}

/**
 *  \name TaskFxn
 *  \brief Task which do EIP initialization
 *  \param a0
 *  \param a1
 *  \return none
 *
 */
void TaskFxn(UArg a0, UArg a1)
{
    CI_IPNET    NA;
    char IPString[16];
    char *pBuf = (char *)FG_BASE_ADDRESS;
    int firmlen, res;
    uint16_t errcode;

    /* Allocate the file environment for this task */
    fdOpenSession( TaskSelf() );

    if (CfgGetImmediate( 0, CFGTAG_IPNET, 0, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA)) {
        /* Yes the device was configured and we got the IP address/Mask */
        NtIPN2Str (NA.IPAddr, IPString);
        NIMU_log ("IP Address    : %s\n", IPString);
        NtIPN2Str (NA.IPMask, IPString);
        NIMU_log ("IP Mask       : %s\n", IPString);
    }

    /* Wait for the link to come up */
    Task_sleep(10000);

    while (1) {
        firmlen = MAX_BLOCK_SIZE;

        res = NtTftpRecv(inet_addr(REMOTE_IP_ADDRESS), "FGBoardProto.bin", pBuf, (UINT32 *)&firmlen, &errcode);
        if (res == 0 || res == 1) {
            NIMU_log ("Firmware file found with len %d, res is %d\n", firmlen, res);
            break;
        } else {
            NIMU_log ("Error (%d/%d) fetching firmware\n", res, (int)errcode);
        }
    }

    NIMU_log ("Firmware download is complete. Jumping to FW\n");
    {
        Task_Params taskParams;
        EMAC_HwAttrs_V4 cfg;
        EMAC_socGetInitCfg(0, &cfg);
        cfg.port[0].phy_addr = EMAC_CPSW_PORT0_PHY_ADDR_SK;
        cfg.port[1].phy_addr = EMAC_CPSW_PORT1_PHY_ADDR_SK;
        EMAC_socSetInitCfg(0, &cfg);

        Task_Params_init(&taskParams);
        taskParams.priority = 1;
        taskParams.stackSize = 0x1400;
        main_task = Task_create(jumpToApplication, &taskParams, NULL);
    }

    fdCloseSession( TaskSelf() );

    TaskDestroy( TaskSelf() );
}

// handle exceptions
void BL_Exception(uint32_t *stack, uint32_t lr)
{
    NIMU_log("Exception occurred \n");
}


I as I jump into the application - it receives an exception and doesn't gets inside application's main. 

UART output is:

SetPhyMode:000021e1 Auto:1, FD10:64, HD10:32, FD100:256, HD100:128, FD1000:8192 LPBK:0
ENETPHY_FindingState: PhyNum: 4
ENETPHY_DisablePhy(4)
Enable Phy to negotiate external connection
NWAY Advertising: FullDuplex-1000 FullDuplex-100 HalfDuplex-100 FullDuplex-10 HalfDuplex-10
Negotiated connection: FullDuplex 1000 Mbs
Firmware file found with len 1113309, res is 0
Firmware download is complete. Jumping to FW
All interrupts are disabled
jump context = 0xe59ff018
Jumping...
Exception occurred

What is missing in my solution?

  • The RTOS team have been notified. They will respond here.
  • Ithamar,

    Are you using bootloader from Processor SDK RTOS or is this your custom bootloader. If you check the boot flow, you will notice that secondary bootloader on this device is responsible for initializing DDR so I am not sure how you are running bootloader from 0x90000000. The bootloader needs to always run from OCMC RAM or onchip RAM. I am assuming this booting mechanism is working when you load over JTAG And only fails during booting from flash, is that correct?

    If your modified secondary bootloader doesn`t fit inside OCMC memory then the suggestion would be to have the Processor SDK RTOS bootloader to load your bootloader into 0x9000_0000 which in turn would load your application. At the moment, since the code is booting into your bootloader, can you step through the code and try to capture at what stage the exception occurs. The other way to debug this would be set a while loop (with a volatile variable) right after the bootloader jumps your application and connect using JTAG and see if BIOS provides any register dump when the exception occurs.

    Regards,
    Rahul
  • Hi Rahul,

    We did this custom boot loader as TI-RTOS does not support boot from network. The boot loader image is too big, and this is why we ALREADY put the boot loader image in base address  0x90000000. We already tracked with debugger the boot loader and we found out that the exception of 0x20023 (Undefined exception by ARM Cortex A9) when jumping into the FW image we loaded (to 0x80000000).We mentioned it while opening the ticket. 

    Question: Is there any standard boot loader that can load TI RTOS from network? We know Linux has it but we haven't found anything for TI RTOS.

  • This is not a typical usecase for TI RTOS so we don`t provide this as part of our Processor SDK RTOS offering. I have indicated RTOS SBL or Linux SPL is loaded into memory by ROM bootloader that is pre-programmed in the L2ROM on the device. ROM bootloader doesn`t load code into DDR memory, it can only load code into on chip memory.

    So if you have determined that adding network stack to bootlader is increasing the size of the image to be more than OCMC RAM, then you need to break the booting to have mutli-stage boot.
    1. RBL loads minimal SBL into OCMC ram which sets up OPP, DDR, pinmux, etc and copies second stage into DDR.
    2. Second stage SBL will setup network stack and setup booting application over the network.
    3. Application is loaded into rest of DDR and control is passed to the application.

    Given that ROM bootloader and the secondary bootloader restrictions, this is the only way I can see to proceed with this system boot, unless you want to spend the time to optimize the code size of the SBL+network boot image to fit inside OCMC RAM. there are several things to optimize the TI SBL as has been described in section 2.3.1 of the DDRless EtherCAT TI Design :
    www.ti.com/.../tidue46.pdf


    Regards,
    Rahul
  • Dear Rahul,

    Thank you for your reply. Indeed a network enabled bootloader that fits into internal ram can be great, but we are not there yet. What we did is rather simple. Instead of writing a new boot loader, we take into advantage that we have an sd card. Inside the SD card, we have the standard RTOS MLO bootloader and our "so called" secondary bootloader as a DDR app. This app is a simple full blown NDK core app, that the only thing it does is reading the main app using tftp from the network, then it passes control to the main app.
    Since the main app is compiled to work on the standard memory space starting at 0x80000000, the bootloader app is compiled to work on address space starting from 0x90000000, so it can load the main app to 0x80000000.
    The entire process is rather simple and everything works fine right until we pass control to the main app where it seems nothing works. We either get exceptions or just get stuck somewhere along the way.
    Our question is what we need to do before passing control to the main app? Currently we just simply jump to address 0x80000000.
    Do we need to turn interrupts off before jumping? Do we need to disable MMU somehow (MMU is on because the "bootloader" is, as said, a full NDK/RTOS app) - we tried both options, and both immediately crashed the SW even before jumping.
    Are there any registers we need to reset first before jumping? anything else we need to do to cleanup everything before jumping?

    Thanks,
    Ithamar
  • Ithamar,

    There is no additional configuration required before passing control to the main app.  We have all the NDK examples booting and running from bootloader without any issues so I don`t beleive there is any thing in addition to loading and running the sections into DDR that you need to do.

    You indicated everything works fine until the control is passed to main app.  so let me try and understand that setup a little better. The MLO loads the DDR app as a contiguous binary by reading the header appended to the binary.  The first two words of the TI image format contains the load address and size of the binary to load. Can you open your app (which does network boot) and conform that the load address 0x90000000? Can you confirm that when you used  TIIMAGE utility to process your image, you use the IMG_LOAD_ADDR as 0x90000000.

    you can also step through the bootloader code on AM437x and check to confirm that the load address is 0x90000000.  Also, in your NDK application. can you check to see if the entry symbol is set to 0x90000000. the process that describes chnaging the entry address in SYSBIOS projects is described here for Cortex A platforms.

    Have you debugged the network loader application over JTAG and confirmed that you don`t have these issues when loaded over emulator?

    One issue that I suspect, that may be causing this issue is that ARM MMU is configured by SYSBIOS before you enter the app main and currently, I see that BIOS default platform definition defined as follows:

    override readonly config xdc.platform.IPlatform.Memory
            externalMemoryMap[string] = [
                ["EXT_RAM", {
                    comment: "External RAM",
                    name: "EXT_RAM",
                    base: 0x80000000,
                    len:  0x08000000    /* 128 MB */
                }],
            ];

    After you have loaded the app and the bootloader passes control can you go to ROV view/open XGCONF tool and check the MMU module to see if the page tables for that region have been setup ?

    Regards,

    Rahul

  • Hi Rahul,

    Thank you for your reply.

    My name is Shai and I work with Ithamar on the AM437x project.

    The NDK APP that is loaded into 0x90000000 from the SD is working correctly, we have no issue with that. After it loads, It reads ANOTHER NDK app (main)  using tftp boot into the standard location 0x80000000, then it perform a jump to the new entry point (0x80000000) and this is where it fails.

    Here is the way it is done:

    pBuf = (char *)0x80000000
    NtTftpRecv(inet_addr(REMOTE_IP_ADDRESS), "FGBoardProto.bin", pBuf, (UINT32 *)&firmlen, &errcode); // read main NDK app into 0x80000000
    pfnFGAppEntry = (void (*)(void)) 0x8000000;  // prepare to jump to entry point
    (*pfnFGAppEntry)( ); // jump to new entry point --- fails

    I'm almost sure there must be some cleanup to be done before a TI BIOS app can start a new TI BIOS app, but I dont know what do I need to do.

    I even tried to simplify the problem:

    Suppose I have a standard NDK app running at standard location 0x80000000, and for some reason I want to restart the App. Performing a simple jump to the entry point of the app (jump to 0x80000000) does not work, it will also crash. What is needed to be done if I want and app to restart itself by re-jumping to the entry point? I even tried exiting the bios (BIOS_exit()) and try to jump from the exit function to the entry point, same thing, the app crashes.

    shai

  • Shai,

    I noticed a small bug in the code that you posted.  the entry point has a zero missing in the end. Is that a typo  or just a copy paste error. ?

    pfnFGAppEntry = (void (*)(void)) 0x80000000;  // prepare to jump to entry point

    I think now I understand the issue a little better. I was assuming your network bootloader had bare-metal setup and not TI RTOS NDK setup. This definitely might be causing issues. You can also experience this in CCS when you try to reload new SYSBIOS code on the A9 without doing a system reset. I think the BIOS exit will close the BIOS services but will not clean the cache and MMU states on the ARM core. I need to check internally if we have any BIOS clean up code to allow for reloading of the A9 app. 

    Regards,

    Rahul

  • Dear Rahul,

    Thank you for your fast reply. Yes it is a copy paste typo, we actually use #define for that, I just wanted it to be simple.
    You are correct, this is not a bare bone bootloader as we wanted a quick solution and not dive into the low level.
    As I tried for simplification to restart the same app (by a jump to start) and it did not work, I came across this thread: e2e.ti.com/.../539636 , where it discuss the issue of not being able to restart SYSBIOS code in the debugger (same issue you mentioned). It turns out the startup code does not do a proper cleanup after reload. They included a patch to _startup.c that solves this issue, and interestingly, not only it solved the the code reload in the debugger, it also solved the "jump to start" of the code!
    I really hoped it will also solve the "jump from one SYSBIOS code to another" but it did not. It still throws an exception somewhere after the main of the new app starts (looks like in the first create_task call but not sure - debug symbols are not available when I just load a bin file from tftp)
    So I guess, there are some other things need to be init or cleared to work correctly.
    Hope this info helps,

    shai
  • Hi Rahul.

    I realize that the FW we were trying to upload had stack overflow exception happening often and occured every time we tried to jump into FW's address (i.e. 0x8000_0000) we were getting hit by exception of 0x20023 (Application Termination exception). Once I resloved the stack overflow - I was managed to jump into FW, see that it runs its main() and all the functions called by it including BiosInit()

    I was able to see UART printing, so this exception was actually the problem

    I'm closing the ticket.

    Ithamar