You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1138 lines
29 KiB

/* vim: set ts=4 sw=4 et fdm=marker: */
/* sysLib.c - system-dependent routines */
/*
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/* includes */
#include <vxWorks.h>
#include <vsbConfig.h>
#include "config.h"
#if defined(INCLUDE_IPFTPS)
#include <ipcom_sysvar.h>
#endif
#define INCLUDE_MMU
#include <sysLib.h>
#include <string.h>
#include <intLib.h>
#include <taskLib.h>
#include <vxLib.h>
#include <muxLib.h>
#include <cacheLib.h>
#ifdef INCLUDE_MMU
#include <arch/arm/mmuArmLib.h>
#include <private/vmLibP.h>
#endif /* INCLUDE_MMU */
#include <dllLib.h>
#ifdef INCLUDE_VXIPI
#include <vxIpiLib.h>
#endif /* INCLUDE_VXIPI */
#ifdef _WRS_CONFIG_SMP
#include <arch/arm/vxAtomicArchLib.h>
#include <vxbTimerLib.h>
#endif /* _WRS_CONFIG_SMP */
#include <ioLib.h>
#include <stdio.h>
#include <logLib.h>
#include <ffsLib.h>
LOCAL UINT32 sysSdhcClkFreqGet(void);
LOCAL void sysGmacAddrSet(UINT8 *);
#ifdef INCLUDE_VXBUS
#include "vxbArmGenIntCtlrV3.h"
#include <hwif/vxbus/vxBus.h>
#include "hwconf.c"
#include "ft2000-4.h"
IMPORT void hardWareInterFaceInit(void);
#ifdef INCLUDE_SIO_UTILS
IMPORT void sysSerialConnectAll(void);
#endif /* INCLUDE_SIO_UTILS */
#endif /* INCLUDE_VXBUS */
#ifdef INCLUDE_PCI_BUS /* BSP PCI bus & config support */
#include <drv/pci/pciConfigLib.h>
#include <drv/pci/pciIntLib.h>
#include <drv/pci/pciAutoConfigLib.h>
/* 24-bit PCI network class ethernet subclass and prog. I/F code */
#include "pciCfgIntStub.c"
#endif /* INCLUDE_PCI_BUS */
#if defined(INCLUDE_PC_CONSOLE) || defined(INCLUDE_WINDML)
#include "vxbM6845Vga.c" /* X100 VGA */
#endif
typedef struct arm_smc_regs {
int a0;
int a1;
int a2;
int a3;
int a4;
int a5;
int a6;
int a7;
} ARM_SMC_REGS;
#ifdef _WRS_CONFIG_SMP
/* constant used with IPI to request reboot of application processors */
#define APPCORE_REBOOT 0xFEFEFEF0
LOCAL UINT32 rebootVar = 0; /* it passes the CPU index */
/* it protect from multiple reboots */
LOCAL SPIN_LOCK_ISR_DECL(rebootLock, 0);
/* Non-Boot CPU Start info. Managed by sysCpuEnable */
typedef struct sysMPCoreStartup_s {
UINT32 newPC; /* Address of 'C' based startup code */
UINT32 newSP; /* Stack pointer for startup */
UINT32 newArg; /* vxWorks kernel entry point */
#ifndef _WRS_CONFIG_ARM_LPAE
UINT32 newSync; /* Translation Table Base and sync */
#else /* _WRS_CONFIG_ARM_LPAE */
UINT32 ttbcr; /* Translation Table Base Control Register */
UINT64 newSync; /* 64 bits Translation Table Base and sync */
#endif /* !_WRS_CONFIG_ARM_LPAE */
} sysMPCoreStartup_t;
extern sysMPCoreStartup_t sysMPCoreStartup[VX_SMP_NUM_CPUS];
extern unsigned int arm_mmu_ttbr;
IMPORT void sysInit(void);
IMPORT void sysInit32(void);
IMPORT void mmuCortexA8DacrSet(UINT32 dacrVal);
IMPORT STATUS sysArmGicDevInit(void);
IMPORT void mmuCortexA8AEnable(UINT32 cacheState);
IMPORT void mmuCortexA8ADisable(void);
IMPORT void armInitExceptionModes(void);
IMPORT void sysCpuInit(void);
IMPORT void cacheCortexA9MPCoreSMPInit(void);
IMPORT void mmuCortexA8TLBIDFlushAll(void);
IMPORT MMU_LEVEL_1_DESC *mmuCortexA8TtbrGet(void);
UINT32 sysCpuAvailableGet(void);
STATUS sysCpuEnable(unsigned int, void (*startFunc)(void), char *);
void sysUsDelay(int us);
#endif /* _WRS_CONFIG_SMP */
int uartf(const char *fmt, /* format string */... /* optional arguments to format */);
/* {{{ XXX: added */
IMPORT void bspPinMuxInitialize(void);
IMPORT void bspDriverRegiser(void);
/* }}} */
/* imports */
IMPORT char end[]; /* end of system, created by ld */
#ifndef _ARCH_SUPPORTS_PROTECT_INTERRUPT_STACK
IMPORT VOIDFUNCPTR _func_armIntStackSplit; /* ptr to fn to split stack */
#endif /* !_ARCH_SUPPORTS_PROTECT_INTERRUPT_STACK */
/* globals */
#if defined(INCLUDE_MMU)
/* general parameters*/
#define MMU_PAGE_SIZE 4096
#define MMU_PAGE_SIZE_SHIFT 12
#define PAGE_SIZE MMU_PAGE_SIZE
/*
* The following structure describes the various different parts of the
* memory map to be used only during initialization by
* vm(Base)GlobalMapInit() when INCLUDE_MMU_BASIC/FULL/GLOBAL_MAP are
* defined.
*
* Clearly, this structure is only needed if the CPU has an MMU!
*
* The following are not the smallest areas that could be allocated for a
* working system. If the amount of memory used by the page tables is
* critical, they could be reduced.
*/
PHYS_MEM_DESC sysPhysMemDesc[] = {
{ LOCAL_MEM_LOCAL_ADRS, /* virtual address */
LOCAL_MEM_LOCAL_ADRS, /* physical address */
LOCAL_MEM_SIZE, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_WRITEALLOCATE_MSK,
#if defined(_WRS_CONFIG_SMP) /* needs to be shared */
MMU_ATTR_VALID | MMU_ATTR_SUP_RWX | MMU_ATTR_WRITEALLOCATE_SHARED
#else
MMU_ATTR_VALID | MMU_ATTR_SUP_RWX | MMU_ATTR_WRITEALLOCATE
#endif /* _WRS_CONFIG_SMP */
},
{ PIN_DEMUX_BASE, /* pin MUX/DEMUX */
PIN_DEMUX_BASE, 0x10000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ UART_0_BASE_ADR, /* UART */
UART_0_BASE_ADR, 0x18000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ 0x28207000, /* CAN*/
0x28207000, 0x1000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ 0x2820b000, /* GMAC*/
0x2820b000, 0x00009000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ 0x29900000, /* GIC */
0x29900000, 0x100000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ FT_PCI_CONFIG_ADDR, /* PCI Memory address spcae */
FT_PCI_CONFIG_ADDR, 0x10000000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ 0x50000000, /* PCI io32Addr */
0x50000000, 0x08000000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
{ 0x58000000, /* PCI mem32Addr */
0x58000000, 0x27000000, MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
#ifdef DRV_FTQSPI
{ /* Qspi BootRom */
SPI_FLASH_BASE_ADRS, SPI_FLASH_BASE_ADRS, QSPI_PROTECT_SIZE,
MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RO | MMU_ATTR_DEVICE_SHARED },
{ /* Qspi Flash */
SPI_FLASH_BASE_ADRS + QSPI_PROTECT_SIZE, SPI_FLASH_BASE_ADRS + QSPI_PROTECT_SIZE, SPI_FLASH_SIZE - QSPI_PROTECT_SIZE,
MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
#endif
};
int sysPhysMemDescNumEnt = NELEMENTS(sysPhysMemDesc);
#endif /* defined(INCLUDE_MMU) */
int sysBus = BUS_TYPE_PCI; /* system bus type (VME_BUS, etc) */
int sysCpu = CPU; /* system CPU type (e.g. ARMARCH6) */
char *sysBootLine = BOOT_LINE_ADRS; /* address of boot line */
char *sysExcMsg = EXC_MSG_ADRS; /* catastrophic message area */
int sysProcNum; /* processor number of this CPU */
/* locals */
/* defines */
/* externals */
#ifndef _ARCH_SUPPORTS_PROTECT_INTERRUPT_STACK
IMPORT void sysIntStackSplit(char *, long);
#endif /* !_ARCH_SUPPORTS_PROTECT_INTERRUPT_STACK */
/* globals */
char *sysPhysMemTop(void);
/* included source files */
#include <mem/nullNvRam.c>
/*******************************************************************************
*
* sysModel - return the model name of the CPU board
*
* This routine returns the model name of the CPU board.
*
* RETURNS: A pointer to a string identifying the board and CPU.
*
* ERRNO
*/
char *sysModel(void)
{
return SYS_MODEL;
}
/*******************************************************************************
*
* sysBspRev - return the BSP version with the revision eg 1.2/<x>
*
* This function returns a pointer to a BSP version with the revision.
* e.g. 1.2/<x>. BSP_REV is concatenated to BSP_VERSION to form the
* BSP identification string.
*
* RETURNS: A pointer to the BSP version/revision string.
*
* ERRNO
*/
char *sysBspRev(void)
{
return (BSP_VERSION BSP_REV);
}
extern VIRT_ADDR mmuPhysToVirt(PHYS_ADDR physAddr /* physical address to be translated */
);
extern PHYS_ADDR mmuVirtToPhys(VIRT_ADDR virtAddr /* virtual address to be translated */
);
#ifndef _WRS_CONFIG_ARM_LPAE
extern void cacheCortexA9LibInstall(VIRT_ADDR(physToVirt)(PHYS_ADDR), PHYS_ADDR(virtToPhys)(VIRT_ADDR));
#else
extern void cacheCortexA15LibInstall(VIRT_ADDR(physToVirt)(PHYS_ADDR), PHYS_ADDR(virtToPhys)(VIRT_ADDR));
#endif
void writeq(int data, int addr)
{
*((volatile UINT32 *)addr) = (UINT32)data;
}
int readq(int addr)
{
return *((volatile UINT32 *)addr);
}
void v8_outer_disable_l3cache(void)
{
int i, pstate;
for (i = 0; i < 8; i++)
writeq(0x1, 0x3A200010 + i * 0x10000);
for (i = 0; i < 8; i++) {
do {
pstate = readq(0x3A200018 + i * 0x10000);
} while ((pstate & 0xf) != (0x1 << 2));
}
}
void v8_outer_cache_flush_all(void)
{
int i, pstate;
for (i = 0; i < 8; i++)
writeq(0x1, 0x3A200010 + i * 0x10000);
for (i = 0; i < 8; i++) {
do {
pstate = readq(0x3A200018 + i * 0x10000);
} while ((pstate & 0xf) != (0x1 << 2));
}
for (i = 0; i < 8; i++)
writeq(0x3, 0x3A200010 + i * 0x10000);
}
void sysHwInit0(void)
{
/*v8_outer_cache_flush_all();*/
excVecBaseSet(LOCAL_MEM_LOCAL_ADRS);
#ifdef INCLUDE_CACHE_SUPPORT
#ifndef _WRS_CONFIG_ARM_LPAE
cacheCortexA9LibInstall(mmuPhysToVirt, mmuVirtToPhys);
#else
cacheCortexA15LibInstall(mmuPhysToVirt, mmuVirtToPhys);
#endif
#endif
mmuCortexA8LibInstall(mmuPhysToVirt, mmuVirtToPhys);
}
#ifdef _WRS_CONFIG_SMP
/*******************************************************************************
*
* sysMsDelay - delay the specified amount of time (in milliseconds)
*
* This routine delays for approximately one millisecond. It just calls
* sysUsDelay to delay.
*
* RETURNS: N/A
*/
void sysMsDelay(UINT delay /* length of time in ms to delay */
)
{
sysUsDelay(1000 * delay);
}
/*******************************************************************************
*
* sysDelay - fixed 1ms delay.
*
* This routine consumes approximately 1ms of time. It just calls sysMsDelay.
*
* RETURNS: N/A
*/
void sysDelay(void)
{
sysMsDelay(1);
}
LOCAL UINT32 genTimerFreq = 0;
/*******************************************************************************
*
* armGenGetSysCount - get system counter count
*
* This routine gets the system counter count value.
*
* RETURNS: The count value.
*
* ERRNO: N/A
*/
LOCAL UINT64 armGenGetSysCount(void)
{
UINT64 count1;
_WRS_ASM("ISB");
count1 = __inline__GetPhyTimerCnt();
return count1;
}
/*******************************************************************************
*
* armGenGetFreq - get generic timer frequency
*
* This routine gets the generic timer frequency.
*
* RETURNS: The timer frequency.
*
* ERRNO: N/A
*/
#ifndef __DCC__
LOCAL void armGenGetFreq(void)
{
_WRS_ASM("MRC p15, 0, %0, c14, c0, 0" : "=r"(genTimerFreq));
}
#else
/* clang-format off */
__asm volatile UINT32 __macro__GetCntFreq (void)
{
! "r0"
mrc p15, 0, r0, c14, c0, 0
}
LOCAL UINT32 __inline__GetCntFreq (void)
{
return __macro__GetCntFreq();
}
/* clang-format on */
LOCAL UINT32 armGenGetFreq(void)
{
static UINT32 freq = 0;
freq = __inline__GetCntFreq();
genTimerFreq = freq; /* update global value. */
return freq;
}
#endif
/*******************************************************************************
*
* sysUsDelay - delay the specified amount of time (in microseconds)
*
* This routine delays for approximately the requested microseconds. The accuracy
* of the delay increases as the requested delay increases due to a certain
* amount of overhead.
*
* NOTE: This routine will not relinquish the CPU, as it is meant to perform a
* busy loop delay.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*\NOMANUAL
*/
void sysUsDelay(int us)
{
volatile UINT64 oldVal;
volatile UINT64 newVal;
volatile UINT64 incElapsed = 0;
volatile UINT64 totalDelta;
volatile UINT64 maxCount;
if (us <= 0) {
printf("usDelay, wrong parameter: %d us\n", us);
return;
}
totalDelta = (genTimerFreq * (UINT64)us + 1000000 - 1) / 1000000;
maxCount = 0xffffffffffffffffull;
oldVal = armGenGetSysCount();
while (incElapsed < totalDelta) {
newVal = armGenGetSysCount();
if (newVal == oldVal)
continue;
if (newVal > oldVal) {
incElapsed += (newVal - oldVal);
} else {
incElapsed += ((maxCount - oldVal) + newVal);
}
oldVal = newVal;
}
}
#endif /*_WRS_CONFIG_SMP*/
/*******************************************************************************
*
* sysHwInit - initialize the CPU board hardware
*
* This routine initializes various features of the hardware.
* Normally, it is called from usrInit() in usrConfig.c.
*
* NOTE: This routine should not be called directly by the user.
*
* RETURNS: N/A
*
* ERRNO
*/
extern void vxbftCanRegister(void);
#ifdef INCLUDE_DRV_STORAGE_NVME
extern void vxbNvmeStorageRegister(void);
#endif
#ifdef DRV_X100DC
extern void ftX100DcDevicePciRegister(void);
#endif
void sysHwInit(void)
{
uartf("...............................\r\n");
bspPinMuxInitialize();
#ifdef DRV_X100DC
ftX100DcDevicePciRegister();
#endif
bspDriverRegiser();
#ifdef INCLUDE_VXBUS
hardWareInterFaceInit();
#endif /* INCLUDE_VXBUS */
#ifdef DRV_PCIBUS_FT
ftPciRegister();
#endif
#ifdef INCLUDE_DRV_STORAGE_NVME
vxbNvmeStorageRegister();
#endif
#ifdef FORCE_DEFAULT_BOOT_LINE
strncpy(sysBootLine, DEFAULT_BOOT_LINE, strlen(DEFAULT_BOOT_LINE) + 1);
#endif /* FORCE_DEFAULT_BOOT_LINE */
#ifdef _WRS_CONFIG_SMP
_vxb_delayRtn = (void (*)())sysDelay;
_vxb_msDelayRtn = (void (*)(int))sysMsDelay;
_vxb_usDelayRtn = (void (*)(int))sysUsDelay;
armGenGetFreq();
#endif /*_WRS_CONFIG_SMP*/
}
/*******************************************************************************
*
* sysHwInit2 - additional system configuration and initialization
*
* This routine connects system interrupts and does any additional
* configuration necessary. Note that this is called from
* sysClkConnect() in the timer driver.
*
* RETURNS: N/A
*
* ERRNO
*/
void sysHwInit2(void)
{
static BOOL initialised = FALSE;
if (initialised) {
return;
}
#ifdef INCLUDE_VXBUS
vxbDevInit();
#ifdef INCLUDE_SIO_UTILS
sysSerialConnectAll();
#endif /* INCLUDE_SIO_UTILS */
taskSpawn("tDevConn", 11, 0, 10000, vxbDevConnect, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
#endif /* INCLUDE_VXBUS */
initialised = TRUE;
#if defined(INCLUDE_IPFTPS)
ipcom_sysvar_set("ipftps.root", TFFS_FLASH_MOUNT_POINTOT, IPCOM_SYSVAR_FLAG_OVERWRITE);
ipcom_sysvar_set("ipftps.dir", TFFS_FLASH_MOUNT_POINTOT, IPCOM_SYSVAR_FLAG_OVERWRITE);
#endif
}
/*******************************************************************************
*
* sysPhysMemTop - get the address of the top of physical memory
*
* This routine returns the address of the first missing byte of memory,
* which indicates the top of memory.
*
* Normally, the user specifies the amount of physical memory with the
* macro LOCAL_MEM_SIZE in config.h. BSPs that support run-time
* memory sizing do so only if the macro LOCAL_MEM_AUTOSIZE is defined.
* If not defined, then LOCAL_MEM_SIZE is assumed to be, and must be, the
* true size of physical memory.
*
* NOTE: Do no adjust LOCAL_MEM_SIZE to reserve memory for application
* use. See sysMemTop() for more information on reserving memory.
*
* RETURNS: The address of the top of physical memory.
*
* ERRNO
*
* SEE ALSO: sysMemTop()
*/
char *sysPhysMemTop(void)
{
static char *physTop = NULL;
if (physTop == NULL) {
physTop = (char *)(LOCAL_MEM_LOCAL_ADRS + LOCAL_MEM_SIZE);
}
return physTop;
}
/*******************************************************************************
*
* sysMemTop - get the address of the top of VxWorks memory
*
* This routine returns a pointer to the first byte of memory not
* controlled or used by VxWorks.
*
* The user can reserve memory space by defining the macro USER_RESERVED_MEM
* in config.h. This routine returns the address of the reserved memory
* area. The value of USER_RESERVED_MEM is in bytes.
*
* RETURNS: The address of the top of VxWorks memory.
*
* ERRNO
*/
char *sysMemTop(void)
{
static char *memTop = NULL;
#ifdef INCLUDE_EDR_PM
memTop = (char *)sysPhysMemTop() - USER_RESERVED_MEM - PM_RESERVED_MEM;
#else
memTop = (char *)sysPhysMemTop() - USER_RESERVED_MEM;
#endif /* INCLUDE_EDR_PM */
return (memTop);
}
/*******************************************************************************
*
* sysToMonitor - transfer control to the ROM monitor
*
* This routine transfers control to the ROM monitor. It is usually called
* only by reboot() -- which services ^X -- and bus errors at interrupt
* level. However, in some circumstances, the user may wish to introduce a
* new <startType> to enable special boot ROM facilities.
*
* RETURNS: Does not return.
*
* ERRNO
*/
/*Please refer to FT-1500A-4V1.5.pdf for GPIO general description.*/
STATUS sysToMonitor(int startType /* passed to ROM to tell it how to boot */
)
{
ARM_SMC_REGS input = { 0 };
ARM_SMC_REGS output = { 0 };
#ifdef _WRS_CONFIG_ARM_LPAE
/* reset TTBCR */
mmuCortexA8TtbcrSet(0);
#endif /* _WRS_CONFIG_ARM_LPAE */
input.a0 = 0x84000009;
armSmcCall(&input, &output);
while (1) {
}
return OK; /* in case we ever continue from ROM monitor */
}
#if defined(_WRS_CONFIG_SMP)
extern void armv7a_secondary_wake();
extern void arm_int_enable();
/*******************************************************************************
*
* sysCpuStart - vxWorks startup
*
* This routine establishes a CPUs vxWorks envirnonment. Note that the MMU
* and caches have been enabled before this routine is called.
*
* This is NOT callable from C.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* \NOMANUAL
*/
IMPORT void excVBARSet(UINT32 adr);
LOCAL void sysCpuStart(void (*startFunc)(void), UINT32 cpuNum)
{
/* sysMsDelay(cpuNum*100);*/
#ifdef INCLUDE_VFP
vfpEnable();
#endif
excVBARSet(LOCAL_MEM_LOCAL_ADRS);
/* Initialise ARM exception mode registers */
armInitExceptionModes();
/* Enable Local S/W interrupts */
sysArmGicDevInit();
sysMPCoreStartup[cpuNum].newSync = 0;
/* Enter the Kernel */
if (cpuNum == VX_SMP_NUM_CPUS - 1)
uartf("sysCpuStart(). cpu to start : %d done! \r\n", cpuNum);
(*startFunc)();
}
/*******************************************************************************
*
* sysCpuEnable - enable a multi core CPU
*
* This routine brings a CPU out of reset
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
* \NOMANUAL
*/
STATUS sysCpuEnable(unsigned int cpuNum, void (*startFunc)(void), char *stackPtr)
{
static INT32 sysCpuEnableFirst = 1;
/* Validate cpuNum */
if (cpuNum < 1 || cpuNum >= VX_SMP_NUM_CPUS)
return (ERROR);
if (sysCpuEnableFirst == 1) {
/*
* IPIs cannot be connected in sysToMonitor, because interrupt handlers
* cannot be installed in interrupt context.
* sysToMonitor can be called from interrupt context as well
* (WIND00321261).
*/
/*
* Connect and enable IPI for Application Processor cores.
* The INT_LVL_MPCORE_IPI08 is sent by core 0 to all the AP cores.
*/
vxIpiConnect(INT_LVL_MPCORE_IPI08, (IPI_HANDLER_FUNC)(sysToMonitor), (void *)(APPCORE_REBOOT));
vxIpiEnable(INT_LVL_MPCORE_IPI08);
/*
* Connect and enable IPI for core0.
* The INT_LVL_MPCORE_RESET is sent by an Application processor core
* to core0.
*/
vxIpiConnect(INT_LVL_MPCORE_RESET, (IPI_HANDLER_FUNC)(sysToMonitor), (void *)&rebootVar);
vxIpiEnable(INT_LVL_MPCORE_RESET);
sysCpuEnableFirst = 0;
}
/* Setup init values */
sysMPCoreStartup[cpuNum].newPC = (UINT32)sysCpuStart;
sysMPCoreStartup[cpuNum].newSP = (UINT32)stackPtr;
sysMPCoreStartup[cpuNum].newArg = (UINT32)startFunc;
#ifndef _WRS_CONFIG_ARM_LPAE
sysMPCoreStartup[cpuNum].newSync = mmuCortexA8TtbrGetAll();
#else /* _WRS_CONFIG_ARM_LPAE */
sysMPCoreStartup[cpuNum].ttbcr = mmuCortexA8TtbcrGet();
sysMPCoreStartup[cpuNum].newSync = mmuCortexA8TtbrGet64();
#endif /* !_WRS_CONFIG_ARM_LPAE */
arm_mmu_ttbr = sysMPCoreStartup[cpuNum].newSync;
/* Make sure data hits memory */
cacheFlush((CACHE_TYPE)DATA_CACHE, (void *)sysMPCoreStartup, (size_t)(sizeof(sysMPCoreStartup)));
cachePipeFlush();
#if 0
if (cpuNum == (VX_SMP_NUM_CPUS-1))
{
*(volatile unsigned int *)(FT_SECONDARY_BOOT_ADDR) = (UINT32)sysCpuInit;
cacheFlush((CACHE_TYPE)DATA_CACHE, FT_SECONDARY_BOOT_ADDR &(~0x3f), 64);
/* Setup CPU for init */
VX_SYNC_BARRIER ();
/* wake up core1 from wfe using sev. */
/*WRS_ASM ("sev");*/
armv7a_secondary_wake();
/* uartf("sysCpuEnable(). cpu to waken : %d done! \r\n", cpuNum);*/
}
#else
{
ARM_SMC_REGS input = { 0 };
ARM_SMC_REGS output = { 0 };
PHYS_ADDR physAddr;
if (vmTranslate(NULL, (VIRT_ADDR)sysCpuInit, &physAddr) == ERROR)
return ERROR;
input.a0 = 0x84000003;
input.a1 = cpuNum;
if (2 == input.a1) {
input.a1 = 0x100; /* Core2's number is 0x100 */
}
if (3 == input.a1) {
input.a1 = 0x101; /* Core3's number is 0x101 */
}
/*input.a2 = (UINT32)(physAddr >> 32);*/
input.a2 = (UINT32)(physAddr & 0xFFFFFFFF);
armSmcCall(&input, &output);
VX_SYNC_BARRIER();
#ifdef _WRS_CONFIG_ARM_LPAE
sysMsDelay(cpuNum * 100);
#endif
/* wake up core from wfe using sev. */
}
#endif
return OK;
}
/*******************************************************************************
*
* sysCpuAvailableGet - return the number of CPUs available
*
* This routine gets the number of CPUs available.
*
* RETURNS: number of CPU cores available
*
* ERRNO: N/A
*/
UINT32 sysCpuAvailableGet(void)
{
return VX_SMP_NUM_CPUS;
}
#endif /* if defined (_WRS_CONFIG_SMP) */
/****************************************************************************
*
* sysProcNumGet - get the processor number
*
* This routine returns the processor number for the CPU board, which is
* set with sysProcNumSet().
*
* RETURNS: The processor number for the CPU board.
*
* ERRNO
*
* SEE ALSO: sysProcNumSet()
*/
int sysProcNumGet(void)
{
return 0;
}
/****************************************************************************
*
* sysProcNumSet - set the processor number
*
* Set the processor number for the CPU board. Processor numbers should be
* unique on a single backplane.
*
* NOTE
* By convention, only processor 0 should dual-port its memory.
*
* RETURNS: N/A
*
* ERRNO
*
* SEE ALSO: sysProcNumGet()
*/
void sysProcNumSet(int procNum /* processor number */
)
{
sysProcNum = procNum;
}
#ifdef INCLUDE_SIO_UTILS
/******************************************************************************
*
* bspSerialChanGet - get the SIO_CHAN device associated with a serial channel
*
* The sysSerialChanGet() routine returns a pointer to the SIO_CHAN
* device associated with a specified serial channel. It is called
* by usrRoot() to obtain pointers when creating the system serial
* devices, `/tyCo/x'. It is also used by the WDB agent to locate its
* serial channel. The VxBus function requires that the BSP provide a
* function named bspSerialChanGet() to provide the information about
* any non-VxBus serial channels, provided by the BSP. As this BSP
* does not support non-VxBus serial channels, this routine always
* returns ERROR.
*
* RETURNS: ERROR, always
*
* ERRNO
*
* \NOMANUAL
*/
SIO_CHAN *bspSerialChanGet(int channel /* serial channel */
)
{
return ((SIO_CHAN *)ERROR);
}
#endif /* INCLUDE_SIO_UTILS */
#ifdef DRV_PCIBUS_FT
LOCAL UCHAR sysPciExIntRoute[4] = { 60, 61, 62, 63 };
/*******************************************************************************
*
* sysPciExAutoconfigInclude - PCI Express autoconfig support routine
*
* This routine performs the PCI Express auto configuration support function.
*
* RETURNS: OK or ERROR
*/
STATUS sysPciExAutoconfigInclude(PCI_SYSTEM *pSys, /* PCI_SYSTEM structure pointer */
PCI_LOC *pLoc, /* pointer to function in question */
UINT devVend /* deviceID/vendorID of device */
)
{
if (pLoc->bus == 0 && pLoc->device == 0 && pLoc->function == 0)
return ERROR;
return OK;
}
/*******************************************************************************
*
* sysPciExAutoconfigIntrAssign - PCI Express autoconfig support routine
*
* This routine peforms the PCI Express auto configuration interrupt assignment
* support function.
*
* RETURNS: PCI interrupt line number given pin mask
*/
UCHAR pci_int_log[32] = { 0 };
int pci_int_idx = 0;
UCHAR sysPciExAutoconfigIntrAssign(PCI_SYSTEM *pSys, /* PCI_SYSTEM structure pointer */
PCI_LOC *pLoc, /* pointer to function in question */
UCHAR pin /* contents of PCI int pin register */
)
{
pci_int_log[pci_int_idx++] = pin;
if (pci_int_idx == 32) {
pci_int_idx = 0;
}
return sysPciExIntRoute[pin - 1];
}
#endif /* DRV_PCIBUS_M85XX */
/* this is for multi cluster*/
#if defined(_WRS_CONFIG_SMP)
UINT32 cpuIndexMap[4] = { 0, 1, 0x100, 0x101 };
UINT32 vxCpuIdGetByIndex(UINT32 idx)
{
if (idx >= VX_MAX_SMP_CPUS)
return (UINT32)-1;
return cpuIndexMap[idx];
}
#endif /* _WRS_CONFIG_SMP */
UCHAR sysPciInByte(ULONG address)
{
return *(volatile UCHAR *)address;
}
void sysPciOutByte(ULONG address, UCHAR data)
{
*(volatile UCHAR *)address = data;
}
UINT16 sysPciInWord(ULONG address)
{
return *(volatile UINT16 *)address;
}
void sysPciOutWord(ULONG address, UINT16 data)
{
*(volatile UINT16 *)address = data;
}
UINT sysPciInLong(ULONG address)
{
return *(volatile UINT *)address;
}
void sysPciOutLong(ULONG address, UINT data)
{
*(volatile UINT *)address = data;
}
extern int fioFormatV(FAST const char *fmt, /* format string */
va_list vaList, /* pointer to varargs list */
FUNCPTR outRoutine, /* handler for args as they're formatted */
int outarg /* argument to routine */
);
UINT32 uart_tx_fifo_addr = UART_1_BASE_ADR; /* FT UART BASE ADDR */
/* prime cell sio constants */
#define UARTFR 0x18 /* Flag register */
#define FLG_UTXFF (1 << 5) /* UART Tx FIFO Full */
#define FLG_UTXFE (1 << 7) /* UART Tx FIFO Empty */
static void charout(char cha)
{
volatile UINT32 reg_val32;
/* for PrimeCell sio */
reg_val32 = *(volatile UINT32 *)(uart_tx_fifo_addr + UARTFR);
/* is the transmitter ready to accept a character? */
while ((reg_val32 & FLG_UTXFF) != 0x00) {
reg_val32 = *(volatile UINT32 *)(uart_tx_fifo_addr + UARTFR);
}
*(volatile UINT32 *)uart_tx_fifo_addr = cha;
}
void stringout(char *str)
{
char *pbuf = str;
char cha;
volatile UINT32 reg_val32;
while ((cha = *pbuf++) != 0)
charout(cha);
do {
reg_val32 = *(volatile UINT32 *)(uart_tx_fifo_addr + UARTFR);
} while ((reg_val32 & FLG_UTXFE) == 0);
}
static int bufferPut(char *inbuf, /* pointer to source buffer */
int length, /* number of bytes to copy */
char **outptr /* pointer to destination buffer */
)
{
bcopy(inbuf, *outptr, length);
*outptr += length;
return (OK);
}
int uartf(const char *fmt, /* format string */
... /* optional arguments to format */
)
{
char charArray[128] = {
0,
};
char *buffer = charArray;
va_list vaList; /* traverses argument list */
int nChars;
va_start(vaList, fmt);
nChars = fioFormatV(fmt, vaList, bufferPut, (int)&buffer);
va_end(vaList);
*buffer = EOS;
stringout(charArray);
return (nChars);
}
/*******************************************************************************
*
* sysSdhcClkFreqGet - get sdhc freq
*
* This routine get sdhc freq.
*
* RETURNS: freq
*/
LOCAL UINT32 sysSdhcClkFreqGet(void)
{
return 600000000;
}
/*******************************************************************************
*
* sysGmacAddrSet - set gmac mac address
*
* This routine set gmac mac address.
*
* RETURNS: void
*/
LOCAL void sysGmacAddrSet(UINT8 *macAddr)
{
static int addr = 0x38;
macAddr[0] = 0;
macAddr[1] = 0;
macAddr[2] = 0x3e;
macAddr[3] = 0x2;
macAddr[4] = 0x2;
macAddr[5] = addr;
addr += 2;
return;
}