sdio+fatfs创建
This commit is contained in:
commit
f762d5d7f8
2473 files changed
+1192014
No files matched your search
@@ -0,0 +1,19 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
# add common code files
|
||||
group = group + SConscript(os.path.join('common', 'SConscript'))
|
||||
|
||||
# cpu porting code files
|
||||
if rtconfig.CPU != 'common':
|
||||
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,24 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp') + Glob('*.S')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('common', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
# build for sub-directory
|
||||
list = os.listdir(cwd)
|
||||
objs = []
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
group = group + objs
|
||||
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-15 Bernard first version
|
||||
* 2021-12-28 GuEe-GUI add fpu support
|
||||
*/
|
||||
|
||||
#ifndef __ARMV8_H__
|
||||
#define __ARMV8_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
/* the exception stack without VFP registers */
|
||||
struct rt_hw_exp_stack
|
||||
{
|
||||
unsigned long long pc;
|
||||
unsigned long long spsr;
|
||||
unsigned long long x30;
|
||||
unsigned long long xzr;
|
||||
unsigned long long fpcr;
|
||||
unsigned long long fpsr;
|
||||
unsigned long long x28;
|
||||
unsigned long long x29;
|
||||
unsigned long long x26;
|
||||
unsigned long long x27;
|
||||
unsigned long long x24;
|
||||
unsigned long long x25;
|
||||
unsigned long long x22;
|
||||
unsigned long long x23;
|
||||
unsigned long long x20;
|
||||
unsigned long long x21;
|
||||
unsigned long long x18;
|
||||
unsigned long long x19;
|
||||
unsigned long long x16;
|
||||
unsigned long long x17;
|
||||
unsigned long long x14;
|
||||
unsigned long long x15;
|
||||
unsigned long long x12;
|
||||
unsigned long long x13;
|
||||
unsigned long long x10;
|
||||
unsigned long long x11;
|
||||
unsigned long long x8;
|
||||
unsigned long long x9;
|
||||
unsigned long long x6;
|
||||
unsigned long long x7;
|
||||
unsigned long long x4;
|
||||
unsigned long long x5;
|
||||
unsigned long long x2;
|
||||
unsigned long long x3;
|
||||
unsigned long long x0;
|
||||
unsigned long long x1;
|
||||
|
||||
unsigned long long fpu[16];
|
||||
};
|
||||
|
||||
#define SP_ELx ( ( unsigned long long ) 0x01 )
|
||||
#define SP_EL0 ( ( unsigned long long ) 0x00 )
|
||||
#define PSTATE_EL1 ( ( unsigned long long ) 0x04 )
|
||||
#define PSTATE_EL2 ( ( unsigned long long ) 0x08 )
|
||||
#define PSTATE_EL3 ( ( unsigned long long ) 0x0c )
|
||||
|
||||
rt_ubase_t rt_hw_get_current_el(void);
|
||||
void rt_hw_set_elx_env(void);
|
||||
void rt_hw_set_current_vbar(rt_ubase_t addr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-05-18 Jesven the first version
|
||||
*/
|
||||
|
||||
.macro SAVE_FPU, reg
|
||||
STR Q0, [\reg, #-0x10]!
|
||||
STR Q1, [\reg, #-0x10]!
|
||||
STR Q2, [\reg, #-0x10]!
|
||||
STR Q3, [\reg, #-0x10]!
|
||||
STR Q4, [\reg, #-0x10]!
|
||||
STR Q5, [\reg, #-0x10]!
|
||||
STR Q6, [\reg, #-0x10]!
|
||||
STR Q7, [\reg, #-0x10]!
|
||||
STR Q8, [\reg, #-0x10]!
|
||||
STR Q9, [\reg, #-0x10]!
|
||||
STR Q10, [\reg, #-0x10]!
|
||||
STR Q11, [\reg, #-0x10]!
|
||||
STR Q12, [\reg, #-0x10]!
|
||||
STR Q13, [\reg, #-0x10]!
|
||||
STR Q14, [\reg, #-0x10]!
|
||||
STR Q15, [\reg, #-0x10]!
|
||||
.endm
|
||||
|
||||
.macro RESTORE_FPU, reg
|
||||
LDR Q15, [\reg], #0x10
|
||||
LDR Q14, [\reg], #0x10
|
||||
LDR Q13, [\reg], #0x10
|
||||
LDR Q12, [\reg], #0x10
|
||||
LDR Q11, [\reg], #0x10
|
||||
LDR Q10, [\reg], #0x10
|
||||
LDR Q9, [\reg], #0x10
|
||||
LDR Q8, [\reg], #0x10
|
||||
LDR Q7, [\reg], #0x10
|
||||
LDR Q6, [\reg], #0x10
|
||||
LDR Q5, [\reg], #0x10
|
||||
LDR Q4, [\reg], #0x10
|
||||
LDR Q3, [\reg], #0x10
|
||||
LDR Q2, [\reg], #0x10
|
||||
LDR Q1, [\reg], #0x10
|
||||
LDR Q0, [\reg], #0x10
|
||||
.endm
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-03-17 bigmagic first version
|
||||
*/
|
||||
|
||||
/*
|
||||
* void __asm_dcache_level(level)
|
||||
*
|
||||
* flush or invalidate one level cache.
|
||||
*
|
||||
* x0: cache level
|
||||
* x1: 0 clean & invalidate, 1 invalidate only
|
||||
* x2~x9: clobbered
|
||||
*/
|
||||
.globl __asm_dcache_level
|
||||
__asm_dcache_level:
|
||||
lsl x12, x0, #1
|
||||
msr csselr_el1, x12 /* select cache level */
|
||||
isb /* sync change of cssidr_el1 */
|
||||
mrs x6, ccsidr_el1 /* read the new cssidr_el1 */
|
||||
and x2, x6, #7 /* x2 <- log2(cache line size)-4 */
|
||||
add x2, x2, #4 /* x2 <- log2(cache line size) */
|
||||
mov x3, #0x3ff
|
||||
and x3, x3, x6, lsr #3 /* x3 <- max number of #ways */
|
||||
clz w5, w3 /* bit position of #ways */
|
||||
mov x4, #0x7fff
|
||||
and x4, x4, x6, lsr #13 /* x4 <- max number of #sets */
|
||||
/* x12 <- cache level << 1 */
|
||||
/* x2 <- line length offset */
|
||||
/* x3 <- number of cache ways - 1 */
|
||||
/* x4 <- number of cache sets - 1 */
|
||||
/* x5 <- bit position of #ways */
|
||||
|
||||
loop_set:
|
||||
mov x6, x3 /* x6 <- working copy of #ways */
|
||||
loop_way:
|
||||
lsl x7, x6, x5
|
||||
orr x9, x12, x7 /* map way and level to cisw value */
|
||||
lsl x7, x4, x2
|
||||
orr x9, x9, x7 /* map set number to cisw value */
|
||||
tbz w1, #0, 1f
|
||||
dc isw, x9
|
||||
b 2f
|
||||
1: dc cisw, x9 /* clean & invalidate by set/way */
|
||||
2: subs x6, x6, #1 /* decrement the way */
|
||||
b.ge loop_way
|
||||
subs x4, x4, #1 /* decrement the set */
|
||||
b.ge loop_set
|
||||
|
||||
ret
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_all(int invalidate_only)
|
||||
*
|
||||
* x0: 0 clean & invalidate, 1 invalidate only
|
||||
*
|
||||
* flush or invalidate all data cache by SET/WAY.
|
||||
*/
|
||||
.globl __asm_dcache_all
|
||||
__asm_dcache_all:
|
||||
mov x1, x0
|
||||
dsb sy
|
||||
mrs x10, clidr_el1 /* read clidr_el1 */
|
||||
lsr x11, x10, #24
|
||||
and x11, x11, #0x7 /* x11 <- loc */
|
||||
cbz x11, finished /* if loc is 0, exit */
|
||||
mov x15, lr
|
||||
mov x0, #0 /* start flush at cache level 0 */
|
||||
/* x0 <- cache level */
|
||||
/* x10 <- clidr_el1 */
|
||||
/* x11 <- loc */
|
||||
/* x15 <- return address */
|
||||
|
||||
loop_level:
|
||||
lsl x12, x0, #1
|
||||
add x12, x12, x0 /* x0 <- tripled cache level */
|
||||
lsr x12, x10, x12
|
||||
and x12, x12, #7 /* x12 <- cache type */
|
||||
cmp x12, #2
|
||||
b.lt skip /* skip if no cache or icache */
|
||||
bl __asm_dcache_level /* x1 = 0 flush, 1 invalidate */
|
||||
skip:
|
||||
add x0, x0, #1 /* increment cache level */
|
||||
cmp x11, x0
|
||||
b.gt loop_level
|
||||
|
||||
mov x0, #0
|
||||
msr csselr_el1, x0 /* restore csselr_el1 */
|
||||
dsb sy
|
||||
isb
|
||||
mov lr, x15
|
||||
|
||||
finished:
|
||||
ret
|
||||
|
||||
.globl __asm_flush_dcache_all
|
||||
__asm_flush_dcache_all:
|
||||
mov x0, #0
|
||||
b __asm_dcache_all
|
||||
|
||||
.globl __asm_invalidate_dcache_all
|
||||
__asm_invalidate_dcache_all:
|
||||
mov x0, #0x1
|
||||
b __asm_dcache_all
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_range(start, end)
|
||||
*
|
||||
* clean & invalidate data cache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
.globl __asm_flush_dcache_range
|
||||
__asm_flush_dcache_range:
|
||||
mrs x3, ctr_el0
|
||||
lsr x3, x3, #16
|
||||
and x3, x3, #0xf
|
||||
mov x2, #4
|
||||
lsl x2, x2, x3 /* cache line size */
|
||||
|
||||
/* x2 <- minimal cache line size in cache system */
|
||||
sub x3, x2, #1
|
||||
bic x0, x0, x3
|
||||
1: dc civac, x0 /* clean & invalidate data or unified cache */
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo 1b
|
||||
dsb sy
|
||||
ret
|
||||
|
||||
/* void __asm_invalidate_dcache_range(start, end)
|
||||
*
|
||||
* invalidate data cache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
.globl __asm_invalidate_dcache_range
|
||||
__asm_invalidate_dcache_range:
|
||||
mrs x3, ctr_el0
|
||||
lsr x3, x3, #16
|
||||
and x3, x3, #0xf
|
||||
mov x2, #4
|
||||
lsl x2, x2, x3 /* cache line size */
|
||||
|
||||
/* x2 <- minimal cache line size in cache system */
|
||||
sub x3, x2, #1
|
||||
bic x0, x0, x3
|
||||
|
||||
1: dc ivac, x0 /* invalidate data or unified cache */
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo 1b
|
||||
dsb sy
|
||||
ret
|
||||
|
||||
/* void __asm_invalidate_icache_range(start, end)
|
||||
*
|
||||
* invalidate icache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
.globl __asm_invalidate_icache_range
|
||||
__asm_invalidate_icache_range:
|
||||
mrs x3, ctr_el0
|
||||
and x3, x3, #0xf
|
||||
mov x2, #4
|
||||
lsl x2, x2, x3 /* cache line size */
|
||||
|
||||
/* x2 <- minimal cache line size in cache system */
|
||||
sub x3, x2, #1
|
||||
bic x0, x0, x3
|
||||
|
||||
1: ic ivau, x0 /* invalidate instruction or unified cache */
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo 1b
|
||||
dsb sy
|
||||
ret
|
||||
|
||||
/*
|
||||
* void __asm_invalidate_icache_all(void)
|
||||
*
|
||||
* invalidate all tlb entries.
|
||||
*/
|
||||
.globl __asm_invalidate_icache_all
|
||||
__asm_invalidate_icache_all:
|
||||
ic ialluis
|
||||
isb sy
|
||||
ret
|
||||
|
||||
.globl __asm_flush_l3_cache
|
||||
__asm_flush_l3_cache:
|
||||
mov x0, #0 /* return status as success */
|
||||
ret
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-28 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
void __asm_flush_dcache_all(void);
|
||||
void __asm_invalidate_dcache_all(void);
|
||||
void __asm_flush_dcache_range(unsigned long start, unsigned long end);
|
||||
void __asm_invalidate_dcache_range(unsigned long start, unsigned long end);
|
||||
|
||||
void __asm_invalidate_icache_all(void);
|
||||
void __asm_invalidate_icache_range(unsigned long start, unsigned long end);
|
||||
|
||||
void rt_hw_dcache_flush_all(void)
|
||||
{
|
||||
__asm_flush_dcache_all();
|
||||
}
|
||||
|
||||
void rt_hw_dcache_invalidate_all(void)
|
||||
{
|
||||
__asm_invalidate_dcache_all();
|
||||
}
|
||||
|
||||
void rt_hw_dcache_flush_range(unsigned long start_addr, unsigned long size)
|
||||
{
|
||||
__asm_flush_dcache_range(start_addr, start_addr + size);
|
||||
}
|
||||
|
||||
void rt_hw_dcache_invalidate_range(unsigned long start_addr,unsigned long size)
|
||||
{
|
||||
__asm_invalidate_dcache_range(start_addr, start_addr + size);
|
||||
}
|
||||
|
||||
void rt_hw_icache_invalidate_all()
|
||||
{
|
||||
__asm_invalidate_icache_all();
|
||||
}
|
||||
|
||||
void rt_hw_icache_invalidate_range(unsigned long start_addr, int size)
|
||||
{
|
||||
__asm_invalidate_icache_range(start_addr, start_addr + size);
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
{
|
||||
rt_hw_icache_invalidate_range((unsigned long)addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_FLUSH)
|
||||
{
|
||||
rt_hw_dcache_flush_range((unsigned long)addr, size);
|
||||
}
|
||||
else if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
{
|
||||
rt_hw_dcache_invalidate_range((unsigned long)addr, size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-10-06 ZhaoXiaowei the first version
|
||||
* 2021-11-04 GuEe-GUI set sp with SP_ELx
|
||||
* 2021-12-28 GuEe-GUI add fpu and smp support
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
#include "asm_fpu.h"
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
|
||||
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
|
||||
#endif
|
||||
|
||||
/*
|
||||
*enable gtimer
|
||||
*/
|
||||
.globl rt_hw_gtimer_enable
|
||||
rt_hw_gtimer_enable:
|
||||
MOV X0,#1
|
||||
MSR CNTP_CTL_EL0,X0
|
||||
RET
|
||||
|
||||
/*
|
||||
*disable gtimer
|
||||
*/
|
||||
.globl rt_hw_gtimer_disable
|
||||
rt_hw_gtimer_disable:
|
||||
MSR CNTP_CTL_EL0,XZR
|
||||
RET
|
||||
|
||||
/*
|
||||
*set gtimer CNTP_TVAL_EL0 value
|
||||
*/
|
||||
.globl rt_hw_set_gtimer_val
|
||||
rt_hw_set_gtimer_val:
|
||||
MSR CNTP_TVAL_EL0,X0
|
||||
RET
|
||||
|
||||
/*
|
||||
*get gtimer CNTP_TVAL_EL0 value
|
||||
*/
|
||||
.globl rt_hw_get_gtimer_val
|
||||
rt_hw_get_gtimer_val:
|
||||
MRS X0,CNTP_TVAL_EL0
|
||||
RET
|
||||
|
||||
|
||||
.globl rt_hw_get_cntpct_val
|
||||
rt_hw_get_cntpct_val:
|
||||
MRS X0, CNTPCT_EL0
|
||||
RET
|
||||
|
||||
/*
|
||||
*get gtimer frq value
|
||||
*/
|
||||
.globl rt_hw_get_gtimer_frq
|
||||
rt_hw_get_gtimer_frq:
|
||||
MRS X0,CNTFRQ_EL0
|
||||
RET
|
||||
|
||||
/*
|
||||
*set gtimer frq value (only in EL3)
|
||||
*/
|
||||
.globl rt_hw_set_gtimer_frq
|
||||
rt_hw_set_gtimer_frq:
|
||||
MRS X1, CurrentEL
|
||||
CMP X1, 0xc
|
||||
BNE rt_hw_set_gtimer_frq_exit
|
||||
MSR CNTFRQ_EL0, X0
|
||||
MOV X0, XZR
|
||||
rt_hw_set_gtimer_frq_exit:
|
||||
RET
|
||||
|
||||
.macro SAVE_CONTEXT
|
||||
/* Save the entire context. */
|
||||
SAVE_FPU SP
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
STP X2, X3, [SP, #-0x10]!
|
||||
STP X4, X5, [SP, #-0x10]!
|
||||
STP X6, X7, [SP, #-0x10]!
|
||||
STP X8, X9, [SP, #-0x10]!
|
||||
STP X10, X11, [SP, #-0x10]!
|
||||
STP X12, X13, [SP, #-0x10]!
|
||||
STP X14, X15, [SP, #-0x10]!
|
||||
STP X16, X17, [SP, #-0x10]!
|
||||
STP X18, X19, [SP, #-0x10]!
|
||||
STP X20, X21, [SP, #-0x10]!
|
||||
STP X22, X23, [SP, #-0x10]!
|
||||
STP X24, X25, [SP, #-0x10]!
|
||||
STP X26, X27, [SP, #-0x10]!
|
||||
STP X28, X29, [SP, #-0x10]!
|
||||
MRS X28, FPCR
|
||||
MRS X29, FPSR
|
||||
STP X28, X29, [SP, #-0x10]!
|
||||
STP X30, XZR, [SP, #-0x10]!
|
||||
|
||||
MRS X0, CurrentEL
|
||||
CMP X0, 0xc
|
||||
B.EQ 3f
|
||||
CMP X0, 0x8
|
||||
B.EQ 2f
|
||||
CMP X0, 0x4
|
||||
B.EQ 1f
|
||||
B .
|
||||
3:
|
||||
MRS X3, SPSR_EL3
|
||||
/* Save the ELR. */
|
||||
MRS X2, ELR_EL3
|
||||
B 0f
|
||||
2:
|
||||
MRS X3, SPSR_EL2
|
||||
/* Save the ELR. */
|
||||
MRS X2, ELR_EL2
|
||||
B 0f
|
||||
1:
|
||||
MRS X3, SPSR_EL1
|
||||
MRS X2, ELR_EL1
|
||||
B 0f
|
||||
0:
|
||||
|
||||
STP X2, X3, [SP, #-0x10]!
|
||||
|
||||
MOV X0, SP /* Move SP into X0 for saving. */
|
||||
|
||||
.endm
|
||||
|
||||
.macro SAVE_CONTEXT_T
|
||||
/* Save the entire context. */
|
||||
SAVE_FPU SP
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
STP X2, X3, [SP, #-0x10]!
|
||||
STP X4, X5, [SP, #-0x10]!
|
||||
STP X6, X7, [SP, #-0x10]!
|
||||
STP X8, X9, [SP, #-0x10]!
|
||||
STP X10, X11, [SP, #-0x10]!
|
||||
STP X12, X13, [SP, #-0x10]!
|
||||
STP X14, X15, [SP, #-0x10]!
|
||||
STP X16, X17, [SP, #-0x10]!
|
||||
STP X18, X19, [SP, #-0x10]!
|
||||
STP X20, X21, [SP, #-0x10]!
|
||||
STP X22, X23, [SP, #-0x10]!
|
||||
STP X24, X25, [SP, #-0x10]!
|
||||
STP X26, X27, [SP, #-0x10]!
|
||||
STP X28, X29, [SP, #-0x10]!
|
||||
MRS X28, FPCR
|
||||
MRS X29, FPSR
|
||||
STP X28, X29, [SP, #-0x10]!
|
||||
STP X30, XZR, [SP, #-0x10]!
|
||||
|
||||
MRS X0, CurrentEL
|
||||
CMP X0, 0xc
|
||||
B.EQ 3f
|
||||
CMP X0, 0x8
|
||||
B.EQ 2f
|
||||
CMP X0, 0x4
|
||||
B.EQ 1f
|
||||
B .
|
||||
3:
|
||||
MOV X3, #((3 << 6) | 0x0d) /* EL3h */
|
||||
MOV X2, X30
|
||||
B 0f
|
||||
2:
|
||||
MOV X3, #((3 << 6) | 0x09) /* EL2h */
|
||||
MOV X2, X30
|
||||
B 0f
|
||||
1:
|
||||
MOV X3, #((3 << 6) | 0x05) /* EL1h */
|
||||
MOV X2, X30
|
||||
B 0f
|
||||
0:
|
||||
|
||||
STP X2, X3, [SP, #-0x10]!
|
||||
|
||||
MOV X0, SP /* Move SP into X0 for saving. */
|
||||
|
||||
.endm
|
||||
|
||||
.macro RESTORE_CONTEXT
|
||||
|
||||
/* Set the SP to point to the stack of the task being restored. */
|
||||
MOV SP, X0
|
||||
|
||||
LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */
|
||||
|
||||
MRS X0, CurrentEL
|
||||
CMP X0, 0xc
|
||||
B.EQ 3f
|
||||
CMP X0, 0x8
|
||||
B.EQ 2f
|
||||
CMP X0, 0x4
|
||||
B.EQ 1f
|
||||
B .
|
||||
3:
|
||||
MSR SPSR_EL3, X3
|
||||
MSR ELR_EL3, X2
|
||||
B 0f
|
||||
2:
|
||||
MSR SPSR_EL2, X3
|
||||
MSR ELR_EL2, X2
|
||||
B 0f
|
||||
1:
|
||||
MSR SPSR_EL1, X3
|
||||
MSR ELR_EL1, X2
|
||||
B 0f
|
||||
0:
|
||||
|
||||
LDP X30, XZR, [SP], #0x10
|
||||
LDP X28, X29, [SP], #0x10
|
||||
MSR FPCR, X28
|
||||
MSR FPSR, X29
|
||||
LDP X28, X29, [SP], #0x10
|
||||
LDP X26, X27, [SP], #0x10
|
||||
LDP X24, X25, [SP], #0x10
|
||||
LDP X22, X23, [SP], #0x10
|
||||
LDP X20, X21, [SP], #0x10
|
||||
LDP X18, X19, [SP], #0x10
|
||||
LDP X16, X17, [SP], #0x10
|
||||
LDP X14, X15, [SP], #0x10
|
||||
LDP X12, X13, [SP], #0x10
|
||||
LDP X10, X11, [SP], #0x10
|
||||
LDP X8, X9, [SP], #0x10
|
||||
LDP X6, X7, [SP], #0x10
|
||||
LDP X4, X5, [SP], #0x10
|
||||
LDP X2, X3, [SP], #0x10
|
||||
LDP X0, X1, [SP], #0x10
|
||||
RESTORE_FPU SP
|
||||
|
||||
ERET
|
||||
|
||||
.endm
|
||||
|
||||
.text
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS X0, DAIF
|
||||
MSR DAIFSet, #3
|
||||
DSB SY
|
||||
RET
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
DSB SY
|
||||
MOV X1, #0xC0
|
||||
ANDS X0, X0, X1
|
||||
B.NE rt_hw_interrupt_enable_exit
|
||||
MSR DAIFClr, #3
|
||||
rt_hw_interrupt_enable_exit:
|
||||
RET
|
||||
|
||||
/*
|
||||
* #ifdef RT_USING_SMP
|
||||
* void rt_hw_context_switch_to(rt_ubase_t to, stuct rt_thread *to_thread);
|
||||
* #else
|
||||
* void rt_hw_context_switch_to(rt_ubase_t to);
|
||||
* #endif
|
||||
* X0 --> to
|
||||
* X1 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
#ifdef RT_USING_SMP
|
||||
STR X0, [SP, #-0x8]!
|
||||
MOV X0, X1
|
||||
BL rt_cpus_lock_status_restore
|
||||
LDR X0, [SP], #0x8
|
||||
#endif /*RT_USING_SMP*/
|
||||
LDR X0, [X0]
|
||||
RESTORE_CONTEXT
|
||||
|
||||
.text
|
||||
/*
|
||||
* #ifdef RT_USING_SMP
|
||||
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
|
||||
* #else
|
||||
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
|
||||
* #endif
|
||||
* X0 --> from
|
||||
* X1 --> to
|
||||
* X2 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
#ifdef RT_USING_SMP
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
STR X30, [SP, #-0x8]!
|
||||
MOV X0, X2
|
||||
BL rt_cpus_lock_status_restore
|
||||
LDR X30, [SP], #0x8
|
||||
LDP X0, X1, [SP], #0x10
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
MOV X8,X0
|
||||
MOV X9,X1
|
||||
|
||||
SAVE_CONTEXT_T
|
||||
|
||||
STR X0, [X8] // store sp in preempted tasks TCB
|
||||
LDR X0, [X9] // get new task stack pointer
|
||||
|
||||
RESTORE_CONTEXT
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
#ifdef RT_USING_SMP
|
||||
/* x0 = context */
|
||||
/* x1 = ¤t_thread->sp */
|
||||
/* x2 = &to_thread->sp, */
|
||||
/* x3 = to_thread TCB */
|
||||
STR X0, [X1]
|
||||
LDR X0, [x2]
|
||||
MOV SP, X0
|
||||
MOV X0, X3
|
||||
BL rt_cpus_lock_status_restore
|
||||
MOV X0, SP
|
||||
RESTORE_CONTEXT
|
||||
#else
|
||||
LDR X2, =rt_thread_switch_interrupt_flag
|
||||
LDR X3, [X2]
|
||||
CMP X3, #1
|
||||
B.EQ _reswitch
|
||||
LDR X4, =rt_interrupt_from_thread // set rt_interrupt_from_thread
|
||||
MOV X3, #1 // set rt_thread_switch_interrupt_flag to 1
|
||||
STR X0, [X4]
|
||||
STR X3, [X2]
|
||||
_reswitch:
|
||||
LDR X2, =rt_interrupt_to_thread // set rt_interrupt_to_thread
|
||||
STR X1, [X2]
|
||||
RET
|
||||
#endif
|
||||
.text
|
||||
|
||||
// -- Exception handlers ----------------------------------
|
||||
|
||||
.align 8
|
||||
.globl vector_fiq
|
||||
vector_fiq:
|
||||
SAVE_CONTEXT
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
BL rt_hw_trap_fiq
|
||||
LDP X0, X1, [SP], #0x10
|
||||
RESTORE_CONTEXT
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
.align 8
|
||||
.globl vector_irq
|
||||
vector_irq:
|
||||
SAVE_CONTEXT
|
||||
STP X0, X1, [SP, #-0x10]!
|
||||
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
LDP X0, X1, [SP], #0x10
|
||||
#ifdef RT_USING_SMP
|
||||
/* Never reture If can switch */
|
||||
BL rt_scheduler_do_irq_switch
|
||||
MOV X0, SP
|
||||
#endif
|
||||
|
||||
// if rt_thread_switch_interrupt_flag set, jump to
|
||||
// rt_hw_context_switch_interrupt_do and don't return
|
||||
LDR X1, =rt_thread_switch_interrupt_flag
|
||||
LDR X2, [X1]
|
||||
CMP X2, #1
|
||||
B.NE vector_irq_exit
|
||||
|
||||
MOV X2, #0 // clear flag
|
||||
STR X2, [X1]
|
||||
|
||||
LDR X3, =rt_interrupt_from_thread
|
||||
LDR X4, [X3]
|
||||
STR x0, [X4] // store sp in preempted tasks's TCB
|
||||
|
||||
LDR x3, =rt_interrupt_to_thread
|
||||
LDR X4, [X3]
|
||||
LDR x0, [X4] // get new task's stack pointer
|
||||
|
||||
vector_irq_exit:
|
||||
RESTORE_CONTEXT
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
.align 8
|
||||
.globl vector_error
|
||||
vector_error:
|
||||
SAVE_CONTEXT
|
||||
BL rt_hw_trap_error
|
||||
B .
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-15 Bernard first version
|
||||
* 2019-07-28 zdzn add smp support
|
||||
* 2021-12-21 GuEe-GUI set tpidr_el1 as multiprocessor id instead of mpidr_el1
|
||||
* 2021-12-28 GuEe-GUI add spinlock for aarch64
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <cpuport.h>
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
/* The more common mpidr_el1 table, redefine it in BSP if it is in other cases */
|
||||
RT_WEAK rt_uint64_t rt_cpu_mpidr_early[] =
|
||||
{
|
||||
[0] = 0x80000000,
|
||||
[1] = 0x80000001,
|
||||
[2] = 0x80000002,
|
||||
[3] = 0x80000003,
|
||||
[4] = 0x80000004,
|
||||
[5] = 0x80000005,
|
||||
[6] = 0x80000006,
|
||||
[7] = 0x80000007,
|
||||
[RT_CPUS_NR] = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
int rt_hw_cpu_id(void)
|
||||
{
|
||||
rt_base_t value;
|
||||
|
||||
__asm__ volatile ("mrs %0, tpidr_el1":"=r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
lock->slock = 0;
|
||||
}
|
||||
|
||||
void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
rt_hw_spinlock_t lock_val, new_lockval;
|
||||
unsigned int tmp;
|
||||
|
||||
__asm__ volatile (
|
||||
/* Increment the next ticket. */
|
||||
" prfm pstl1strm, %3\n"
|
||||
"1: ldaxr %w0, %3\n"
|
||||
" add %w1, %w0, %w5\n"
|
||||
" stxr %w2, %w1, %3\n"
|
||||
" cbnz %w2, 1b\n"
|
||||
/* Check wether we get the lock */
|
||||
" eor %w1, %w0, %w0, ror #16\n"
|
||||
" cbz %w1, 3f\n"
|
||||
/*
|
||||
* Didn't get lock and spin on the owner.
|
||||
* Should send a local event to avoid missing an
|
||||
* unlock before the exclusive load.
|
||||
*/
|
||||
" sevl\n"
|
||||
"2: wfe\n"
|
||||
" ldaxrh %w2, %4\n"
|
||||
" eor %w1, %w2, %w0, lsr #16\n"
|
||||
" cbnz %w1, 2b\n"
|
||||
/* got the lock. */
|
||||
"3:"
|
||||
: "=&r" (lock_val), "=&r" (new_lockval), "=&r" (tmp), "+Q" (*lock)
|
||||
: "Q" (lock->tickets.owner), "I" (1 << 16)
|
||||
: "memory");
|
||||
__DMB();
|
||||
}
|
||||
|
||||
void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
__DMB();
|
||||
__asm__ volatile (
|
||||
"stlrh %w1, %0\n"
|
||||
: "=Q" (lock->tickets.owner)
|
||||
: "r" (lock->tickets.owner + 1)
|
||||
: "memory");
|
||||
}
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
/**
|
||||
* @addtogroup ARM CPU
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/** shutdown CPU */
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Date Author Notes
|
||||
* 2018-10-06 ZhaoXiaowei the first version
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl rt_hw_get_current_el
|
||||
rt_hw_get_current_el:
|
||||
MRS X0, CurrentEL
|
||||
CMP X0, 0xc
|
||||
B.EQ 3f
|
||||
CMP X0, 0x8
|
||||
B.EQ 2f
|
||||
CMP X0, 0x4
|
||||
B.EQ 1f
|
||||
|
||||
LDR X0, =0
|
||||
B 0f
|
||||
3:
|
||||
LDR X0, =3
|
||||
B 0f
|
||||
2:
|
||||
LDR X0, =2
|
||||
B 0f
|
||||
1:
|
||||
LDR X0, =1
|
||||
B 0f
|
||||
0:
|
||||
RET
|
||||
|
||||
|
||||
.globl rt_hw_set_current_vbar
|
||||
rt_hw_set_current_vbar:
|
||||
MRS X1, CurrentEL
|
||||
CMP X1, 0xc
|
||||
B.EQ 3f
|
||||
CMP X1, 0x8
|
||||
B.EQ 2f
|
||||
CMP X1, 0x4
|
||||
B.EQ 1f
|
||||
B 0f
|
||||
3:
|
||||
MSR VBAR_EL3,X0
|
||||
B 0f
|
||||
2:
|
||||
MSR VBAR_EL2,X0
|
||||
B 0f
|
||||
1:
|
||||
MSR VBAR_EL1,X0
|
||||
B 0f
|
||||
0:
|
||||
RET
|
||||
|
||||
|
||||
.globl rt_hw_set_elx_env
|
||||
rt_hw_set_elx_env:
|
||||
MRS X1, CurrentEL
|
||||
CMP X1, 0xc
|
||||
B.EQ 3f
|
||||
CMP X1, 0x8
|
||||
B.EQ 2f
|
||||
CMP X1, 0x4
|
||||
B.EQ 1f
|
||||
B 0f
|
||||
3:
|
||||
MRS X0, SCR_EL3
|
||||
ORR X0, X0, #0xF /* SCR_EL3.NS|IRQ|FIQ|EA */
|
||||
MSR SCR_EL3, X0
|
||||
B 0f
|
||||
2:
|
||||
MRS X0, HCR_EL2
|
||||
ORR X0, X0, #0x38
|
||||
MSR HCR_EL2, X0
|
||||
B 0f
|
||||
1:
|
||||
B 0f
|
||||
0:
|
||||
RET
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-10 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __CPUPORT_H__
|
||||
#define __CPUPORT_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#define __WFI() __asm__ volatile ("wfi":::"memory")
|
||||
#define __WFE() __asm__ volatile ("wfe":::"memory")
|
||||
#define __SEV() __asm__ volatile ("sev")
|
||||
#define __ISB() __asm__ volatile ("isb 0xf":::"memory")
|
||||
#define __DSB() __asm__ volatile ("dsb 0xf":::"memory")
|
||||
#define __DMB() __asm__ volatile ("dmb 0xf":::"memory")
|
||||
|
||||
rt_inline void rt_hw_isb(void)
|
||||
{
|
||||
__asm__ volatile ("isb":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_dmb(void)
|
||||
{
|
||||
__asm__ volatile ("dmb sy":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_dsb(void)
|
||||
{
|
||||
__asm__ volatile ("dsb sy":::"memory");
|
||||
}
|
||||
|
||||
#endif /* __CPUPORT_H__ */
|
||||
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
* 2022-03-08 GuEe-GUI add BSP bind SPI CPU self support
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2)
|
||||
|
||||
#include <gic.h>
|
||||
#include <cpuport.h>
|
||||
|
||||
#include <board.h>
|
||||
|
||||
struct arm_gic
|
||||
{
|
||||
rt_uint64_t offset; /* the first interrupt index in the vector table */
|
||||
|
||||
rt_uint64_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint64_t cpu_hw_base; /* the base address of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
||||
*/
|
||||
#define GIC_CPU_CTRL(hw_base) HWREG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) HWREG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) HWREG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) HWREG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) HWREG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) HWREG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) HWREG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) HWREG32((hw_base) + 0xFCU)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
||||
*/
|
||||
#define GIC_DIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) HWREG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) HWREG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) HWREG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) HWREG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) HWREG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) HWREG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) HWREG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) HWREG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) HWREG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) HWREG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) HWREG32((hw_base) + 0xfe8U)
|
||||
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint64_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
|
||||
irq += _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0U)
|
||||
{
|
||||
pend = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return (pend);
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
mask = 1U << (irq % 32U);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1U << ((irq % 4U) * 8U);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config)
|
||||
{
|
||||
rt_uint64_t icfgr;
|
||||
rt_uint64_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16U) << 1U;
|
||||
|
||||
icfgr &= (~(3U << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint64_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
|
||||
old_tgt |= cpumask << ((irq % 4U)*8U);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority)
|
||||
{
|
||||
rt_uint64_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
/* set priority mask */
|
||||
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point)
|
||||
{
|
||||
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index)
|
||||
{
|
||||
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t pending;
|
||||
rt_uint64_t active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
|
||||
return ((active << 1U) | pending);
|
||||
}
|
||||
|
||||
void arm_gic_send_sgi(rt_uint64_t index, int irq, rt_uint64_t target_list, rt_uint64_t filter_list)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) =
|
||||
((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
|
||||
|
||||
__DSB();
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group)
|
||||
{
|
||||
rt_uint32_t igroupr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1U);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32U);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ((group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start)
|
||||
{
|
||||
unsigned int gic_type, i;
|
||||
rt_uint64_t cpumask = 1U << 0U;
|
||||
|
||||
#ifdef ARM_SPI_BIND_CPU_ID
|
||||
cpumask = 1U << ARM_SPI_BIND_CPU_ID;
|
||||
#endif
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020U)
|
||||
{
|
||||
_gic_max_irq = 1020U;
|
||||
}
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
{
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
}
|
||||
|
||||
cpumask |= cpumask << 8U;
|
||||
cpumask |= cpumask << 16U;
|
||||
cpumask |= cpumask << 24U;
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0x0U;
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 16U)
|
||||
{
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
|
||||
}
|
||||
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 4U)
|
||||
{
|
||||
GIC_DIST_TARGET(dist_base, i) = cpumask;
|
||||
}
|
||||
|
||||
/* Set priority on all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 4U)
|
||||
{
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
|
||||
}
|
||||
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
{
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
}
|
||||
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
{
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0U;
|
||||
}
|
||||
|
||||
/* Enable group0 and group1 interrupt forwarding. */
|
||||
GIC_DIST_CTRL(dist_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
if (!_gic_table[index].cpu_hw_base)
|
||||
{
|
||||
_gic_table[index].cpu_hw_base = cpu_base;
|
||||
}
|
||||
cpu_base = _gic_table[index].cpu_hw_base;
|
||||
|
||||
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
|
||||
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
|
||||
/* Enable CPU interrupt */
|
||||
GIC_CPU_CTRL(cpu_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_gic_dump_type(rt_uint64_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1U << 10U) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint64_t index)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw pending ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw active ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, i * 32U));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
|
||||
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __GIC_H__
|
||||
#define __GIC_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2)
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint64_t index);
|
||||
void arm_gic_ack(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint64_t index, int irq);
|
||||
void arm_gic_umask(rt_uint64_t index, int irq);
|
||||
|
||||
rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint64_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config);
|
||||
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask);
|
||||
rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority);
|
||||
rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority);
|
||||
rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point);
|
||||
rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index);
|
||||
|
||||
rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_send_sgi(rt_uint64_t index, int irq, rt_uint64_t target_list, rt_uint64_t filter_list);
|
||||
|
||||
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index);
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group);
|
||||
rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq);
|
||||
|
||||
int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start);
|
||||
int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base);
|
||||
|
||||
void arm_gic_dump_type(rt_uint64_t index);
|
||||
void arm_gic_dump(rt_uint64_t index);
|
||||
|
||||
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,849 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
* 2022-03-08 GuEe-GUI add BSP bind SPI CPU self support
|
||||
* add GICv3 AArch64 system register interface
|
||||
* modify arm_gic_redist_init() args
|
||||
* modify arm_gic_cpu_init() args
|
||||
* modify arm_gic_send_affinity_sgi() args
|
||||
* remove arm_gic_redist_address_set()
|
||||
* remove arm_gic_cpu_interface_address_set()
|
||||
* remove arm_gic_secondary_cpu_init()
|
||||
* remove get_main_cpu_affval()
|
||||
* remove arm_gic_cpumask_to_affval()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV3)
|
||||
|
||||
#include <gicv3.h>
|
||||
#include <cpuport.h>
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#ifndef ARM_SPI_BIND_CPU_ID
|
||||
#define ARM_SPI_BIND_CPU_ID 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
#define RT_CPUS_NR 1
|
||||
extern int rt_hw_cpu_id(void);
|
||||
#else
|
||||
extern rt_uint64_t rt_cpu_mpidr_early[];
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
struct arm_gic
|
||||
{
|
||||
rt_uint64_t offset; /* the first interrupt index in the vector table */
|
||||
rt_uint64_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */
|
||||
rt_uint64_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint64_t cpu_hw_base[RT_CPUS_NR]; /* the base address of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
#define GET_GICV3_REG(reg, out) __asm__ volatile ("mrs %0, " reg:"=r"(out)::"memory");
|
||||
#define SET_GICV3_REG(reg, in) __asm__ volatile ("msr " reg ", %0"::"r"(in):"memory");
|
||||
|
||||
/* AArch64 System register interface to GICv3 */
|
||||
#define ICC_IAR0_EL1 "S3_0_C12_C8_0"
|
||||
#define ICC_IAR1_EL1 "S3_0_C12_C12_0"
|
||||
#define ICC_EOIR0_EL1 "S3_0_C12_C8_1"
|
||||
#define ICC_EOIR1_EL1 "S3_0_C12_C12_1"
|
||||
#define ICC_HPPIR0_EL1 "S3_0_C12_C8_2"
|
||||
#define ICC_HPPIR1_EL1 "S3_0_C12_C12_2"
|
||||
#define ICC_BPR0_EL1 "S3_0_C12_C8_3"
|
||||
#define ICC_BPR1_EL1 "S3_0_C12_C12_3"
|
||||
#define ICC_DIR_EL1 "S3_0_C12_C11_1"
|
||||
#define ICC_PMR_EL1 "S3_0_C4_C6_0"
|
||||
#define ICC_RPR_EL1 "S3_0_C12_C11_3"
|
||||
#define ICC_CTLR_EL1 "S3_0_C12_C12_4"
|
||||
#define ICC_CTLR_EL3 "S3_6_C12_C12_4"
|
||||
#define ICC_SRE_EL1 "S3_0_C12_C12_5"
|
||||
#define ICC_SRE_EL2 "S3_4_C12_C9_5"
|
||||
#define ICC_SRE_EL3 "S3_6_C12_C12_5"
|
||||
#define ICC_IGRPEN0_EL1 "S3_0_C12_C12_6"
|
||||
#define ICC_IGRPEN1_EL1 "S3_0_C12_C12_7"
|
||||
#define ICC_IGRPEN1_EL3 "S3_6_C12_C12_7"
|
||||
#define ICC_SGI0R_EL1 "S3_0_C12_C11_7"
|
||||
#define ICC_SGI1R_EL1 "S3_0_C12_C11_5"
|
||||
#define ICC_ASGI1R_EL1 "S3_0_C12_C11_6"
|
||||
|
||||
/* Macro to access the Distributor Control Register (GICD_CTLR) */
|
||||
#define GICD_CTLR_RWP (1 << 31)
|
||||
#define GICD_CTLR_E1NWF (1 << 7)
|
||||
#define GICD_CTLR_DS (1 << 6)
|
||||
#define GICD_CTLR_ARE_NS (1 << 5)
|
||||
#define GICD_CTLR_ARE_S (1 << 4)
|
||||
#define GICD_CTLR_ENGRP1S (1 << 2)
|
||||
#define GICD_CTLR_ENGRP1NS (1 << 1)
|
||||
#define GICD_CTLR_ENGRP0 (1 << 0)
|
||||
|
||||
/* Macro to access the Redistributor Control Register (GICR_CTLR) */
|
||||
#define GICR_CTLR_UWP (1 << 31)
|
||||
#define GICR_CTLR_DPG1S (1 << 26)
|
||||
#define GICR_CTLR_DPG1NS (1 << 25)
|
||||
#define GICR_CTLR_DPG0 (1 << 24)
|
||||
#define GICR_CTLR_RWP (1 << 3)
|
||||
#define GICR_CTLR_IR (1 << 2)
|
||||
#define GICR_CTLR_CES (1 << 1)
|
||||
#define GICR_CTLR_EnableLPI (1 << 0)
|
||||
|
||||
/* Macro to access the Generic Interrupt Controller Interface (GICC) */
|
||||
#define GIC_CPU_CTRL(hw_base) HWREG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) HWREG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) HWREG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) HWREG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) HWREG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) HWREG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) HWREG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) HWREG32((hw_base) + 0xFCU)
|
||||
|
||||
/* Macro to access the Generic Interrupt Controller Distributor (GICD) */
|
||||
#define GIC_DIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) HWREG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) HWREG32((hw_base) + 0x080U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) HWREG32((hw_base) + 0x100U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x180U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) HWREG32((hw_base) + 0x200U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) HWREG32((hw_base) + 0x280U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) HWREG32((hw_base) + 0x300U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x380U + ((n) / 32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) HWREG32((hw_base) + 0x400U + ((n) / 4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) HWREG32((hw_base) + 0x800U + ((n) / 4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) HWREG32((hw_base) + 0xc00U + ((n) / 16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) HWREG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf10U + ((n) / 4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf20U + ((n) / 4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) HWREG32((hw_base) + 0xfe8U)
|
||||
#define GIC_DIST_IROUTER(hw_base, n) HWREG64((hw_base) + 0x6000U + (n) * 8U)
|
||||
|
||||
/* SGI base address is at 64K offset from Redistributor base address */
|
||||
#define GIC_RSGI_OFFSET 0x10000
|
||||
|
||||
/* Macro to access the Generic Interrupt Controller Redistributor (GICR) */
|
||||
#define GIC_RDIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U)
|
||||
#define GIC_RDIST_IIDR(hw_base) HWREG32((hw_base) + 0x004U)
|
||||
#define GIC_RDIST_TYPER(hw_base) HWREG64((hw_base) + 0x008U)
|
||||
#define GIC_RDIST_TSTATUSR(hw_base) HWREG32((hw_base) + 0x010U)
|
||||
#define GIC_RDIST_WAKER(hw_base) HWREG32((hw_base) + 0x014U)
|
||||
#define GIC_RDIST_SETLPIR(hw_base) HWREG32((hw_base) + 0x040U)
|
||||
#define GIC_RDIST_CLRLPIR(hw_base) HWREG32((hw_base) + 0x048U)
|
||||
#define GIC_RDIST_PROPBASER(hw_base) HWREG32((hw_base) + 0x070U)
|
||||
#define GIC_RDIST_PENDBASER(hw_base) HWREG32((hw_base) + 0x078U)
|
||||
#define GIC_RDIST_INVLPIR(hw_base) HWREG32((hw_base) + 0x0A0U)
|
||||
#define GIC_RDIST_INVALLR(hw_base) HWREG32((hw_base) + 0x0B0U)
|
||||
#define GIC_RDIST_SYNCR(hw_base) HWREG32((hw_base) + 0x0C0U)
|
||||
|
||||
#define GIC_RDISTSGI_IGROUPR0(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n) * 4U)
|
||||
#define GIC_RDISTSGI_ISENABLER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
|
||||
#define GIC_RDISTSGI_ICENABLER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
|
||||
#define GIC_RDISTSGI_ISPENDR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
|
||||
#define GIC_RDISTSGI_ICPENDR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
|
||||
#define GIC_RDISTSGI_ISACTIVER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
|
||||
#define GIC_RDISTSGI_ICACTIVER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
|
||||
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
|
||||
#define GIC_RDISTSGI_ICFGR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
|
||||
#define GIC_RDISTSGI_ICFGR1(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
|
||||
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n) * 4)
|
||||
#define GIC_RDISTSGI_NSACR(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint64_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
GET_GICV3_REG(ICC_IAR1_EL1, irq);
|
||||
|
||||
irq = (irq & 0x1ffffff) + _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
__DSB();
|
||||
SET_GICV3_REG(ICC_EOIR1_EL1, irq);
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1 << (irq % 32);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq < 32)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1 << (irq % 32);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq < 32)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq >= 16)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0)
|
||||
{
|
||||
pend = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return pend;
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq >= 16)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1 << (irq % 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq >= 16)
|
||||
{
|
||||
mask = 1 << (irq % 32);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1 << ((irq % 4) * 8);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config)
|
||||
{
|
||||
rt_uint64_t icfgr;
|
||||
rt_uint64_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16) << 1;
|
||||
|
||||
icfgr &= (~(3 << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16) >> 1));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t mask = 1 << (irq % 32);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint64_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0ff << ((irq % 4) * 8));
|
||||
old_tgt |= cpumask << ((irq % 4) * 8);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority)
|
||||
{
|
||||
rt_uint64_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq < 32)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
|
||||
mask &= ~(0xff << ((irq % 4) * 8));
|
||||
mask |= ((priority & 0xff) << ((irq % 4) * 8));
|
||||
GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xff << ((irq % 4) * 8));
|
||||
mask |= ((priority & 0xff) << ((irq % 4) * 8));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
if (irq < 32)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4) * 8)) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_system_register_enable_mask(rt_uint64_t index, rt_uint64_t value)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
value &= 0xff;
|
||||
/* set priority mask */
|
||||
SET_GICV3_REG(ICC_SRE_EL1, value);
|
||||
__ISB();
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_system_register_enable_mask(rt_uint64_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint64_t value;
|
||||
|
||||
GET_GICV3_REG(ICC_SRE_EL1, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
priority &= 0xff;
|
||||
/* set priority mask */
|
||||
SET_GICV3_REG(ICC_PMR_EL1, priority);
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint64_t priority;
|
||||
|
||||
GET_GICV3_REG(ICC_PMR_EL1, priority);
|
||||
return priority;
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point)
|
||||
{
|
||||
index = index;
|
||||
binary_point &= 0x7;
|
||||
|
||||
SET_GICV3_REG(ICC_BPR1_EL1, binary_point);
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index)
|
||||
{
|
||||
rt_uint64_t binary_point;
|
||||
|
||||
index = index;
|
||||
GET_GICV3_REG(ICC_BPR1_EL1, binary_point);
|
||||
return binary_point;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq)
|
||||
{
|
||||
rt_uint64_t pending, active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1;
|
||||
|
||||
return ((active << 1) | pending);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void arm_gic_send_affinity_sgi(rt_uint64_t index, int irq, rt_uint64_t cpu_masks[], rt_uint64_t routing_mode)
|
||||
{
|
||||
const int cpu_mask_cpu_max_nr = sizeof(cpu_masks[0]) * 8;
|
||||
rt_uint64_t int_id = (irq & 0xf) << 24;
|
||||
rt_uint64_t irm = routing_mode << 40; /* Interrupt Routing Mode */
|
||||
|
||||
if (routing_mode == GICV3_ROUTED_TO_SPEC)
|
||||
{
|
||||
int cpu_id, cpu_mask_bit, i, cpu_masks_nr = RT_CPUS_NR / cpu_mask_cpu_max_nr;
|
||||
rt_uint16_t target_list;
|
||||
rt_uint64_t rs = 0; /* Range Selector */
|
||||
rt_uint64_t affinity_val, next_affinity_val;
|
||||
|
||||
if (cpu_masks_nr * cpu_mask_cpu_max_nr != RT_CPUS_NR)
|
||||
{
|
||||
++cpu_masks_nr;
|
||||
}
|
||||
|
||||
for (i = cpu_id = 0; i < cpu_masks_nr;)
|
||||
{
|
||||
/* No cpu in this mask */
|
||||
if (cpu_masks[i] == 0)
|
||||
{
|
||||
++i;
|
||||
cpu_id += cpu_mask_cpu_max_nr;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get last cpu affinity value */
|
||||
affinity_val = rt_cpu_mpidr_early[cpu_id] & 0xff00ffff00ULL;
|
||||
|
||||
/* Read 16 cpus information */
|
||||
for (cpu_mask_bit = 0; cpu_mask_bit < 16; ++cpu_mask_bit, ++cpu_id)
|
||||
{
|
||||
/* MPIDR_EL1: aff3[39:32], aff2[23:16], aff1[15:8] */
|
||||
next_affinity_val = rt_cpu_mpidr_early[cpu_id] & 0xff00ffff00ULL;
|
||||
|
||||
/* Affinity value is different, read end */
|
||||
if (affinity_val != next_affinity_val)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get all valid cpu mask */
|
||||
target_list = (0xffff >> (16 - cpu_mask_bit)) & cpu_masks[i];
|
||||
/* Clear read mask */
|
||||
cpu_masks[i] >>= cpu_mask_bit;
|
||||
/* ICC_SGI1R_EL1: aff3[55:48], aff2[39:32], aff1[23:16] */
|
||||
affinity_val <<= 8;
|
||||
|
||||
__DSB();
|
||||
/* Interrupts routed to the PEs specified by Aff3.Aff2.Aff1.<target list>. */
|
||||
SET_GICV3_REG(ICC_SGI1R_EL1, affinity_val | (rs << 44) | irm | int_id | target_list);
|
||||
__ISB();
|
||||
|
||||
/* Check if reset the range selector */
|
||||
rs = affinity_val != next_affinity_val ? 0 : rs + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__DSB();
|
||||
/* Interrupts routed to all PEs in the system, excluding "self". */
|
||||
SET_GICV3_REG(ICC_SGI1R_EL1, irm | int_id);
|
||||
__ISB();
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index)
|
||||
{
|
||||
rt_uint64_t irq;
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
index = index;
|
||||
GET_GICV3_REG(ICC_HPPIR1_EL1, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index)
|
||||
{
|
||||
rt_uint64_t ret = 0;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
if (_gic_table[index].cpu_hw_base != RT_NULL)
|
||||
{
|
||||
ret = GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group)
|
||||
{
|
||||
rt_uint64_t igroupr;
|
||||
rt_uint64_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ((group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1UL;
|
||||
}
|
||||
|
||||
static int arm_gicv3_wait_rwp(rt_uint64_t index, rt_uint64_t irq)
|
||||
{
|
||||
rt_uint64_t rwp_bit;
|
||||
rt_uint64_t base;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
if (irq < 32)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
base = _gic_table[index].redist_hw_base[cpu_id];
|
||||
rwp_bit = GICR_CTLR_RWP;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = _gic_table[index].dist_hw_base;
|
||||
rwp_bit = GICD_CTLR_RWP;
|
||||
}
|
||||
|
||||
while (HWREG32(base) & rwp_bit)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start)
|
||||
{
|
||||
int i;
|
||||
unsigned int gic_type;
|
||||
rt_uint64_t main_cpu_affinity_val;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1f) + 1) * 32;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020)
|
||||
{
|
||||
_gic_max_irq = 1020;
|
||||
}
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
{
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
}
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0;
|
||||
/* Wait for register write pending */
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32; i < _gic_max_irq; i += 16)
|
||||
{
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
main_cpu_affinity_val = rt_cpu_mpidr_early[ARM_SPI_BIND_CPU_ID];
|
||||
#else
|
||||
__asm__ volatile ("mrs %0, mpidr_el1":"=r"(main_cpu_affinity_val));
|
||||
#endif
|
||||
|
||||
/* aff3[39:32], aff2[23:16], aff1[15:8], aff0[7:0] */
|
||||
main_cpu_affinity_val &= 0xff00ffffffULL;
|
||||
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32; i < _gic_max_irq; i++)
|
||||
{
|
||||
GIC_DIST_IROUTER(dist_base, i) = main_cpu_affinity_val | (GICV3_ROUTED_TO_SPEC << 31);
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set priority on spi interrupts. */
|
||||
for (i = 32; i < _gic_max_irq; i += 4)
|
||||
{
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0; i < _gic_max_irq; i += 32)
|
||||
{
|
||||
GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffff;
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0; i < _gic_max_irq; i += 32)
|
||||
{
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/*
|
||||
* The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
|
||||
* Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
|
||||
* If affinity routing is not enabled, GICv3 can be configured for legacy operation.
|
||||
* Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
|
||||
* Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
|
||||
* GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
|
||||
* GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
|
||||
* GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
|
||||
*/
|
||||
GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_redist_init(rt_uint64_t index, rt_uint64_t redist_base)
|
||||
{
|
||||
int i;
|
||||
int cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
redist_base += cpu_id * (2 << 16);
|
||||
_gic_table[index].redist_hw_base[cpu_id] = redist_base;
|
||||
|
||||
/* redistributor enable */
|
||||
GIC_RDIST_WAKER(redist_base) &= ~(1 << 1);
|
||||
while (GIC_RDIST_WAKER(redist_base) & (1 << 2))
|
||||
{
|
||||
}
|
||||
|
||||
/* Disable all sgi and ppi interrupt */
|
||||
GIC_RDISTSGI_ICENABLER0(redist_base) = 0xffffffff;
|
||||
arm_gicv3_wait_rwp(0, 0);
|
||||
|
||||
/* Clear all inetrrupt pending */
|
||||
GIC_RDISTSGI_ICPENDR0(redist_base) = 0xffffffff;
|
||||
|
||||
/* the corresponding interrupt is Group 1 or Non-secure Group 1. */
|
||||
GIC_RDISTSGI_IGROUPR0(redist_base, 0) = 0xffffffff;
|
||||
GIC_RDISTSGI_IGRPMODR0(redist_base, 0) = 0xffffffff;
|
||||
|
||||
/* Configure default priorities for SGI 0:15 and PPI 16:31. */
|
||||
for (i = 0; i < 32; i += 4)
|
||||
{
|
||||
GIC_RDISTSGI_IPRIORITYR(redist_base, i) = 0xa0a0a0a0U;
|
||||
}
|
||||
|
||||
/* Trigger level for PPI interrupts*/
|
||||
GIC_RDISTSGI_ICFGR1(redist_base) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base)
|
||||
{
|
||||
rt_uint64_t value;
|
||||
int cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].cpu_hw_base[cpu_id] = cpu_base;
|
||||
|
||||
value = arm_gic_get_system_register_enable_mask(index);
|
||||
value |= (1 << 0);
|
||||
arm_gic_set_system_register_enable_mask(index, value);
|
||||
SET_GICV3_REG(ICC_CTLR_EL1, 0);
|
||||
|
||||
arm_gic_set_interface_prior_mask(index, 0xff);
|
||||
|
||||
/* Enable group1 interrupt */
|
||||
value = 1;
|
||||
SET_GICV3_REG(ICC_IGRPEN1_EL1, value);
|
||||
|
||||
arm_gic_set_binary_point(0, 0);
|
||||
|
||||
/* ICC_BPR0_EL1 determines the preemption group for both Group 0 and Group 1 interrupts. */
|
||||
value = 1; /* ICC_BPR0_EL1 determines the preemption group for both Group 0 and Group 1 interrupts.*/
|
||||
value |= 1 << 18; /* Targeted SGIs with affinity level 0 values of 0 - 255 are supported. */
|
||||
SET_GICV3_REG(ICC_CTLR_EL1, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_gic_dump_type(rt_uint64_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1 << 10) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint64_t index)
|
||||
{
|
||||
int i;
|
||||
unsigned int val;
|
||||
|
||||
val = arm_gic_get_high_pending_irq(0);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", val, val);
|
||||
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0; i < _gic_max_irq / 32; ++i)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, i * 32));
|
||||
}
|
||||
|
||||
rt_kprintf("\b\b\n--- hw pending ---\n");
|
||||
for (i = 0; i < _gic_max_irq / 32; ++i)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, i * 32));
|
||||
}
|
||||
|
||||
rt_kprintf("\b\b\n--- hw active ---\n");
|
||||
for (i = 0; i < _gic_max_irq / 32; ++i)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, i * 32));
|
||||
}
|
||||
|
||||
rt_kprintf("\b\b\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
|
||||
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) */
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
*/
|
||||
|
||||
#ifndef __GICV3_H__
|
||||
#define __GICV3_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV3)
|
||||
|
||||
#define GICV3_ROUTED_TO_ALL 1UL
|
||||
#define GICV3_ROUTED_TO_SPEC 0UL
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint64_t index);
|
||||
void arm_gic_ack(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint64_t index, int irq);
|
||||
void arm_gic_umask(rt_uint64_t index, int irq);
|
||||
|
||||
rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint64_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config);
|
||||
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask);
|
||||
rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority);
|
||||
rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority);
|
||||
rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point);
|
||||
rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index);
|
||||
|
||||
rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void arm_gic_send_affinity_sgi(rt_uint64_t index, int irq, rt_uint64_t cpu_masks[], rt_uint64_t routing_mode);
|
||||
#endif
|
||||
|
||||
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index);
|
||||
|
||||
rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group);
|
||||
rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq);
|
||||
|
||||
int arm_gic_redist_address_set(rt_uint64_t index, rt_uint64_t redist_addr, int cpu_id);
|
||||
int arm_gic_cpu_interface_address_set(rt_uint64_t index, rt_uint64_t interface_addr, int cpu_id);
|
||||
|
||||
int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start);
|
||||
int arm_gic_redist_init(rt_uint64_t index, rt_uint64_t redist_base);
|
||||
int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base);
|
||||
|
||||
void arm_gic_dump_type(rt_uint64_t index);
|
||||
void arm_gic_dump(rt_uint64_t index);
|
||||
|
||||
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-20 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <gtimer.h>
|
||||
#include <cpuport.h>
|
||||
|
||||
#define EL1_PHY_TIMER_IRQ_NUM 30
|
||||
|
||||
static volatile rt_uint64_t timer_step;
|
||||
|
||||
static void rt_hw_timer_isr(int vector, void *parameter)
|
||||
{
|
||||
rt_hw_set_gtimer_val(timer_step);
|
||||
rt_tick_increase();
|
||||
}
|
||||
|
||||
void rt_hw_gtimer_init(void)
|
||||
{
|
||||
rt_hw_interrupt_install(EL1_PHY_TIMER_IRQ_NUM, rt_hw_timer_isr, RT_NULL, "tick");
|
||||
__ISB();
|
||||
timer_step = rt_hw_get_gtimer_frq();
|
||||
__DSB();
|
||||
timer_step /= RT_TICK_PER_SECOND;
|
||||
rt_hw_gtimer_local_enable();
|
||||
}
|
||||
|
||||
void rt_hw_gtimer_local_enable(void)
|
||||
{
|
||||
rt_hw_gtimer_disable();
|
||||
rt_hw_set_gtimer_val(timer_step);
|
||||
rt_hw_interrupt_umask(EL1_PHY_TIMER_IRQ_NUM);
|
||||
rt_hw_gtimer_enable();
|
||||
}
|
||||
|
||||
void rt_hw_gtimer_local_disable(void)
|
||||
{
|
||||
rt_hw_gtimer_disable();
|
||||
rt_hw_interrupt_mask(EL1_PHY_TIMER_IRQ_NUM);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-20 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __GTIMER_H__
|
||||
#define __GTIMER_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
void rt_hw_gtimer_init(void);
|
||||
void rt_hw_gtimer_local_enable(void);
|
||||
void rt_hw_gtimer_local_disable(void);
|
||||
|
||||
void rt_hw_gtimer_enable();
|
||||
void rt_hw_gtimer_disable();
|
||||
void rt_hw_set_gtimer_val(rt_uint64_t value);
|
||||
rt_uint64_t rt_hw_get_gtimer_val();
|
||||
rt_uint64_t rt_hw_get_cntpct_val();
|
||||
rt_uint64_t rt_hw_get_gtimer_frq();
|
||||
rt_uint64_t rt_hw_set_gtimer_frq(rt_uint64_t value);
|
||||
|
||||
#endif /* __GTIMER_H__ */
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
* 2018-11-22 Jesven add smp support
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "interrupt.h"
|
||||
#include "gic.h"
|
||||
#include "gicv3.h"
|
||||
#include "armv8.h"
|
||||
#include "mmu.h"
|
||||
#include "cpuport.h"
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc isr_table[MAX_HANDLERS];
|
||||
|
||||
/* Those variables will be accessed in ISR, so we need to share them. */
|
||||
rt_ubase_t rt_interrupt_from_thread = 0;
|
||||
rt_ubase_t rt_interrupt_to_thread = 0;
|
||||
rt_ubase_t rt_thread_switch_interrupt_flag = 0;
|
||||
|
||||
extern int system_vectors;
|
||||
|
||||
void rt_hw_vector_init(void)
|
||||
{
|
||||
rt_hw_set_current_vbar((rt_ubase_t)&system_vectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* initialize exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
#ifndef BSP_USING_GIC
|
||||
/* mask all of interrupts */
|
||||
IRQ_DISABLE_BASIC = 0x000000ff;
|
||||
IRQ_DISABLE1 = 0xffffffff;
|
||||
IRQ_DISABLE2 = 0xffffffff;
|
||||
#else
|
||||
/* initialize ARM GIC */
|
||||
arm_gic_dist_init(0, platform_get_gic_dist_base(), GIC_IRQ_START);
|
||||
arm_gic_cpu_init(0, platform_get_gic_cpu_base());
|
||||
#ifdef BSP_USING_GICV3
|
||||
arm_gic_redist_init(0, platform_get_gic_redist_base());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
#ifndef BSP_USING_GIC
|
||||
if (vector < 32)
|
||||
{
|
||||
IRQ_DISABLE1 = (1 << vector);
|
||||
}
|
||||
else if (vector < 64)
|
||||
{
|
||||
vector = vector % 32;
|
||||
IRQ_DISABLE2 = (1 << vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
vector = vector - 64;
|
||||
IRQ_DISABLE_BASIC = (1 << vector);
|
||||
}
|
||||
#else
|
||||
arm_gic_mask(0, vector);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
#ifndef BSP_USING_GIC
|
||||
if (vector < 32)
|
||||
{
|
||||
IRQ_ENABLE1 = (1 << vector);
|
||||
}
|
||||
else if (vector < 64)
|
||||
{
|
||||
vector = vector % 32;
|
||||
IRQ_ENABLE2 = (1 << vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
vector = vector - 64;
|
||||
IRQ_ENABLE_BASIC = (1 << vector);
|
||||
}
|
||||
#else
|
||||
arm_gic_umask(0, vector);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the active interrupt number.
|
||||
* @param none
|
||||
*/
|
||||
int rt_hw_interrupt_get_irq(void)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_active_irq(0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function acknowledges the interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_ack(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_ack(0, vector);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* cpu_mask: target cpus mask, one bit for one core
|
||||
*/
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_set_cpu(0, vector, cpu_mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* @return target cpus mask, one bit for one core
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_target_cpu(0, vector);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* mode: interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_set_configuration(0, vector, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_configuration(0, vector);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_set_pending(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_set_pending_irq(0, vector);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt pending flag, 0: not pending; 1: pending
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_pending_irq(0, vector);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function clear interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_clear_pending(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_clear_pending_irq(0, vector);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt priority value.
|
||||
* @param vector: the interrupt number
|
||||
* priority: the priority of interrupt to set
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_set_priority(0, vector, priority);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt priority.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt priority value
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_priority(0, vector);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority masking threshold.
|
||||
* @param priority: priority masking threshold
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
arm_gic_set_interface_prior_mask(0, priority);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority masking threshold.
|
||||
* @param none
|
||||
* @return priority masking threshold
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
return arm_gic_get_interface_prior_mask(0);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority grouping field split point.
|
||||
* @param bits: priority grouping field split point
|
||||
* @return 0: success; -1: failed
|
||||
*/
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
int status;
|
||||
|
||||
if (bits < 8)
|
||||
{
|
||||
arm_gic_set_binary_point(0, (7 - bits));
|
||||
status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return (status);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority grouping field split point.
|
||||
* @param none
|
||||
* @return priority grouping field split point
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
unsigned int bp;
|
||||
|
||||
bp = arm_gic_get_binary_point(0) & 0x07;
|
||||
|
||||
return (7 - bp);
|
||||
#else
|
||||
return -RT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param new_handler the interrupt service routine to be installed
|
||||
* @param old_handler the old interrupt service routine
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
|
||||
if (vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = isr_table[vector].handler;
|
||||
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
|
||||
#endif /* RT_USING_INTERRUPT_INFO */
|
||||
isr_table[vector].handler = handler;
|
||||
isr_table[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
|
||||
{
|
||||
#ifdef BSP_USING_GIC
|
||||
#ifdef BSP_USING_GICV2
|
||||
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
|
||||
#else
|
||||
arm_gic_send_affinity_sgi(0, ipi_vector, (rt_uint64_t *)&cpu_mask, GICV3_ROUTED_TO_SPEC);
|
||||
#endif
|
||||
#else
|
||||
int i;
|
||||
|
||||
__DSB();
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; ++i)
|
||||
{
|
||||
if (cpu_mask & (1 << i))
|
||||
{
|
||||
IPI_MAILBOX_SET(i) = 1 << ipi_vector;
|
||||
}
|
||||
}
|
||||
|
||||
__DSB();
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
|
||||
{
|
||||
/* note: ipi_vector maybe different with irq_vector */
|
||||
rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __INTERRUPT_H__
|
||||
#define __INTERRUPT_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
#define IRQ_MODE_TRIG_LEVEL (0x00) /* Trigger: level triggered interrupt */
|
||||
#define IRQ_MODE_TRIG_EDGE (0x01) /* Trigger: edge triggered interrupt */
|
||||
|
||||
void rt_hw_vector_init(void);
|
||||
|
||||
void rt_hw_interrupt_init(void);
|
||||
void rt_hw_interrupt_mask(int vector);
|
||||
void rt_hw_interrupt_umask(int vector);
|
||||
|
||||
int rt_hw_interrupt_get_irq(void);
|
||||
void rt_hw_interrupt_ack(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask);
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode);
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_pending(int vector);
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector);
|
||||
void rt_hw_interrupt_clear_pending(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void);
|
||||
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits);
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void);
|
||||
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask);
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-11-28 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include <cpuport.h>
|
||||
#include <mmu.h>
|
||||
|
||||
#define ARCH_SECTION_SHIFT 21
|
||||
#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
|
||||
#define ARCH_SECTION_MASK (ARCH_SECTION_SIZE - 1)
|
||||
#define ARCH_PAGE_SHIFT 12
|
||||
#define ARCH_PAGE_SIZE (1 << ARCH_PAGE_SHIFT)
|
||||
#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
|
||||
|
||||
#define MMU_LEVEL_MASK 0x1ffUL
|
||||
#define MMU_LEVEL_SHIFT 9
|
||||
#define MMU_ADDRESS_BITS 39
|
||||
#define MMU_ADDRESS_MASK 0x0000fffffffff000UL
|
||||
#define MMU_ATTRIB_MASK 0xfff0000000000ffcUL
|
||||
|
||||
#define MMU_TYPE_MASK 3UL
|
||||
#define MMU_TYPE_USED 1UL
|
||||
#define MMU_TYPE_BLOCK 1UL
|
||||
#define MMU_TYPE_TABLE 3UL
|
||||
#define MMU_TYPE_PAGE 3UL
|
||||
|
||||
#define MMU_TBL_BLOCK_2M_LEVEL 2
|
||||
#define MMU_TBL_PAGE_NR_MAX 32
|
||||
|
||||
/* only map 4G io/memory */
|
||||
static volatile unsigned long MMUTable[512] __attribute__((aligned(4096)));
|
||||
static volatile struct
|
||||
{
|
||||
unsigned long entry[512];
|
||||
} MMUPage[MMU_TBL_PAGE_NR_MAX] __attribute__((aligned(4096)));
|
||||
|
||||
static unsigned long _kernel_free_page(void)
|
||||
{
|
||||
static unsigned long i = 0;
|
||||
|
||||
if (i >= MMU_TBL_PAGE_NR_MAX)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
++i;
|
||||
|
||||
return (unsigned long)&MMUPage[i - 1].entry;
|
||||
}
|
||||
|
||||
static int _kenrel_map_2M(unsigned long *tbl, unsigned long va, unsigned long pa, unsigned long attr)
|
||||
{
|
||||
int level;
|
||||
unsigned long *cur_lv_tbl = tbl;
|
||||
unsigned long page;
|
||||
unsigned long off;
|
||||
int level_shift = MMU_ADDRESS_BITS;
|
||||
|
||||
if (va & ARCH_SECTION_MASK)
|
||||
{
|
||||
return MMU_MAP_ERROR_VANOTALIGN;
|
||||
}
|
||||
if (pa & ARCH_SECTION_MASK)
|
||||
{
|
||||
return MMU_MAP_ERROR_PANOTALIGN;
|
||||
}
|
||||
|
||||
for (level = 0; level < MMU_TBL_BLOCK_2M_LEVEL; ++level)
|
||||
{
|
||||
off = (va >> level_shift);
|
||||
off &= MMU_LEVEL_MASK;
|
||||
|
||||
if (!(cur_lv_tbl[off] & MMU_TYPE_USED))
|
||||
{
|
||||
page = _kernel_free_page();
|
||||
|
||||
if (!page)
|
||||
{
|
||||
return MMU_MAP_ERROR_NOPAGE;
|
||||
}
|
||||
|
||||
rt_memset((char *)page, 0, ARCH_PAGE_SIZE);
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)page, ARCH_PAGE_SIZE);
|
||||
cur_lv_tbl[off] = page | MMU_TYPE_TABLE;
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, cur_lv_tbl + off, sizeof(void *));
|
||||
}
|
||||
else
|
||||
{
|
||||
page = cur_lv_tbl[off];
|
||||
page &= MMU_ADDRESS_MASK;
|
||||
}
|
||||
|
||||
page = cur_lv_tbl[off];
|
||||
if ((page & MMU_TYPE_MASK) == MMU_TYPE_BLOCK)
|
||||
{
|
||||
/* is block! error! */
|
||||
return MMU_MAP_ERROR_CONFLICT;
|
||||
}
|
||||
|
||||
/* next level */
|
||||
cur_lv_tbl = (unsigned long *)(page & MMU_ADDRESS_MASK);
|
||||
level_shift -= MMU_LEVEL_SHIFT;
|
||||
}
|
||||
|
||||
attr &= MMU_ATTRIB_MASK;
|
||||
pa |= (attr | MMU_TYPE_BLOCK);
|
||||
off = (va >> ARCH_SECTION_SHIFT);
|
||||
off &= MMU_LEVEL_MASK;
|
||||
cur_lv_tbl[off] = pa;
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, cur_lv_tbl + off, sizeof(void *));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_hw_mmu_setmtt(unsigned long vaddr_start, unsigned long vaddr_end,
|
||||
unsigned long paddr_start, unsigned long attr)
|
||||
{
|
||||
int ret = -1;
|
||||
int i;
|
||||
unsigned long count;
|
||||
unsigned long map_attr = MMU_MAP_CUSTOM(MMU_AP_KAUN, attr);
|
||||
|
||||
if (vaddr_start > vaddr_end)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
if (vaddr_start % ARCH_SECTION_SIZE)
|
||||
{
|
||||
vaddr_start = (vaddr_start / ARCH_SECTION_SIZE) * ARCH_SECTION_SIZE;
|
||||
}
|
||||
if (paddr_start % ARCH_SECTION_SIZE)
|
||||
{
|
||||
paddr_start = (paddr_start / ARCH_SECTION_SIZE) * ARCH_SECTION_SIZE;
|
||||
}
|
||||
if (vaddr_end % ARCH_SECTION_SIZE)
|
||||
{
|
||||
vaddr_end = (vaddr_end / ARCH_SECTION_SIZE + 1) * ARCH_SECTION_SIZE;
|
||||
}
|
||||
|
||||
count = (vaddr_end - vaddr_start) >> ARCH_SECTION_SHIFT;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ret = _kenrel_map_2M((void *)MMUTable, vaddr_start, paddr_start, map_attr);
|
||||
vaddr_start += ARCH_SECTION_SIZE;
|
||||
paddr_start += ARCH_SECTION_SIZE;
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_size_t desc_nr)
|
||||
{
|
||||
rt_memset((void *)MMUTable, 0, sizeof(MMUTable));
|
||||
rt_memset((void *)MMUPage, 0, sizeof(MMUPage));
|
||||
|
||||
/* set page table */
|
||||
for (; desc_nr > 0; --desc_nr)
|
||||
{
|
||||
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end, mdesc->paddr_start, mdesc->attr);
|
||||
++mdesc;
|
||||
}
|
||||
|
||||
rt_hw_dcache_flush_range((unsigned long)MMUTable, sizeof(MMUTable));
|
||||
}
|
||||
|
||||
void rt_hw_mmu_tlb_invalidate(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"tlbi vmalle1\n\r"
|
||||
"dsb sy\n\r"
|
||||
"isb sy\n\r"
|
||||
"ic ialluis\n\r"
|
||||
"dsb sy\n\r"
|
||||
"isb sy");
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(void)
|
||||
{
|
||||
unsigned long reg_val;
|
||||
|
||||
reg_val = 0x00447fUL;
|
||||
__asm__ volatile("msr mair_el1, %0"::"r"(reg_val));
|
||||
|
||||
rt_hw_isb();
|
||||
|
||||
reg_val = (16UL << 0) /* t0sz 48bit */
|
||||
| (0UL << 6) /* reserved */
|
||||
| (0UL << 7) /* epd0 */
|
||||
| (3UL << 8) /* t0 wb cacheable */
|
||||
| (3UL << 10) /* inner shareable */
|
||||
| (2UL << 12) /* t0 outer shareable */
|
||||
| (0UL << 14) /* t0 4K */
|
||||
| (16UL << 16) /* t1sz 48bit */
|
||||
| (0UL << 22) /* define asid use ttbr0.asid */
|
||||
| (0UL << 23) /* epd1 */
|
||||
| (3UL << 24) /* t1 inner wb cacheable */
|
||||
| (3UL << 26) /* t1 outer wb cacheable */
|
||||
| (2UL << 28) /* t1 outer shareable */
|
||||
| (2UL << 30) /* t1 4k */
|
||||
| (1UL << 32) /* 001b 64GB PA */
|
||||
| (0UL << 35) /* reserved */
|
||||
| (1UL << 36) /* as: 0:8bit 1:16bit */
|
||||
| (0UL << 37) /* tbi0 */
|
||||
| (0UL << 38); /* tbi1 */
|
||||
__asm__ volatile("msr tcr_el1, %0"::"r"(reg_val));
|
||||
|
||||
rt_hw_isb();
|
||||
|
||||
__asm__ volatile ("mrs %0, sctlr_el1":"=r"(reg_val));
|
||||
|
||||
reg_val |= 1 << 2; /* enable dcache */
|
||||
reg_val |= 1 << 0; /* enable mmu */
|
||||
|
||||
__asm__ volatile (
|
||||
"msr ttbr0_el1, %0\n\r"
|
||||
"msr sctlr_el1, %1\n\r"
|
||||
"dsb sy\n\r"
|
||||
"isb sy\n\r"
|
||||
::"r"(MMUTable), "r"(reg_val) :"memory");
|
||||
|
||||
rt_hw_mmu_tlb_invalidate();
|
||||
}
|
||||
|
||||
int rt_hw_mmu_map(unsigned long addr, unsigned long size, unsigned long attr)
|
||||
{
|
||||
int ret;
|
||||
rt_ubase_t level;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
ret = rt_hw_mmu_setmtt(addr, addr + size, addr, attr);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-11-28 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H_
|
||||
#define __MMU_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* normal memory wra mapping type */
|
||||
#define NORMAL_MEM 0
|
||||
/* normal nocache memory mapping type */
|
||||
#define NORMAL_NOCACHE_MEM 1
|
||||
/* device mapping type */
|
||||
#define DEVICE_MEM 2
|
||||
|
||||
#define MMU_MAP_ERROR_VANOTALIGN (-1)
|
||||
#define MMU_MAP_ERROR_PANOTALIGN (-2)
|
||||
#define MMU_MAP_ERROR_NOPAGE (-3)
|
||||
#define MMU_MAP_ERROR_CONFLICT (-4)
|
||||
|
||||
struct mem_desc
|
||||
{
|
||||
unsigned long vaddr_start;
|
||||
unsigned long vaddr_end;
|
||||
unsigned long paddr_start;
|
||||
unsigned long attr;
|
||||
};
|
||||
|
||||
#define MMU_AF_SHIFT 10
|
||||
#define MMU_SHARED_SHIFT 8
|
||||
#define MMU_AP_SHIFT 6
|
||||
#define MMU_MA_SHIFT 2
|
||||
|
||||
#define MMU_AP_KAUN 0UL /* kernel r/w, user none */
|
||||
#define MMU_AP_KAUA 1UL /* kernel r/w, user r/w */
|
||||
#define MMU_AP_KRUN 2UL /* kernel r, user none */
|
||||
#define MMU_AP_KRUR 3UL /* kernel r, user r */
|
||||
|
||||
#define MMU_MAP_CUSTOM(ap, mtype) \
|
||||
(\
|
||||
(0x1UL << MMU_AF_SHIFT) |\
|
||||
(0x2UL << MMU_SHARED_SHIFT) |\
|
||||
((ap) << MMU_AP_SHIFT) |\
|
||||
((mtype) << MMU_MA_SHIFT)\
|
||||
)
|
||||
#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM)
|
||||
#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM)
|
||||
#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM)
|
||||
#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM)
|
||||
#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM)
|
||||
#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM)
|
||||
|
||||
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_size_t desc_nr);
|
||||
void rt_hw_mmu_init(void);
|
||||
int rt_hw_mmu_map(unsigned long addr, unsigned long size, unsigned long attr);
|
||||
|
||||
void rt_hw_dcache_flush_all(void);
|
||||
void rt_hw_dcache_invalidate_all(void);
|
||||
void rt_hw_dcache_flush_range(unsigned long start_addr, unsigned long size);
|
||||
void rt_hw_dcache_invalidate_range(unsigned long start_addr,unsigned long size);
|
||||
|
||||
void rt_hw_icache_invalidate_all();
|
||||
void rt_hw_icache_invalidate_range(unsigned long start_addr, int size);
|
||||
|
||||
#endif /* __MMU_H_ */
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 GuEe-GUI The first version
|
||||
*/
|
||||
|
||||
#include <psci.h>
|
||||
#include <smccc.h>
|
||||
#include <armv8.h>
|
||||
|
||||
typedef uint64_t (*psci_call_handle)(uint32_t fn, uint64_t arg0, uint64_t arg1, uint64_t arg2);
|
||||
|
||||
static uint64_t psci_smc_call(uint32_t fn, uint64_t arg0, uint64_t arg1, uint64_t arg2)
|
||||
{
|
||||
return arm_smc_call(fn, arg0, arg1, arg2, 0, 0, 0, 0).x0;
|
||||
}
|
||||
|
||||
static uint64_t psci_hvc_call(uint32_t fn, uint64_t arg0, uint64_t arg1, uint64_t arg2)
|
||||
{
|
||||
return arm_hvc_call(fn, arg0, arg1, arg2, 0, 0, 0, 0).x0;
|
||||
}
|
||||
|
||||
static psci_call_handle psci_call = psci_smc_call;
|
||||
|
||||
static uint64_t shutdown_args[3] = {0, 0, 0};
|
||||
static uint64_t reboot_args[3] = {0, 0, 0};
|
||||
|
||||
void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case PSCI_METHOD_SMC:
|
||||
psci_call = psci_smc_call;
|
||||
break;
|
||||
case PSCI_METHOD_HVC:
|
||||
if (rt_hw_get_current_el() < 2)
|
||||
{
|
||||
psci_call = psci_hvc_call;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (platform_shutdown_args != RT_NULL)
|
||||
{
|
||||
shutdown_args[0] = platform_shutdown_args[0];
|
||||
shutdown_args[1] = platform_shutdown_args[1];
|
||||
shutdown_args[2] = platform_shutdown_args[2];
|
||||
}
|
||||
|
||||
if (platform_reboot_args != RT_NULL)
|
||||
{
|
||||
reboot_args[0] = platform_reboot_args[0];
|
||||
reboot_args[1] = platform_reboot_args[1];
|
||||
reboot_args[2] = platform_reboot_args[2];
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t arm_psci_get_version()
|
||||
{
|
||||
return (uint32_t)psci_call(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t arm_psci_get_affinity_info(uint64_t target_affinity, uint64_t lowest_affinity_level)
|
||||
{
|
||||
return (uint32_t)psci_call(PSCI_0_2_FN_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0);
|
||||
}
|
||||
|
||||
uint32_t arm_psci_get_feature(uint32_t psci_func_id)
|
||||
{
|
||||
return (uint32_t)psci_call(PSCI_1_0_FN_PSCI_FEATURES, psci_func_id, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t arm_psci_cpu_off(uint64_t state)
|
||||
{
|
||||
return (uint32_t)psci_call(PSCI_0_2_FN_CPU_OFF, state, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t arm_psci_cpu_on(uint64_t mpid, uint64_t entry)
|
||||
{
|
||||
/* [40:63] and [24:31] must be zero, other is aff3, aff2, aff1, aff0 */
|
||||
mpid = mpid & 0xff00ffffff;
|
||||
|
||||
return (uint32_t)psci_call(PSCI_0_2_FN_CPU_ON, mpid, entry, 0);
|
||||
}
|
||||
|
||||
uint32_t arm_psci_cpu_suspend(uint32_t power_state, uint64_t entry)
|
||||
{
|
||||
return (uint32_t)psci_call(PSCI_0_2_FN_CPU_SUSPEND, power_state, entry, 0);
|
||||
}
|
||||
|
||||
void arm_psci_system_off()
|
||||
{
|
||||
psci_call(PSCI_0_2_FN_SYSTEM_OFF, shutdown_args[0], shutdown_args[1], shutdown_args[2]);
|
||||
}
|
||||
|
||||
void arm_psci_system_reboot()
|
||||
{
|
||||
psci_call(PSCI_0_2_FN_SYSTEM_RESET, reboot_args[0], reboot_args[1], reboot_args[2]);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 GuEe-GUI The first version
|
||||
*/
|
||||
|
||||
#ifndef __PSCI_H__
|
||||
#define __PSCI_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Non-Confidential PSCI 1.0 release (30 January 2015), and errata fix for PSCI 0.2, unsupport PSCI 0.1
|
||||
*/
|
||||
#define PSCI_VER_0_2 0x00000002
|
||||
|
||||
#define PSCI_METHOD_SMC 3
|
||||
#define PSCI_METHOD_HVC 2
|
||||
|
||||
/* PSCI 0.2 interface */
|
||||
#define PSCI_0_2_FN_BASE 0x84000000
|
||||
#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n))
|
||||
#define PSCI_0_2_FN_END 0x8400001F
|
||||
|
||||
#define PSCI_0_2_FN64_BASE 0xC4000000
|
||||
#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n))
|
||||
#define PSCI_0_2_FN64_END 0xC400001F
|
||||
|
||||
#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0)
|
||||
#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1)
|
||||
#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2)
|
||||
#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3)
|
||||
#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4)
|
||||
#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5)
|
||||
#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6)
|
||||
#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7)
|
||||
#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8)
|
||||
#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9)
|
||||
|
||||
#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1)
|
||||
#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3)
|
||||
#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4)
|
||||
#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5)
|
||||
#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7)
|
||||
|
||||
/* PSCI 1.0 interface */
|
||||
#define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10)
|
||||
#define PSCI_1_0_FN_CPU_FREEZE PSCI_0_2_FN(11)
|
||||
#define PSCI_1_0_FN_CPU_DEFAULT_SUSPEND PSCI_0_2_FN(12)
|
||||
#define PSCI_1_0_FN_NODE_HW_STATE PSCI_0_2_FN(13)
|
||||
#define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14)
|
||||
#define PSCI_1_0_FN_SET_SUSPEND_MODE PSCI_0_2_FN(15)
|
||||
#define PSCI_1_0_FN_STAT_RESIDENCY PSCI_0_2_FN(16)
|
||||
#define PSCI_1_0_FN_STAT_COUNT PSCI_0_2_FN(17)
|
||||
|
||||
#define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND PSCI_0_2_FN64(12)
|
||||
#define PSCI_1_0_FN64_NODE_HW_STATE PSCI_0_2_FN64(13)
|
||||
#define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14)
|
||||
#define PSCI_1_0_FN64_STAT_RESIDENCY PSCI_0_2_FN64(16)
|
||||
#define PSCI_1_0_FN64_STAT_COUNT PSCI_0_2_FN64(17)
|
||||
|
||||
/* 1KB stack per core */
|
||||
#define PSCI_STACK_SHIFT 10
|
||||
#define PSCI_STACK_SIZE (1 << PSCI_STACK_SHIFT)
|
||||
|
||||
/* PSCI affinity level state returned by AFFINITY_INFO */
|
||||
#define PSCI_AFFINITY_LEVEL_ON 0
|
||||
#define PSCI_AFFINITY_LEVEL_OFF 1
|
||||
#define PSCI_AFFINITY_LEVEL_ON_PENDING 2
|
||||
|
||||
/*
|
||||
* PSCI power state
|
||||
* power_level:
|
||||
* Level 0: cores
|
||||
* Level 1: clusters
|
||||
* Level 2: system
|
||||
* state_type:
|
||||
* value 0: standby or retention state
|
||||
* value 1: powerdown state(entry and context_id is valid)
|
||||
* state_id:
|
||||
* StateID
|
||||
*/
|
||||
#define PSCI_POWER_STATE(power_level, state_type, state_id) \
|
||||
( \
|
||||
((power_level) << 24) | \
|
||||
((state_type) << 16) | \
|
||||
((state_id) << 24) \
|
||||
)
|
||||
|
||||
/*
|
||||
* For system, cluster, core
|
||||
* 0: run
|
||||
* 1: standby(only core)
|
||||
* 2: retention
|
||||
* 3: powerdown
|
||||
*/
|
||||
#define PSCI_POWER_STATE_ID(state_id_power_level, system, cluster, core) \
|
||||
( \
|
||||
((state_id_power_level) << 12) | \
|
||||
((system) << 8) | \
|
||||
((cluster) << 4) | \
|
||||
(core) \
|
||||
)
|
||||
|
||||
#define PSCI_RET_SUCCESS 0
|
||||
#define PSCI_RET_NOT_SUPPORTED (-1)
|
||||
#define PSCI_RET_INVALID_PARAMETERS (-2)
|
||||
#define PSCI_RET_DENIED (-3)
|
||||
#define PSCI_RET_ALREADY_ON (-4)
|
||||
#define PSCI_RET_ON_PENDING (-5)
|
||||
#define PSCI_RET_INTERNAL_FAILURE (-6)
|
||||
#define PSCI_RET_NOT_PRESENT (-7)
|
||||
#define PSCI_RET_DISABLED (-8)
|
||||
#define PSCI_RET_INVALID_ADDRESS (-9)
|
||||
|
||||
void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args);
|
||||
|
||||
uint32_t arm_psci_get_version();
|
||||
uint32_t arm_psci_get_affinity_info(uint64_t target_affinity, uint64_t lowest_affinity_level);
|
||||
uint32_t arm_psci_get_feature(uint32_t psci_func_id);
|
||||
|
||||
uint32_t arm_psci_cpu_off(uint64_t state);
|
||||
uint32_t arm_psci_cpu_on(uint64_t mpid, uint64_t entry);
|
||||
uint32_t arm_psci_cpu_suspend(uint32_t power_state, uint64_t entry);
|
||||
|
||||
void arm_psci_system_off();
|
||||
void arm_psci_system_reboot();
|
||||
|
||||
#endif /*__PSCI_H__*/
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 GuEe-GUI The first version
|
||||
*/
|
||||
|
||||
/*
|
||||
* smc calling convention call
|
||||
*/
|
||||
.macro SMCCC_CALL INS
|
||||
stp x8, x29, [sp,#-16]! /* push the frame pointer (x29) for the purposes of AAPCS64 compatibility */
|
||||
\INS #0
|
||||
ldp x8, x29, [sp], #16
|
||||
|
||||
stp x0, x1, [x8]
|
||||
stp x2, x3, [x8, #16]
|
||||
str x6, [x8, #32]
|
||||
ret
|
||||
.endm
|
||||
|
||||
/*
|
||||
* smc call
|
||||
*/
|
||||
.globl arm_smc_call
|
||||
arm_smc_call:
|
||||
SMCCC_CALL smc
|
||||
|
||||
/*
|
||||
* hvc call
|
||||
*/
|
||||
.globl arm_hvc_call
|
||||
arm_hvc_call:
|
||||
SMCCC_CALL hvc
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 GuEe-GUI The first version
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* The ARM SMCCC v1.0 calling convention provides the following guarantees about registers:
|
||||
* Register Modified Return State
|
||||
* X0...X3 Yes Result values
|
||||
* X4...X17 Yes Unpredictable
|
||||
* X18...X30 No Preserved
|
||||
* SP_EL0 No Preserved
|
||||
* SP_ELx No Preserved
|
||||
*/
|
||||
|
||||
struct arm_smccc_ret
|
||||
{
|
||||
uint64_t x0; /* Parameter registers */
|
||||
uint64_t x1; /* Parameter registers */
|
||||
uint64_t x2; /* Parameter registers */
|
||||
uint64_t x3; /* Parameter registers */
|
||||
uint64_t x6; /* Parameter register: Optional Session ID register */
|
||||
};
|
||||
|
||||
struct arm_smccc_ret arm_smc_call(uint32_t w0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, uint32_t w7);
|
||||
struct arm_smccc_ret arm_hvc_call(uint32_t w0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, uint32_t w7);
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-23 Bernard the first version
|
||||
* 2011-10-05 Bernard add thumb mode
|
||||
* 2021-11-04 GuEe-GUI set sp with SP_ELx
|
||||
* 2021-12-28 GuEe-GUI add fpu support
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <armv8.h>
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
static const rt_ubase_t initial_spsr[] =
|
||||
{
|
||||
[1] = PSTATE_EL1 | SP_ELx,
|
||||
[2] = PSTATE_EL2 | SP_ELx,
|
||||
[3] = PSTATE_EL3 | SP_ELx
|
||||
};
|
||||
/* The AAPCS64 requires 128-bit (16 byte) stack alignment */
|
||||
rt_ubase_t *stk = (rt_ubase_t*)RT_ALIGN_DOWN((rt_ubase_t)stack_addr, 16);
|
||||
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q0 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q0 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q1 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q1 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q2 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q2 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q3 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q3 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q4 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q4 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q5 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q5 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q6 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q6 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q7 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q7 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q8 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q8 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q9 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q9 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q10 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q10 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q11 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q11 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q12 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q12 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q13 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q13 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q14 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q14 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q15 */
|
||||
*(--stk) = (rt_ubase_t) 0; /* Q15 */
|
||||
|
||||
*(--stk) = ( rt_ubase_t ) 11; /* X1 */
|
||||
*(--stk) = ( rt_ubase_t ) parameter; /* X0 */
|
||||
*(--stk) = ( rt_ubase_t ) 33; /* X3 */
|
||||
*(--stk) = ( rt_ubase_t ) 22; /* X2 */
|
||||
*(--stk) = ( rt_ubase_t ) 55; /* X5 */
|
||||
*(--stk) = ( rt_ubase_t ) 44; /* X4 */
|
||||
*(--stk) = ( rt_ubase_t ) 77; /* X7 */
|
||||
*(--stk) = ( rt_ubase_t ) 66; /* X6 */
|
||||
*(--stk) = ( rt_ubase_t ) 99; /* X9 */
|
||||
*(--stk) = ( rt_ubase_t ) 88; /* X8 */
|
||||
*(--stk) = ( rt_ubase_t ) 11; /* X11 */
|
||||
*(--stk) = ( rt_ubase_t ) 10; /* X10 */
|
||||
*(--stk) = ( rt_ubase_t ) 13; /* X13 */
|
||||
*(--stk) = ( rt_ubase_t ) 12; /* X12 */
|
||||
*(--stk) = ( rt_ubase_t ) 15; /* X15 */
|
||||
*(--stk) = ( rt_ubase_t ) 14; /* X14 */
|
||||
*(--stk) = ( rt_ubase_t ) 17; /* X17 */
|
||||
*(--stk) = ( rt_ubase_t ) 16; /* X16 */
|
||||
*(--stk) = ( rt_ubase_t ) 19; /* X19 */
|
||||
*(--stk) = ( rt_ubase_t ) 18; /* X18 */
|
||||
*(--stk) = ( rt_ubase_t ) 21; /* X21 */
|
||||
*(--stk) = ( rt_ubase_t ) 20; /* X20 */
|
||||
*(--stk) = ( rt_ubase_t ) 23; /* X23 */
|
||||
*(--stk) = ( rt_ubase_t ) 22; /* X22 */
|
||||
*(--stk) = ( rt_ubase_t ) 25; /* X25 */
|
||||
*(--stk) = ( rt_ubase_t ) 24; /* X24 */
|
||||
*(--stk) = ( rt_ubase_t ) 27; /* X27 */
|
||||
*(--stk) = ( rt_ubase_t ) 26; /* X26 */
|
||||
*(--stk) = ( rt_ubase_t ) 29; /* X29 */
|
||||
*(--stk) = ( rt_ubase_t ) 28; /* X28 */
|
||||
*(--stk) = ( rt_ubase_t ) 0; /* FPSR */
|
||||
*(--stk) = ( rt_ubase_t ) 0; /* FPCR */
|
||||
*(--stk) = ( rt_ubase_t ) 0; /* XZR - has no effect, used so there are an even number of registers. */
|
||||
*(--stk) = ( rt_ubase_t ) texit; /* X30 - procedure call link register. */
|
||||
|
||||
*(--stk) = initial_spsr[rt_hw_get_current_el()];
|
||||
*(--stk) = ( rt_ubase_t ) tentry; /* Exception return address. */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#include <armv8.h>
|
||||
#include <interrupt.h>
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
void rt_hw_show_register(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("X00:0x%16.16p X01:0x%16.16p X02:0x%16.16p X03:0x%16.16p\n", (void *)regs->x0, (void *)regs->x1, (void *)regs->x2, (void *)regs->x3);
|
||||
rt_kprintf("X04:0x%16.16p X05:0x%16.16p X06:0x%16.16p X07:0x%16.16p\n", (void *)regs->x4, (void *)regs->x5, (void *)regs->x6, (void *)regs->x7);
|
||||
rt_kprintf("X08:0x%16.16p X09:0x%16.16p X10:0x%16.16p X11:0x%16.16p\n", (void *)regs->x8, (void *)regs->x9, (void *)regs->x10, (void *)regs->x11);
|
||||
rt_kprintf("X12:0x%16.16p X13:0x%16.16p X14:0x%16.16p X15:0x%16.16p\n", (void *)regs->x12, (void *)regs->x13, (void *)regs->x14, (void *)regs->x15);
|
||||
rt_kprintf("X16:0x%16.16p X17:0x%16.16p X18:0x%16.16p X19:0x%16.16p\n", (void *)regs->x16, (void *)regs->x17, (void *)regs->x18, (void *)regs->x19);
|
||||
rt_kprintf("X20:0x%16.16p X21:0x%16.16p X22:0x%16.16p X23:0x%16.16p\n", (void *)regs->x20, (void *)regs->x21, (void *)regs->x22, (void *)regs->x23);
|
||||
rt_kprintf("X24:0x%16.16p X25:0x%16.16p X26:0x%16.16p X27:0x%16.16p\n", (void *)regs->x24, (void *)regs->x25, (void *)regs->x26, (void *)regs->x27);
|
||||
rt_kprintf("X28:0x%16.16p X29:0x%16.16p X30:0x%16.16p\n", (void *)regs->x28, (void *)regs->x29, (void *)regs->x30);
|
||||
rt_kprintf("SPSR :0x%16.16p\n", (void *)regs->spsr);
|
||||
rt_kprintf("EPC :0x%16.16p\n", (void *)regs->pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* When comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_error(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("error exception:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#ifdef RT_USING_FINSH
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
#ifndef BSP_USING_GIC
|
||||
void *param;
|
||||
uint32_t irq;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
uint32_t value = IRQ_PEND_BASIC & 0x3ff;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
uint32_t cpu_id = rt_hw_cpu_id();
|
||||
uint32_t mailbox_data = IPI_MAILBOX_CLEAR(cpu_id);
|
||||
#else
|
||||
uint32_t cpu_id = 0;
|
||||
#endif
|
||||
uint32_t int_source = CORE_IRQSOURCE(cpu_id) & 0x3ff;
|
||||
|
||||
if (int_source & 0x02)
|
||||
{
|
||||
isr_func = isr_table[IRQ_ARM_TIMER].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[IRQ_ARM_TIMER].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
param = isr_table[IRQ_ARM_TIMER].param;
|
||||
isr_func(IRQ_ARM_TIMER, param);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
if (int_source & 0xf0)
|
||||
{
|
||||
/* it's a ipi interrupt */
|
||||
if (mailbox_data & 0x1)
|
||||
{
|
||||
/* clear mailbox */
|
||||
IPI_MAILBOX_CLEAR(cpu_id) = mailbox_data;
|
||||
isr_func = isr_table[IRQ_ARM_MAILBOX].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[IRQ_ARM_MAILBOX].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
param = isr_table[IRQ_ARM_MAILBOX].param;
|
||||
isr_func(IRQ_ARM_MAILBOX, param);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE_MAILBOX3_CLEAR(cpu_id) = mailbox_data;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
/* local interrupt*/
|
||||
if (value)
|
||||
{
|
||||
if (value & (1 << 8))
|
||||
{
|
||||
value = IRQ_PEND1;
|
||||
irq = __rt_ffs(value) - 1;
|
||||
}
|
||||
else if (value & (1 << 9))
|
||||
{
|
||||
value = IRQ_PEND2;
|
||||
irq = __rt_ffs(value) + 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
value &= 0x0f;
|
||||
irq = __rt_ffs(value) + 63;
|
||||
}
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[irq].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[irq].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
/* Interrupt for myself. */
|
||||
param = isr_table[irq].param;
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(irq, param);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void *param;
|
||||
int ir, ir_self;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_irq();
|
||||
|
||||
if (ir == 1023)
|
||||
{
|
||||
/* Spurious interrupt */
|
||||
return;
|
||||
}
|
||||
|
||||
/* bit 10~12 is cpuid, bit 0~9 is interrupt id */
|
||||
ir_self = ir & 0x3ffUL;
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir_self].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[ir_self].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
/* Interrupt for myself. */
|
||||
param = isr_table[ir_self].param;
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir_self, param);
|
||||
}
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(ir);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
void *param;
|
||||
int ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_irq();
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
param = isr_table[ir].param;
|
||||
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(ir);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Date Author Notes
|
||||
* 2018-10-06 ZhaoXiaowei the first version
|
||||
* 2022-02-16 GuEe-GUI replace vectors entry to macro
|
||||
*/
|
||||
|
||||
.macro ventry label
|
||||
.align 7
|
||||
b \label
|
||||
.endm
|
||||
|
||||
.globl system_vectors
|
||||
.globl vector_error
|
||||
.globl vector_irq
|
||||
.globl vector_fiq
|
||||
.align 11
|
||||
system_vectors:
|
||||
/* Exception from CurrentEL (EL1t) with SP_EL0 (SPSEL = 0) */
|
||||
ventry vector_error /* Synchronous */
|
||||
ventry vector_irq /* IRQ/vIRQ */
|
||||
ventry vector_fiq /* FIQ/vFIQ */
|
||||
ventry vector_error /* SError/vSError */
|
||||
|
||||
/* Exception from CurrentEL (EL1h) with SP_ELn */
|
||||
ventry vector_error /* Synchronous */
|
||||
ventry vector_irq /* IRQ/vIRQ */
|
||||
ventry vector_fiq /* FIQ/vFIQ */
|
||||
ventry vector_error /* SError/vSError */
|
||||
|
||||
/* Exception from lower EL, aarch64 */
|
||||
ventry vector_error /* Synchronous */
|
||||
ventry vector_error /* IRQ/vIRQ */
|
||||
ventry vector_error /* FIQ/vFIQ */
|
||||
ventry vector_error /* SError/vSError */
|
||||
|
||||
/* Exception from lower EL, aarch32 */
|
||||
ventry vector_error /* Synchronous */
|
||||
ventry vector_error /* IRQ/vIRQ */
|
||||
ventry vector_error /* FIQ/vFIQ */
|
||||
ventry vector_error /* SError/vSError */
|
||||
@@ -0,0 +1,13 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp') + Glob('*.S')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('common', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Date Author Notes
|
||||
* 2020-01-15 bigmagic the first version
|
||||
* 2020-08-10 SummerGift support clang compiler
|
||||
* 2021-11-04 GuEe-GUI set sp with SP_ELx
|
||||
* 2021-12-28 GuEe-GUI add smp support
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
|
||||
#define SECONDARY_STACK_SIZE 4096
|
||||
|
||||
.section ".text.entrypoint","ax"
|
||||
|
||||
.globl _start
|
||||
.globl secondary_cpu_start
|
||||
_start:
|
||||
#ifdef RT_USING_SMP
|
||||
mrs x1, mpidr_el1
|
||||
adr x4, .boot_cpu_mpidr
|
||||
str x1, [x4]
|
||||
dsb sy
|
||||
#endif
|
||||
|
||||
bl __asm_flush_dcache_all /* The kernel and data must flush to DDR */
|
||||
|
||||
secondary_cpu_start:
|
||||
#ifdef RT_USING_SMP
|
||||
adr x4, .boot_cpu_mpidr
|
||||
ldr x4, [x4]
|
||||
dsb sy
|
||||
/* Read cpu mpidr_el1 */
|
||||
mrs x1, mpidr_el1
|
||||
|
||||
/* Read cpu id */
|
||||
ldr x0, =rt_cpu_mpidr_early /* BSP must be defined `rt_cpu_mpidr_early' table in smp */
|
||||
mov x2, #0
|
||||
|
||||
cpu_id_confirm:
|
||||
add x2, x2, #1 /* Next cpu id inc */
|
||||
ldr x3, [x0], #8
|
||||
dsb sy
|
||||
cmp x3, #0
|
||||
beq cpu_idle /* Mean that `rt_cpu_mpidr_early' table is end */
|
||||
cmp x3, x1
|
||||
bne cpu_id_confirm
|
||||
|
||||
/* Get cpu id success */
|
||||
sub x0, x2, #1
|
||||
msr tpidr_el1, x0 /* Save cpu id global */
|
||||
cmp x3, x4 /* If it is boot cpu */
|
||||
beq boot_cpu_setup
|
||||
|
||||
/* Set current cpu's stack top */
|
||||
sub x0, x0, #1
|
||||
mov x1, #SECONDARY_STACK_SIZE
|
||||
adr x2, .secondary_cpu_stack_top
|
||||
msub x1, x0, x1, x2
|
||||
|
||||
b cpu_check_el
|
||||
#else
|
||||
msr tpidr_el1, xzr
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
boot_cpu_setup:
|
||||
ldr x1, =_start
|
||||
|
||||
cpu_check_el:
|
||||
mrs x0, CurrentEL /* CurrentEL Register. bit 2, 3. Others reserved */
|
||||
and x0, x0, #12 /* Clear reserved bits */
|
||||
|
||||
/* Running at EL3? */
|
||||
cmp x0, #12 /* EL3 value is 0b1100 */
|
||||
bne cpu_not_in_el3
|
||||
|
||||
/* Should never be executed, just for completeness. (EL3) */
|
||||
mov x2, #(1 << 0) /* EL0 and EL1 are in Non-Secure state */
|
||||
orr x2, x2, #(1 << 4) /* RES1 */
|
||||
orr x2, x2, #(1 << 5) /* RES1 */
|
||||
bic x2, x2, #(1 << 7) /* SMC instructions are enabled at EL1 and above */
|
||||
orr x2, x2, #(1 << 8) /* HVC instructions are enabled at EL1 and above */
|
||||
orr x2, x2, #(1 << 10) /* The next lower level is AArch64 */
|
||||
msr scr_el3, x2
|
||||
|
||||
mov x2, #9 /* Next level is 0b1001->EL2h */
|
||||
orr x2, x2, #(1 << 6) /* Mask FIQ */
|
||||
orr x2, x2, #(1 << 7) /* Mask IRQ */
|
||||
orr x2, x2, #(1 << 8) /* Mask SError */
|
||||
orr x2, x2, #(1 << 9) /* Mask Debug Exception */
|
||||
msr spsr_el3, x2
|
||||
adr x2, cpu_in_el2
|
||||
msr elr_el3, x2
|
||||
eret
|
||||
|
||||
cpu_not_in_el3: /* Running at EL2 or EL1 */
|
||||
cmp x0, #4 /* EL1 = 0100 */
|
||||
beq cpu_in_el1
|
||||
|
||||
cpu_in_el2:
|
||||
/* Enable CNTP for EL1 */
|
||||
mrs x0, cnthctl_el2 /* Counter-timer Hypervisor Control register */
|
||||
orr x0, x0, #3
|
||||
msr cnthctl_el2, x0
|
||||
msr cntvoff_el2, xzr
|
||||
|
||||
mov x0, #(1 << 31) /* Enable AArch64 in EL1 */
|
||||
orr x0, x0, #(1 << 1) /* SWIO hardwired on Pi3 */
|
||||
msr hcr_el2, x0
|
||||
|
||||
mov x2, #5 /* Next level is 0b0101->EL1h */
|
||||
orr x2, x2, #(1 << 6) /* Mask FIQ */
|
||||
orr x2, x2, #(1 << 7) /* Mask IRQ */
|
||||
orr x2, x2, #(1 << 8) /* Mask SError */
|
||||
orr x2, x2, #(1 << 9) /* Mask Debug Exception */
|
||||
msr spsr_el2, x2
|
||||
adr x2, cpu_in_el1
|
||||
msr elr_el2, x2
|
||||
eret
|
||||
|
||||
cpu_in_el1:
|
||||
msr spsel, #1
|
||||
mov sp, x1 /* Set sp in el1 */
|
||||
|
||||
/* Avoid trap from SIMD or float point instruction */
|
||||
mov x1, #0x00300000 /* Don't trap any SIMD/FP instructions in both EL0 and EL1 */
|
||||
msr cpacr_el1, x1
|
||||
|
||||
mrs x1, sctlr_el1
|
||||
orr x1, x1, #(1 << 12) /* Enable Instruction */
|
||||
bic x1, x1, #(3 << 3) /* Disable SP Alignment check */
|
||||
bic x1, x1, #(1 << 1) /* Disable Alignment check */
|
||||
msr sctlr_el1, x1
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
ldr x1, =_start
|
||||
cmp sp, x1
|
||||
bne secondary_cpu_c_start
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
ldr x0, =__bss_start
|
||||
ldr x1, =__bss_end
|
||||
sub x2, x1, x0
|
||||
mov x3, x1
|
||||
cmp x2, #7
|
||||
bls clean_bss_check
|
||||
|
||||
clean_bss_loop_quad:
|
||||
str xzr, [x0], #8
|
||||
sub x2, x3, x0
|
||||
cmp x2, #7
|
||||
bhi clean_bss_loop_quad
|
||||
cmp x1, x0
|
||||
bls jump_to_entry
|
||||
|
||||
clean_bss_loop_byte:
|
||||
str xzr, [x0], #1
|
||||
|
||||
clean_bss_check:
|
||||
cmp x1, x0
|
||||
bhi clean_bss_loop_byte
|
||||
|
||||
jump_to_entry:
|
||||
b rtthread_startup
|
||||
|
||||
cpu_idle:
|
||||
wfe
|
||||
b cpu_idle
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
.align 3
|
||||
.boot_cpu_mpidr:
|
||||
.quad 0x0
|
||||
|
||||
.align 12
|
||||
.secondary_cpu_stack:
|
||||
.space (SECONDARY_STACK_SIZE * (RT_CPUS_NR - 1))
|
||||
.secondary_cpu_stack_top:
|
||||
#endif
|
||||
Reference in new issue
Block a user