rt-thread/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sys.c

676 lines
21 KiB
C

/**************************************************************************//**
* @file sys.c
* @brief N9H30 SYS driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "N9H30.h"
#include "nu_sys.h"
/// @cond HIDDEN_SYMBOLS
#define SYS_MIN_INT_SOURCE 1
#define SYS_MAX_INT_SOURCE 62
#define SYS_NUM_OF_AICREG 16
/* Global variables */
BOOL volatile _sys_bIsAICInitial = FALSE;
/* declaration the function prototype */
extern void SYS_Interrupt_Shell(void);
/* Interrupt Handler Table */
//typedef void (*sys_pvFunPtr)(); /* function pointer */
sys_pvFunPtr sysIrqHandlerTable[] = { 0, /* 0 */
SYS_Interrupt_Shell, /* 1 */
SYS_Interrupt_Shell, /* 2 */
SYS_Interrupt_Shell, /* 3 */
SYS_Interrupt_Shell, /* 4 */
SYS_Interrupt_Shell, /* 5 */
SYS_Interrupt_Shell, /* 6 */
SYS_Interrupt_Shell, /* 7 */
SYS_Interrupt_Shell, /* 8 */
SYS_Interrupt_Shell, /* 9 */
SYS_Interrupt_Shell, /* 10 */
SYS_Interrupt_Shell, /* 11 */
SYS_Interrupt_Shell, /* 12 */
SYS_Interrupt_Shell, /* 13 */
SYS_Interrupt_Shell, /* 14 */
SYS_Interrupt_Shell, /* 15 */
SYS_Interrupt_Shell, /* 16 */
SYS_Interrupt_Shell, /* 17 */
SYS_Interrupt_Shell, /* 18 */
SYS_Interrupt_Shell, /* 19 */
SYS_Interrupt_Shell, /* 20 */
SYS_Interrupt_Shell, /* 21 */
SYS_Interrupt_Shell, /* 22 */
SYS_Interrupt_Shell, /* 23 */
SYS_Interrupt_Shell, /* 24 */
SYS_Interrupt_Shell, /* 25 */
SYS_Interrupt_Shell, /* 26 */
SYS_Interrupt_Shell, /* 27 */
SYS_Interrupt_Shell, /* 28 */
SYS_Interrupt_Shell, /* 29 */
SYS_Interrupt_Shell, /* 30 */
SYS_Interrupt_Shell, /* 31 */
SYS_Interrupt_Shell, /* 32 */
SYS_Interrupt_Shell, /* 33 */
SYS_Interrupt_Shell, /* 34 */
SYS_Interrupt_Shell, /* 35 */
SYS_Interrupt_Shell, /* 36 */
SYS_Interrupt_Shell, /* 37 */
SYS_Interrupt_Shell, /* 38 */
SYS_Interrupt_Shell, /* 39 */
SYS_Interrupt_Shell, /* 40 */
SYS_Interrupt_Shell, /* 41 */
SYS_Interrupt_Shell, /* 42 */
SYS_Interrupt_Shell, /* 43 */
SYS_Interrupt_Shell, /* 44 */
SYS_Interrupt_Shell, /* 45 */
SYS_Interrupt_Shell, /* 46 */
SYS_Interrupt_Shell, /* 47 */
SYS_Interrupt_Shell, /* 48 */
SYS_Interrupt_Shell, /* 49 */
SYS_Interrupt_Shell, /* 50 */
SYS_Interrupt_Shell, /* 51 */
SYS_Interrupt_Shell, /* 52 */
SYS_Interrupt_Shell, /* 53 */
SYS_Interrupt_Shell, /* 54 */
SYS_Interrupt_Shell, /* 55 */
SYS_Interrupt_Shell, /* 56 */
SYS_Interrupt_Shell, /* 57 */
SYS_Interrupt_Shell, /* 58 */
SYS_Interrupt_Shell, /* 59 */
SYS_Interrupt_Shell, /* 60 */
SYS_Interrupt_Shell /* 61 */
};
sys_pvFunPtr sysFiqHandlerTable[] = { 0,
SYS_Interrupt_Shell, /* 1 */
SYS_Interrupt_Shell, /* 2 */
SYS_Interrupt_Shell, /* 3 */
SYS_Interrupt_Shell, /* 4 */
SYS_Interrupt_Shell, /* 5 */
SYS_Interrupt_Shell, /* 6 */
SYS_Interrupt_Shell, /* 7 */
SYS_Interrupt_Shell, /* 8 */
SYS_Interrupt_Shell, /* 9 */
SYS_Interrupt_Shell, /* 10 */
SYS_Interrupt_Shell, /* 11 */
SYS_Interrupt_Shell, /* 12 */
SYS_Interrupt_Shell, /* 13 */
SYS_Interrupt_Shell, /* 14 */
SYS_Interrupt_Shell, /* 15 */
SYS_Interrupt_Shell, /* 16 */
SYS_Interrupt_Shell, /* 17 */
SYS_Interrupt_Shell, /* 18 */
SYS_Interrupt_Shell, /* 19 */
SYS_Interrupt_Shell, /* 20 */
SYS_Interrupt_Shell, /* 21 */
SYS_Interrupt_Shell, /* 22 */
SYS_Interrupt_Shell, /* 23 */
SYS_Interrupt_Shell, /* 24 */
SYS_Interrupt_Shell, /* 25 */
SYS_Interrupt_Shell, /* 26 */
SYS_Interrupt_Shell, /* 27 */
SYS_Interrupt_Shell, /* 28 */
SYS_Interrupt_Shell, /* 29 */
SYS_Interrupt_Shell, /* 30 */
SYS_Interrupt_Shell, /* 31 */
SYS_Interrupt_Shell, /* 32 */
SYS_Interrupt_Shell, /* 33 */
SYS_Interrupt_Shell, /* 34 */
SYS_Interrupt_Shell, /* 35 */
SYS_Interrupt_Shell, /* 36 */
SYS_Interrupt_Shell, /* 37 */
SYS_Interrupt_Shell, /* 38 */
SYS_Interrupt_Shell, /* 39 */
SYS_Interrupt_Shell, /* 40 */
SYS_Interrupt_Shell, /* 41 */
SYS_Interrupt_Shell, /* 42 */
SYS_Interrupt_Shell, /* 43 */
SYS_Interrupt_Shell, /* 44 */
SYS_Interrupt_Shell, /* 45 */
SYS_Interrupt_Shell, /* 46 */
SYS_Interrupt_Shell, /* 47 */
SYS_Interrupt_Shell, /* 48 */
SYS_Interrupt_Shell, /* 49 */
SYS_Interrupt_Shell, /* 50 */
SYS_Interrupt_Shell, /* 51 */
SYS_Interrupt_Shell, /* 52 */
SYS_Interrupt_Shell, /* 53 */
SYS_Interrupt_Shell, /* 54 */
SYS_Interrupt_Shell, /* 55 */
SYS_Interrupt_Shell, /* 56 */
SYS_Interrupt_Shell, /* 57 */
SYS_Interrupt_Shell, /* 58 */
SYS_Interrupt_Shell, /* 59 */
SYS_Interrupt_Shell, /* 60 */
SYS_Interrupt_Shell /* 61 */
};
/* Interrupt Handler */
#if defined ( __GNUC__ ) && !(__CC_ARM)
static void __attribute__((interrupt("IRQ"))) sysIrqHandler(void)
#else
__irq void sysIrqHandler()
#endif
{
UINT32 volatile _mIPER, _mISNR;
_mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f;
_mISNR = inpw(REG_AIC_ISNR);
if (_mIPER != 0)
{
if (_mISNR != 0)
(*sysIrqHandlerTable[_mIPER])();
outpw(REG_AIC_EOSCR, 1);
}
}
#if defined ( __GNUC__ ) && !(__CC_ARM)
static void __attribute__((interrupt("FIQ"))) sysFiqHandler(void)
#else
__irq void sysFiqHandler()
#endif
{
UINT32 volatile _mIPER, _mISNR;
_mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f;
_mISNR = inpw(REG_AIC_ISNR);
if (_mIPER != 0)
{
if (_mISNR != 0)
(*sysFiqHandlerTable[_mIPER])();
outpw(REG_AIC_EOSCR, 1);
}
}
void SYS_Interrupt_Shell()
{
//sysprintf("ISR not found! ISNR=%d\n", inpw(REG_AIC_ISNR));
}
void sysInitializeAIC()
{
*(unsigned int volatile *)0x38 = (unsigned int)sysIrqHandler;
*(unsigned int volatile *)0x3C = (unsigned int)sysFiqHandler;
}
/// @endcond HIDDEN_SYMBOLS
/* Interrupt library functions */
/**
* @brief system AIC - disable interrupt
*
* @param[in] eIntNo Select interrupt source. \ref IRQn_Type
*
* @return 0
*/
INT32 sysDisableInterrupt(IRQn_Type eIntNo)
{
if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE))
return 1;
if (eIntNo < 32)
outpw(REG_AIC_MDCR, (1 << eIntNo));
else
outpw(REG_AIC_MDCRH, (1 << (eIntNo - 32)));
return 0;
}
/**
* @brief system AIC - enable interrupt
*
* @param[in] eIntNo Select interrupt source. \ref IRQn_Type
*
* @return 0
*/
INT32 sysEnableInterrupt(IRQn_Type eIntNo)
{
if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE))
return 1;
if (eIntNo < 32)
outpw(REG_AIC_MECR, (1 << eIntNo));
else
outpw(REG_AIC_MECRH, (1 << (eIntNo - 32)));
return 0;
}
/**
* @brief system AIC - install exception handler
*
* @param[in] nExceptType exception type. ( \ref SYS_SWI / \ref SYS_D_ABORT / \ref SYS_I_ABORT / \ref SYS_UNDEFINE)
* @param[in] pvNewHandler own exception handler
*
* @return old handler
*/
PVOID sysInstallExceptionHandler(INT32 nExceptType, PVOID pvNewHandler)
{
PVOID _mOldVect = NULL;
switch (nExceptType)
{
case SYS_SWI:
_mOldVect = *(PVOID volatile *)0x28;
*(PVOID volatile *)0x28 = pvNewHandler;
break;
case SYS_D_ABORT:
_mOldVect = *(PVOID volatile *)0x30;
*(PVOID volatile *)0x30 = pvNewHandler;
break;
case SYS_I_ABORT:
_mOldVect = *(PVOID volatile *)0x2C;
*(PVOID volatile *)0x2C = pvNewHandler;
break;
case SYS_UNDEFINE:
_mOldVect = *(PVOID volatile *)0x24;
*(PVOID volatile *)0x24 = pvNewHandler;
break;
default:
;
}
return _mOldVect;
}
/**
* @brief system AIC - install FIQ handler
*
* @param[in] pvNewISR own fiq handler
*
* @return old handler
*/
PVOID sysInstallFiqHandler(PVOID pvNewISR)
{
PVOID _mOldVect;
_mOldVect = *(PVOID volatile *)0x3C;
*(PVOID volatile *)0x3C = pvNewISR;
return _mOldVect;
}
/**
* @brief system AIC - install IRQ handler
*
* @param[in] pvNewISR own irq handler
*
* @return old handler
*/
PVOID sysInstallIrqHandler(PVOID pvNewISR)
{
PVOID _mOldVect;
_mOldVect = *(PVOID volatile *)0x38;
*(PVOID volatile *)0x38 = pvNewISR;
return _mOldVect;
}
/**
* @brief system AIC - install Own IRQ service routine
*
* @param[in] nIntTypeLevel Interrupt Level. ( \ref FIQ_LEVEL_0 / \ref IRQ_LEVEL_1 / \ref IRQ_LEVEL_2 / \ref IRQ_LEVEL_3 /
* \ref IRQ_LEVEL_4 / \ref IRQ_LEVEL_5 / \ref IRQ_LEVEL_6 / \ref IRQ_LEVEL_7 )
* @param[in] eIntNo Interrupt number. \ref IRQn_Type
* @param[in] pvNewISR own irq handler
*
* @return old handler
*/
PVOID sysInstallISR(INT32 nIntTypeLevel, IRQn_Type eIntNo, PVOID pvNewISR)
{
PVOID _mOldVect;
UINT32 _mRegAddr/*, _mRegValue*/;
INT shift;
if (!_sys_bIsAICInitial)
{
sysInitializeAIC();
_sys_bIsAICInitial = TRUE;
}
_mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4);
shift = (eIntNo % 4) * 8;
nIntTypeLevel &= 0xff;
outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0x07 << shift)) | (nIntTypeLevel << shift));
if ((nIntTypeLevel & 0x7) == FIQ_LEVEL_0)
{
_mOldVect = (PVOID) sysFiqHandlerTable[eIntNo];
sysFiqHandlerTable[eIntNo] = (sys_pvFunPtr)pvNewISR;
}
else
{
_mOldVect = (PVOID) sysIrqHandlerTable[eIntNo];
sysIrqHandlerTable[eIntNo] = (sys_pvFunPtr)pvNewISR;
}
return _mOldVect;
}
INT32 sysSetGlobalInterrupt(INT32 nIntState)
{
switch (nIntState)
{
case ENABLE_ALL_INTERRUPTS:
outpw(REG_AIC_MECR, 0xFFFFFFFF);
outpw(REG_AIC_MECRH, 0xFFFFFFFF);
break;
case DISABLE_ALL_INTERRUPTS:
outpw(REG_AIC_MDCR, 0xFFFFFFFF);
outpw(REG_AIC_MDCRH, 0xFFFFFFFF);
break;
default:
;
}
return 0;
}
/**
* @brief system AIC - Change interrupt level
*
* @param[in] eIntNo Interrupt number. \ref IRQn_Type
* @param[in] uIntLevel Interrupt Level. ( \ref FIQ_LEVEL_0 / \ref IRQ_LEVEL_1 / \ref IRQ_LEVEL_2 / \ref IRQ_LEVEL_3 /
* \ref IRQ_LEVEL_4 / \ref IRQ_LEVEL_5 / \ref IRQ_LEVEL_6 / \ref IRQ_LEVEL_7 )
*
* @return 0
*/
INT32 sysSetInterruptPriorityLevel(IRQn_Type eIntNo, UINT32 uIntLevel)
{
UINT32 _mRegAddr;
INT shift;
if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE))
return 1;
_mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4);
shift = (eIntNo % 4) * 8;
uIntLevel &= 0x7;
outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0x07 << shift)) | (uIntLevel << shift));
return 0;
}
INT32 sysSetInterruptType(IRQn_Type eIntNo, UINT32 uIntSourceType)
{
UINT32 _mRegAddr;
INT shift;
if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE))
return 1;
_mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4);
shift = (eIntNo % 4) * 8;
uIntSourceType &= 0xC0;
outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0xC0 << shift)) | (uIntSourceType << shift));
return 0;
}
/**
* @brief system AIC - Set CP15 Interrupt Type
*
* @param[in] nIntState Interrupt state. ( \ref ENABLE_IRQ / \ref ENABLE_FIQ / \ref ENABLE_FIQ_IRQ /
* \ref DISABLE_IRQ / \ref DISABLE_FIQ / \ref DISABLE_FIQ_IRQ)
*
* @return 0
*/
INT32 sysSetLocalInterrupt(INT32 nIntState)
{
#if defined ( __GNUC__ ) && !(__CC_ARM)
# else
INT32 temp;
#endif
switch (nIntState)
{
case ENABLE_IRQ:
case ENABLE_FIQ:
case ENABLE_FIQ_IRQ:
#if defined ( __GNUC__ ) && !(__CC_ARM)
asm
(
"mrs r0, CPSR \n"
"bic r0, r0, #0x80 \n"
"msr CPSR_c, r0 \n"
);
#else
__asm
{
MRS temp, CPSR
AND temp, temp, nIntState
MSR CPSR_c, temp
}
#endif
break;
case DISABLE_IRQ:
case DISABLE_FIQ:
case DISABLE_FIQ_IRQ:
#if defined ( __GNUC__ ) && !(__CC_ARM)
asm
(
"MRS r0, CPSR \n"
"ORR r0, r0, #0x80 \n"
"MSR CPSR_c, r0 \n"
);
#else
__asm
{
MRS temp, CPSR
ORR temp, temp, nIntState
MSR CPSR_c, temp
}
#endif
break;
default:
;
}
return 0;
}
UINT32 sysGetInterruptEnableStatus(void)
{
return (inpw(REG_AIC_IMR));
}
UINT32 sysGetInterruptEnableStatusH(void)
{
return (inpw(REG_AIC_IMRH));
}
/// @cond HIDDEN_SYMBOLS
BOOL sysGetIBitState()
{
INT32 temp;
#if defined ( __GNUC__ ) && !(__CC_ARM)
asm
(
"MRS %0, CPSR \n"
:"=r"(temp) : :
);
#else
__asm
{
MRS temp, CPSR
}
#endif
if (temp & 0x80)
return FALSE;
else
return TRUE;
}
INT32 sysGetPLL(UINT32 reg)
{
UINT32 N, M, P;
N = ((inpw(reg) & 0x007F) >> 0) + 1;
M = ((inpw(reg) & 0x1F80) >> 7) + 1;
P = ((inpw(reg) & 0xE000) >> 13) + 1;
return (12 * N / (M * P)); /* 12MHz HXT */
}
/// @endcond HIDDEN_SYMBOLS
/**
* @brief system Timer - install WDT interrupt handler
*
* @param[in] clk clock source. \ref CLK_Type
*
* @return MHz
*/
UINT32 sysGetClock(CLK_Type clk)
{
UINT32 src, divS, divN, reg, div;
switch (clk)
{
case SYS_UPLL:
return sysGetPLL(REG_CLK_UPLLCON);
case SYS_APLL:
return sysGetPLL(REG_CLK_APLLCON);
case SYS_SYSTEM:
{
reg = inpw(REG_CLK_DIVCTL0);
switch (reg & 0x18)
{
case 0x0:
src = 12; /* HXT */
break;
case 0x10:
src = sysGetPLL(REG_CLK_APLLCON);
break;
case 0x18:
src = sysGetPLL(REG_CLK_UPLLCON);
break;
default:
return 0;
}
divS = (reg & 0x7) + 1;
divN = ((reg & 0xf00) >> 8) + 1;
return (src / divS / divN);
}
case SYS_HCLK1:
{
reg = inpw(REG_CLK_DIVCTL0);
switch (reg & 0x18)
{
case 0x0:
src = 12; /* HXT */
break;
case 0x10:
src = sysGetPLL(REG_CLK_APLLCON);
break;
case 0x18:
src = sysGetPLL(REG_CLK_UPLLCON);
break;
default:
return 0;
}
divS = (reg & 0x7) + 1;
divN = ((reg & 0xf00) >> 8) + 1;
return (src / divS / divN / 2);
}
case SYS_HCLK234:
{
reg = inpw(REG_CLK_DIVCTL0);
switch (reg & 0x18)
{
case 0x0:
src = 12; /* HXT */
break;
case 0x10:
src = sysGetPLL(REG_CLK_APLLCON);
break;
case 0x18:
src = sysGetPLL(REG_CLK_UPLLCON);
break;
default:
return 0;
}
divS = (reg & 0x7) + 1;
divN = ((reg & 0xf00) >> 8) + 1;
div = ((reg & 0xf00000) >> 20) + 1;
return (src / divS / divN / 2 / div);
}
case SYS_PCLK:
{
reg = inpw(REG_CLK_DIVCTL0);
switch (reg & 0x18)
{
case 0x0:
src = 12; /* HXT */
break;
case 0x10:
src = sysGetPLL(REG_CLK_APLLCON);
break;
case 0x18:
src = sysGetPLL(REG_CLK_UPLLCON);
break;
default:
return 0;
}
divS = (reg & 0x7) + 1;
divN = ((reg & 0xf00) >> 8) + 1;
div = ((reg & 0xf000000) >> 24) + 1;
return (src / divS / divN / 2 / div);
}
case SYS_CPU:
{
reg = inpw(REG_CLK_DIVCTL0);
switch (reg & 0x18)
{
case 0x0:
src = 12; /* HXT */
break;
case 0x10:
src = sysGetPLL(REG_CLK_APLLCON);
break;
case 0x18:
src = sysGetPLL(REG_CLK_UPLLCON);
break;
default:
return 0;
}
divS = (reg & 0x7) + 1;
divN = ((reg & 0xf00) >> 8) + 1;
div = ((reg & 0xf0000) >> 16) + 1;
return (src / divS / divN / div);
}
default:
;
}
return 0;
}
/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/