arm64: ARMv8-r(Cortex-R82) support
Summary: Adding armv8-r(Cortex-R82) support and modify some common code to fit the change, the change including: 1. ARM Single Security State Support, ARMv8-R support only single security state, and some GIC configure need to change and fit 2. For ARMv8-R, only have EL0 ~ EL2, the code at EL3 is not necessary and system register for EL3 is not accessible(gcc will failed when access these registers) 3. add base MPU configure for the platform. Signed-off-by: qinwei1 <qinwei1@xiaomi.com>
This commit is contained in:
parent
4240723b78
commit
0841f4dbaa
@ -49,10 +49,12 @@ endchoice
|
||||
config ARCH_ARMV8A
|
||||
bool
|
||||
default n
|
||||
select ARCH_HAVE_EL3
|
||||
|
||||
config ARCH_ARMV8R
|
||||
bool
|
||||
default n
|
||||
select ARCH_SINGLE_SECURITY_STATE
|
||||
|
||||
config ARCH_HAVE_PSCI
|
||||
bool "ARM PCSI (Power State Coordination Interface) Support"
|
||||
@ -64,6 +66,24 @@ config ARCH_HAVE_PSCI
|
||||
maybe not applicable for arm core without PCSI firmware
|
||||
interface implement
|
||||
|
||||
config ARCH_SINGLE_SECURITY_STATE
|
||||
bool "ARM Single Security State Support"
|
||||
default n
|
||||
---help---
|
||||
Some ARM aarch64 Cortex-family processors only supports single
|
||||
security state(eg. Cortex-R82). For these Processors,
|
||||
GIC or other ARM architecture feature will with different
|
||||
configure
|
||||
|
||||
config ARCH_HAVE_EL3
|
||||
bool
|
||||
default n
|
||||
---help---
|
||||
Some ARM aarch64 Cortex-family processors only supports
|
||||
EL0~El2(eg. Cortex-R82). For these Processors, the code
|
||||
runing at EL3 is not necessary and system register for EL3
|
||||
is not accessible
|
||||
|
||||
config ARCH_EARLY_PRINT
|
||||
bool "arch early print support"
|
||||
default n
|
||||
|
@ -34,12 +34,18 @@ ifeq ($(CONFIG_ARCH_ARMV8A),y)
|
||||
ARCHCPUFLAGS += -march=armv8-a
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_ARMV8R),y)
|
||||
ARCHCPUFLAGS += -march=armv8-r
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_CORTEX_A53),y)
|
||||
ARCHCPUFLAGS += -mtune=cortex-a53
|
||||
else ifeq ($(CONFIG_ARCH_CORTEX_A57),y)
|
||||
ARCHCPUFLAGS += -mtune=cortex-a57
|
||||
else ifeq ($(CONFIG_ARCH_CORTEX_A72),y)
|
||||
ARCHCPUFLAGS += -mtune=cortex-a72
|
||||
else ifeq ($(CONFIG_ARCH_CORTEX_R82),y)
|
||||
ARCHCPUFLAGS += -mtune=cortex-r82
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y)
|
||||
|
@ -70,6 +70,24 @@ const struct arm_mmu_config mmu_config =
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm64_el_init
|
||||
*
|
||||
* Description:
|
||||
* The function called from arm64_head.S at very early stage for these
|
||||
* platform, it's use to:
|
||||
* - Handling special hardware initialize routine which is need to
|
||||
* run at high ELs
|
||||
* - Initialize system software such as hypervisor or security firmware
|
||||
* which is need to run at high ELs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void arm64_el_init(void)
|
||||
{
|
||||
/* TODO: A64 set init sys clock */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm64_chip_boot
|
||||
*
|
||||
|
@ -50,13 +50,29 @@ CMN_CSRCS += arm64_schedulesigaction.c arm64_sigdeliver.c
|
||||
CMN_CSRCS += arm64_backtrace.c arm64_getintstack.c arm64_registerdump.c
|
||||
|
||||
# Common C source files ( hardware BSP )
|
||||
CMN_CSRCS += arm64_mmu.c arm64_arch_timer.c arm64_cache.c
|
||||
CMN_CSRCS += arm64_doirq.c arm64_gicv2.c arm64_gicv3.c arm64_fatal.c
|
||||
CMN_CSRCS += arm64_arch_timer.c arm64_cache.c
|
||||
CMN_CSRCS += arm64_doirq.c arm64_fatal.c
|
||||
CMN_CSRCS += arm64_syscall.c
|
||||
|
||||
# Use common heap allocation for now (may need to be customized later)
|
||||
CMN_CSRCS += arm64_allocateheap.c
|
||||
|
||||
ifeq ($(CONFIG_ARM_GIC_VERSION),3)
|
||||
CMN_CSRCS += arm64_gicv3.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARM_GIC_VERSION),2)
|
||||
CMN_CSRCS += arm64_gicv2.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HAVE_MMU),y)
|
||||
CMN_CSRCS += arm64_mmu.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HAVE_MPU),y)
|
||||
CMN_CSRCS += arm64_mpu.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HAVE_PSCI),y)
|
||||
CMN_CSRCS += arm64_cpu_psci.c arm64_systemreset.c
|
||||
endif
|
||||
|
@ -221,8 +221,6 @@ void up_timer_initialize(void)
|
||||
(unsigned long)(arch_timer_rate / 10000) % 100, cycle_per_tick);
|
||||
|
||||
irq_attach(ARM_ARCH_TIMER_IRQ, arm64_arch_timer_compare_isr, 0);
|
||||
arm64_gic_irq_set_priority(ARM_ARCH_TIMER_IRQ, ARM_ARCH_TIMER_PRIO,
|
||||
ARM_ARCH_TIMER_FLAGS);
|
||||
|
||||
curr_cycle = arm64_arch_timer_count();
|
||||
arm64_arch_timer_set_compare(curr_cycle + cycle_per_tick);
|
||||
|
@ -36,6 +36,13 @@ extern void *_vector_table[];
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_EL3
|
||||
|
||||
/* Some ARM aarch64 Cortex-family processors have not EL3
|
||||
* these two function should never called
|
||||
* defined to available compile error when with gcc option
|
||||
*/
|
||||
|
||||
void arm64_boot_el3_init(void)
|
||||
{
|
||||
uint64_t reg;
|
||||
@ -87,6 +94,7 @@ void arm64_boot_el3_get_next_el(uint64_t switch_addr)
|
||||
|
||||
write_sysreg(spsr, spsr_el3);
|
||||
}
|
||||
#endif
|
||||
|
||||
void arm64_boot_el2_init(void)
|
||||
{
|
||||
|
@ -43,7 +43,12 @@
|
||||
#include "arm64_arch_timer.h"
|
||||
#include "arm64_smp.h"
|
||||
#include "arm64_cpu_psci.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_MPU
|
||||
#include "arm64_mpu.h"
|
||||
#else
|
||||
#include "arm64_mmu.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public data
|
||||
@ -58,6 +63,7 @@ struct arm64_boot_params
|
||||
arm64_cpustart_t func;
|
||||
void *arg;
|
||||
int cpu_num;
|
||||
volatile long cpu_ready_flag;
|
||||
};
|
||||
|
||||
volatile struct arm64_boot_params aligned_data(L1_CACHE_BYTES)
|
||||
@ -76,8 +82,6 @@ volatile uint64_t *g_cpu_int_stacktop[CONFIG_SMP_NCPUS] =
|
||||
* Private data
|
||||
****************************************************************************/
|
||||
|
||||
static volatile long cpu_ready_flag;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@ -89,12 +93,28 @@ static inline void local_delay(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_MMU
|
||||
static void flush_boot_params(void)
|
||||
{
|
||||
uintptr_t flush_start;
|
||||
uintptr_t flush_end;
|
||||
|
||||
flush_start = (uintptr_t)&cpu_boot_params;
|
||||
flush_end = flush_start + sizeof(cpu_boot_params);
|
||||
|
||||
up_flush_dcache(flush_start, flush_end);
|
||||
}
|
||||
#else
|
||||
static void flush_boot_params(void)
|
||||
{
|
||||
/* TODO: Flush at MPU platform */
|
||||
}
|
||||
#endif
|
||||
|
||||
static void arm64_smp_init_top(void *arg)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
cpu_ready_flag = 1;
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
/* And finally, enable interrupts */
|
||||
|
||||
@ -118,6 +138,9 @@ static void arm64_smp_init_top(void *arg)
|
||||
write_sysreg(tcb, tpidr_el1);
|
||||
write_sysreg(tcb, tpidr_el0);
|
||||
|
||||
cpu_boot_params.cpu_ready_flag = 1;
|
||||
SP_SEV();
|
||||
|
||||
nx_idle_trampoline();
|
||||
}
|
||||
|
||||
@ -126,8 +149,6 @@ static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
|
||||
{
|
||||
uint64_t cpu_mpid = cpu_num;
|
||||
|
||||
uintptr_t flush_start;
|
||||
uintptr_t flush_end;
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
|
||||
@ -149,9 +170,7 @@ static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
|
||||
|
||||
cpu_boot_params.mpid = cpu_num;
|
||||
|
||||
flush_start = (uintptr_t)&cpu_boot_params;
|
||||
flush_end = flush_start + sizeof(cpu_boot_params);
|
||||
up_flush_dcache(flush_start, flush_end);
|
||||
flush_boot_params();
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_PSCI
|
||||
if (psci_cpu_on(cpu_mpid, (uint64_t)__start))
|
||||
@ -216,15 +235,16 @@ int up_cpu_start(int cpu)
|
||||
arm64_stack_color(g_cpu_idlestackalloc[cpu], SMP_STACK_SIZE);
|
||||
#endif
|
||||
|
||||
cpu_ready_flag = 0;
|
||||
cpu_boot_params.cpu_ready_flag = 0;
|
||||
arm64_start_cpu(cpu, (char *)g_cpu_idlestackalloc[cpu], SMP_STACK_SIZE,
|
||||
arm64_smp_init_top);
|
||||
|
||||
/* Waiting for this CPU to be boot complete */
|
||||
|
||||
while (!cpu_ready_flag)
|
||||
while (!cpu_boot_params.cpu_ready_flag)
|
||||
{
|
||||
local_delay();
|
||||
SP_WFE();
|
||||
flush_boot_params();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -237,7 +257,13 @@ void arm64_boot_secondary_c_routine(void)
|
||||
arm64_cpustart_t func;
|
||||
void *arg;
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_MPU
|
||||
arm64_mpu_init(false);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_MMU
|
||||
arm64_mmu_init(false);
|
||||
#endif
|
||||
|
||||
arm64_gic_secondary_init();
|
||||
|
||||
@ -263,7 +289,6 @@ void arm64_boot_secondary_c_routine(void)
|
||||
int arm64_smp_sgi_init(void)
|
||||
{
|
||||
irq_attach(SGI_CPU_PAUSE, arm64_pause_handler, 0);
|
||||
arm64_gic_irq_set_priority(SGI_CPU_PAUSE, IRQ_DEFAULT_PRIORITY, 0);
|
||||
up_enable_irq(SGI_CPU_PAUSE);
|
||||
|
||||
return 0;
|
||||
|
@ -359,6 +359,7 @@ void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_EL3
|
||||
case MODE_EL3:
|
||||
{
|
||||
sinfo("CurrentEL: MODE_EL3\n");
|
||||
@ -367,6 +368,7 @@ void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
|
||||
__asm__ volatile ("mrs %0, elr_el3" : "=r" (elr));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -145,15 +145,38 @@
|
||||
|
||||
#define GIC_INT_DEF_PRI_X4 0xa0a0a0a0
|
||||
|
||||
/* Register bit definitions */
|
||||
/* GICD_CTLR : Distributor Control Register
|
||||
*
|
||||
* [31](RO) RWP Register Write Pending:
|
||||
* -- 0 No register write in progress
|
||||
* -- 1 Register write in progress
|
||||
* [30:8] - Reserved -
|
||||
* [7](RW) E1NWF Enable 1 of N Wakeup Functionality 0
|
||||
* [6](RO) DS Disable Security status:
|
||||
* -- 0 The gicd_ctlr_ds signal was LOW when the GIC
|
||||
* exited reset. Therefore, the Distributor supports
|
||||
* two Security states and Non-secure accesses cannot
|
||||
* access and modify registers that control Group 0
|
||||
* interrupts.
|
||||
* -- 1 The gicd_ctlr_ds signal was HIGH when the GIC
|
||||
* exited reset. Therefore, the Distributor only supports
|
||||
* a single Security state and Non-secure accesses
|
||||
* can access and modify registers that control
|
||||
* Group 0 interrupts.
|
||||
* [5](RO) ARE_NS Affinity Routing Enable, Non-secure state
|
||||
* [4](RO) ARE_S Affinity Routing Enable, Secure state
|
||||
* [3] - Reserved -
|
||||
* [2](RW) EnableGrp1S Enable Secure Group 1 interrupts
|
||||
* [1](RW) EnableGrp1NS Enable Non-secure Group 1 interrupts
|
||||
* [0](RW) EnableGrp0 Enable Group 0 interrupts
|
||||
*/
|
||||
|
||||
/* GICD_CTLR Interrupt group definitions */
|
||||
#define GICD_CTLR_ENABLE_G0 0
|
||||
#define GICD_CTLR_ENABLE_G1NS 1
|
||||
#define GICD_CTLR_ENABLE_G1S 2
|
||||
#define GICD_CTRL_ARE_S 4
|
||||
#define GICD_CTRL_ARE_NS 5
|
||||
#define GICD_CTRL_NS 6
|
||||
#define GICD_CTRL_DS 6
|
||||
#define GICD_CGRL_E1NWF 7
|
||||
|
||||
/* GICD_CTLR Register write progress bit */
|
||||
|
@ -73,6 +73,32 @@ static unsigned long gic_rdists[CONFIG_SMP_NCPUS];
|
||||
* Private Functions
|
||||
***************************************************************************/
|
||||
|
||||
static inline void sys_set_bit(unsigned long addr, unsigned int bit)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = getreg32(addr);
|
||||
temp = temp | (BIT(bit));
|
||||
putreg32(temp, addr);
|
||||
}
|
||||
|
||||
static inline void sys_clear_bit(unsigned long addr, unsigned int bit)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = getreg32(addr);
|
||||
temp = temp & ~(BIT(bit));
|
||||
putreg32(temp, addr);
|
||||
}
|
||||
|
||||
static inline int sys_test_bit(unsigned long addr, unsigned int bit)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = getreg32(addr);
|
||||
return (temp & BIT(bit));
|
||||
}
|
||||
|
||||
static inline unsigned long gic_get_rdist(void)
|
||||
{
|
||||
return gic_rdists[this_cpu()];
|
||||
@ -170,7 +196,7 @@ void arm64_gic_irq_enable(unsigned int intid)
|
||||
if (GIC_IS_SPI(intid))
|
||||
{
|
||||
putreg64(MPIDR_TO_CORE(GET_MPIDR()),
|
||||
IROUTER(GET_DIST_BASE(intid), intid));
|
||||
IROUTER(GET_DIST_BASE(intid), intid));
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,16 +288,12 @@ int arm64_gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
|
||||
|
||||
static void gicv3_rdist_enable(unsigned long rdist)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
if (!(getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
temp = getreg32(rdist + GICR_WAKER);
|
||||
temp = temp & ~(BIT(GICR_WAKER_PS));
|
||||
putreg32(temp, rdist + GICR_WAKER);
|
||||
sys_clear_bit(rdist + GICR_WAKER, GICR_WAKER_PS);
|
||||
|
||||
while (getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA))
|
||||
{
|
||||
@ -361,17 +383,19 @@ static void gicv3_dist_init(void)
|
||||
putreg32(0, GICD_CTLR);
|
||||
gic_wait_rwp(GIC_SPI_INT_BASE);
|
||||
|
||||
#if 0
|
||||
#ifdef CONFIG_ARCH_SINGLE_SECURITY_STATE
|
||||
|
||||
/* Before configuration, we need to check whether
|
||||
* the GIC single security state mode is supported.
|
||||
* Make sure GICD_CTRL_NS is 1.
|
||||
*/
|
||||
|
||||
sys_set_bit(GICD_CTLR, GICD_CTRL_NS);
|
||||
__ASSERT(sys_test_bit(GICD_CTLR,
|
||||
GICD_CTRL_NS),
|
||||
"Current GIC does not support single security state");
|
||||
sys_set_bit(GICD_CTLR, GICD_CTRL_DS);
|
||||
if (!sys_test_bit(GICD_CTLR, GICD_CTRL_DS))
|
||||
{
|
||||
sinfo("Current GIC does not support single security state\n");
|
||||
PANIC();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default configuration of all SPIs */
|
||||
@ -416,15 +440,12 @@ static void gicv3_dist_init(void)
|
||||
putreg32(0, ICFGR(base, idx));
|
||||
}
|
||||
|
||||
/* Enable distributor with ARE */
|
||||
/* TODO: Some arrch64 Cortex-A core maybe without security state
|
||||
* it has different GIC configure with standard arrch64 A or R core
|
||||
*/
|
||||
|
||||
putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
|
||||
GICD_CTLR);
|
||||
#if 0
|
||||
|
||||
/* TODO: ARMv8-R support
|
||||
*
|
||||
* For GIC single security state(ARMv8-R), the config means
|
||||
#ifdef CONFIG_ARCH_SINGLE_SECURITY_STATE
|
||||
/* For GIC single security state(ARMv8-R), the config means
|
||||
* the GIC is under single security state which has
|
||||
* only two groups:
|
||||
* group 0 and group 1.
|
||||
@ -437,11 +458,20 @@ static void gicv3_dist_init(void)
|
||||
|
||||
putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS),
|
||||
GICD_CTLR);
|
||||
|
||||
#else
|
||||
/* Enable distributor with ARE */
|
||||
|
||||
putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
|
||||
GICD_CTLR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void up_enable_irq(int irq)
|
||||
{
|
||||
/* TODO: add common interface to set IRQ type for NuttX */
|
||||
|
||||
arm64_gic_irq_set_priority(irq, IRQ_DEFAULT_PRIORITY, IRQ_TYPE_LEVEL);
|
||||
arm64_gic_irq_enable(irq);
|
||||
}
|
||||
|
||||
@ -563,7 +593,7 @@ static int gic_validate_redist_version(void)
|
||||
ppi_nr = 0;
|
||||
}
|
||||
|
||||
sinfo("GICD_TYPER = 0x%"PRIx64"\n", typer);
|
||||
sinfo("GICR_TYPER = 0x%"PRIx64"\n", typer);
|
||||
sinfo("%d PPIs implemented\n", ppi_nr);
|
||||
sinfo("%sVLPI support, %sdirect LPI support\n", !has_vlpis ? "no " : "",
|
||||
!has_direct_lpi ? "no " : "");
|
||||
|
@ -176,10 +176,14 @@ primary_core:
|
||||
|
||||
cpu_boot:
|
||||
PRINT(cpu_boot, "- Ready to Boot CPU\r\n")
|
||||
/* Platform hook for highest EL */
|
||||
|
||||
bl arm64_el_init
|
||||
|
||||
switch_el:
|
||||
switch_el x0, 3f, 2f, 1f
|
||||
3:
|
||||
#ifdef CONFIG_ARCH_HAVE_EL3
|
||||
PRINT(switch_el3, "- Boot from EL3\r\n")
|
||||
|
||||
/* EL3 init */
|
||||
@ -191,7 +195,7 @@ switch_el:
|
||||
adr x0, switch_el
|
||||
bl arm64_boot_el3_get_next_el
|
||||
eret
|
||||
|
||||
#endif
|
||||
2:
|
||||
PRINT(switch_el2, "- Boot from EL2\r\n")
|
||||
|
||||
@ -243,10 +247,12 @@ __reset_prep_c:
|
||||
|
||||
switch_el x0, 3f, 2f, 1f
|
||||
3:
|
||||
#ifdef CONFIG_ARCH_HAVE_EL3
|
||||
/* Reinitialize SCTLR from scratch in EL3 */
|
||||
|
||||
ldr w0, =(SCTLR_EL3_RES1 | SCTLR_I_BIT | SCTLR_SA_BIT)
|
||||
msr sctlr_el3, x0
|
||||
#endif
|
||||
|
||||
/* Set SP_EL1 */
|
||||
|
||||
|
241
arch/arm64/src/common/arm64_mpu.c
Normal file
241
arch/arm64/src/common/arm64_mpu.c
Normal file
@ -0,0 +1,241 @@
|
||||
/***************************************************************************
|
||||
* arch/arm64/src/common/arm64_mpu.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* Included Files
|
||||
***************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <stdint.h>
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <arch/irq.h>
|
||||
#include <arch/chip/chip.h>
|
||||
|
||||
#include "arm64_arch.h"
|
||||
#include "arm64_internal.h"
|
||||
#include "arm64_fatal.h"
|
||||
#include "arm64_mpu.h"
|
||||
|
||||
/***************************************************************************
|
||||
* Pre-processor Definitions
|
||||
***************************************************************************/
|
||||
|
||||
#define __MPU_ASSERT(__cond, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(__cond)) \
|
||||
{ \
|
||||
sinfo(fmt, ## __VA_ARGS__); \
|
||||
PANIC(); \
|
||||
} \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
/* AArch64 Memory Model Feature Register 0
|
||||
* Provides information about the implemented memory model and memory
|
||||
* management support in AArch64 state.
|
||||
* See Arm Architecture Reference Manual Supplement
|
||||
* Armv8, for Armv8-R AArch64 architecture profile, G1.3.7
|
||||
*
|
||||
* ID_AA64MMFR0_MSA_FRAC, bits[55:52]
|
||||
* ID_AA64MMFR0_MSA, bits [51:48]
|
||||
*/
|
||||
|
||||
#define ID_AA64MMFR0_MSA_MSK (0xFFUL << 48U)
|
||||
#define ID_AA64MMFR0_PMSA_EN (0x1FUL << 48U)
|
||||
#define ID_AA64MMFR0_PMSA_VMSA_EN (0x2FUL << 48U)
|
||||
|
||||
/* Global status variable holding the number of HW MPU region indices, which
|
||||
* have been reserved by the MPU driver to program the static (fixed) memory
|
||||
* regions.
|
||||
*/
|
||||
|
||||
static uint8_t static_regions_num;
|
||||
|
||||
/***************************************************************************
|
||||
* Private Functions
|
||||
***************************************************************************/
|
||||
|
||||
/* Get the number of supported MPU regions. */
|
||||
|
||||
static inline uint8_t get_num_regions(void)
|
||||
{
|
||||
uint64_t type;
|
||||
|
||||
type = read_sysreg(mpuir_el1);
|
||||
type = type & MPU_IR_REGION_MSK;
|
||||
|
||||
return (uint8_t)type;
|
||||
}
|
||||
|
||||
/* ARM Core MPU Driver API Implementation for ARM MPU */
|
||||
|
||||
/**
|
||||
* @brief enable the MPU
|
||||
*/
|
||||
|
||||
void arm64_core_mpu_enable(void)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
val = read_sysreg(sctlr_el1);
|
||||
val |= SCTLR_M_BIT;
|
||||
write_sysreg(val, sctlr_el1);
|
||||
ARM64_DSB();
|
||||
ARM64_ISB();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief disable the MPU
|
||||
*/
|
||||
|
||||
void arm64_core_mpu_disable(void)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
/* Force any outstanding transfers to complete before disabling MPU */
|
||||
|
||||
ARM64_DMB();
|
||||
|
||||
val = read_sysreg(sctlr_el1);
|
||||
val &= ~SCTLR_M_BIT;
|
||||
write_sysreg(val, sctlr_el1);
|
||||
ARM64_DSB();
|
||||
ARM64_ISB();
|
||||
}
|
||||
|
||||
/* ARM MPU Driver Initial Setup
|
||||
*
|
||||
* Configure the cache-ability attributes for all the
|
||||
* different types of memory regions.
|
||||
*/
|
||||
|
||||
static void mpu_init(void)
|
||||
{
|
||||
/* Device region(s): Attribute-0
|
||||
* Flash region(s): Attribute-1
|
||||
* SRAM region(s): Attribute-2
|
||||
* SRAM no cache-able regions(s): Attribute-3
|
||||
*/
|
||||
|
||||
uint64_t mair = MPU_MAIR_ATTRS;
|
||||
|
||||
write_sysreg(mair, mair_el1);
|
||||
ARM64_DSB();
|
||||
ARM64_ISB();
|
||||
}
|
||||
|
||||
static inline void mpu_set_region(uint32_t rnr, uint64_t rbar,
|
||||
uint64_t rlar)
|
||||
{
|
||||
write_sysreg(rnr, prselr_el1);
|
||||
ARM64_DSB();
|
||||
write_sysreg(rbar, prbar_el1);
|
||||
write_sysreg(rlar, prlar_el1);
|
||||
ARM64_DSB();
|
||||
ARM64_ISB();
|
||||
}
|
||||
|
||||
/* This internal functions performs MPU region initialization. */
|
||||
|
||||
static void region_init(const uint32_t index,
|
||||
const struct arm64_mpu_region *region_conf)
|
||||
{
|
||||
uint64_t rbar = region_conf->base & MPU_RBAR_BASE_MSK;
|
||||
uint64_t rlar = (region_conf->limit - 1) & MPU_RLAR_LIMIT_MSK;
|
||||
|
||||
rbar |= region_conf->attr.rbar &
|
||||
(MPU_RBAR_XN_MSK | MPU_RBAR_AP_MSK | MPU_RBAR_SH_MSK);
|
||||
rlar |=
|
||||
(region_conf->attr.mair_idx <<
|
||||
MPU_RLAR_ATTRINDX_POS) & MPU_RLAR_ATTRINDX_MSK;
|
||||
rlar |= MPU_RLAR_EN_MSK;
|
||||
|
||||
mpu_set_region(index, rbar, rlar);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Public Functions
|
||||
***************************************************************************/
|
||||
|
||||
/* @brief MPU default configuration
|
||||
*
|
||||
* This function here provides the default configuration mechanism
|
||||
* for the Memory Protection Unit (MPU).
|
||||
*/
|
||||
|
||||
void arm64_mpu_init(bool is_primary_core)
|
||||
{
|
||||
uint64_t val;
|
||||
uint32_t r_index;
|
||||
|
||||
/* Current MPU code supports only EL1 */
|
||||
|
||||
__asm__ volatile ("mrs %0, CurrentEL" : "=r" (val));
|
||||
|
||||
__MPU_ASSERT(GET_EL(
|
||||
val) == MODE_EL1,
|
||||
"Exception level not EL1, MPU not enabled!\n");
|
||||
|
||||
/* Check whether the processor supports MPU */
|
||||
|
||||
val = read_sysreg(id_aa64mmfr0_el1) & ID_AA64MMFR0_MSA_MSK;
|
||||
if ((val != ID_AA64MMFR0_PMSA_EN) && (val != ID_AA64MMFR0_PMSA_VMSA_EN))
|
||||
{
|
||||
__MPU_ASSERT(0, "MPU not supported!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mpu_config.num_regions > get_num_regions())
|
||||
{
|
||||
/* Attempt to configure more MPU regions than
|
||||
* what is supported by hardware. As this operation
|
||||
* is executed during system (pre-kernel) initialization,
|
||||
* we want to ensure we can detect an attempt to
|
||||
* perform invalid configuration.
|
||||
*/
|
||||
|
||||
__MPU_ASSERT(0, "Request to configure: %u regions (supported: %u)\n",
|
||||
mpu_config.num_regions, get_num_regions());
|
||||
return;
|
||||
}
|
||||
|
||||
arm64_core_mpu_disable();
|
||||
|
||||
/* Architecture-specific configuration */
|
||||
|
||||
mpu_init();
|
||||
|
||||
/* Program fixed regions configured at SOC definition. */
|
||||
|
||||
for (r_index = 0U; r_index < mpu_config.num_regions; r_index++)
|
||||
{
|
||||
region_init(r_index, &mpu_config.mpu_regions[r_index]);
|
||||
}
|
||||
|
||||
/* Update the number of programmed MPU regions. */
|
||||
|
||||
static_regions_num = mpu_config.num_regions;
|
||||
|
||||
arm64_core_mpu_enable();
|
||||
}
|
301
arch/arm64/src/common/arm64_mpu.h
Normal file
301
arch/arm64/src/common/arm64_mpu.h
Normal file
@ -0,0 +1,301 @@
|
||||
/****************************************************************************
|
||||
* arch/arm64/src/common/arm64_mpu.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM64_SRC_COMMON_ARM64_MPU_H
|
||||
#define __ARCH_ARM64_SRC_COMMON_ARM64_MPU_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include "arm64_arch.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Convenience macros to represent the ARMv8-R64-specific configuration
|
||||
* for memory access permission and cache-ability attribution.
|
||||
*/
|
||||
|
||||
/* MPU MPUIR Register Definitions */
|
||||
|
||||
#define MPU_IR_REGION_MSK (0xFFU)
|
||||
|
||||
/* MPU RBAR Register attribute msk Definitions */
|
||||
|
||||
#define MPU_RBAR_BASE_POS 6U
|
||||
#define MPU_RBAR_BASE_MSK (0x3FFFFFFFFFFFFFFUL << MPU_RBAR_BASE_POS)
|
||||
#define MPU_RBAR_SH_POS 4U
|
||||
#define MPU_RBAR_SH_MSK (0x3UL << MPU_RBAR_SH_POS)
|
||||
#define MPU_RBAR_AP_POS 2U
|
||||
#define MPU_RBAR_AP_MSK (0x3UL << MPU_RBAR_AP_POS)
|
||||
|
||||
/* RBAR_EL1 XN */
|
||||
|
||||
#define MPU_RBAR_XN_POS 1U
|
||||
#define MPU_RBAR_XN_MSK (0x1UL << MPU_RBAR_XN_POS)
|
||||
|
||||
/* MPU PLBAR_ELx Register Definitions */
|
||||
|
||||
#define MPU_RLAR_LIMIT_POS 6U
|
||||
#define MPU_RLAR_LIMIT_MSK (0x3FFFFFFFFFFFFFFUL << MPU_RLAR_LIMIT_POS)
|
||||
#define MPU_RLAR_ATTRINDX_POS 1U
|
||||
#define MPU_RLAR_ATTRINDX_MSK (0x7UL << MPU_RLAR_ATTRINDX_POS)
|
||||
#define MPU_RLAR_EN_MSK (0x1UL)
|
||||
|
||||
/* PRBAR_ELx: Attribute flag for not-allowing
|
||||
* execution (eXecute Never)
|
||||
*/
|
||||
|
||||
#define NOT_EXEC MPU_RBAR_XN_MSK /* PRBAR_EL1 */
|
||||
|
||||
/* PRBAR_ELx: Attribute flag for access permissions
|
||||
* Privileged Read Write, Unprivileged No Access
|
||||
*/
|
||||
|
||||
#define P_RW_U_NA 0x0U
|
||||
#define P_RW_U_NA_MSK ((P_RW_U_NA << \
|
||||
MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
|
||||
|
||||
/* Privileged Read Write, Unprivileged Read Write */
|
||||
|
||||
#define P_RW_U_RW 0x1U
|
||||
#define P_RW_U_RW_MSK ((P_RW_U_RW << \
|
||||
MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
|
||||
|
||||
/* Privileged Read Only, Unprivileged No Access */
|
||||
|
||||
#define P_RO_U_NA 0x2U
|
||||
#define P_RO_U_NA_MSK ((P_RO_U_NA << \
|
||||
MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
|
||||
|
||||
/* Privileged Read Only, Unprivileged Read Only */
|
||||
|
||||
#define P_RO_U_RO 0x3U
|
||||
#define P_RO_U_RO_MSK ((P_RO_U_RO << \
|
||||
MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
|
||||
|
||||
/* PRBAR_ELx: Attribute flags for share-ability */
|
||||
|
||||
#define NON_SHAREABLE 0x0U
|
||||
#define NON_SHAREABLE_MSK \
|
||||
((NON_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
|
||||
#define OUTER_SHAREABLE 0x2U
|
||||
#define OUTER_SHAREABLE_MSK \
|
||||
((OUTER_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
|
||||
#define INNER_SHAREABLE 0x3U
|
||||
#define INNER_SHAREABLE_MSK \
|
||||
((INNER_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
|
||||
|
||||
/* MPIR_ELx Attribute flags for cache-ability */
|
||||
|
||||
/* Memory Attributes for Device Memory
|
||||
* 1.Gathering (G/nG)
|
||||
* Determines whether multiple accesses can be merged into a single
|
||||
* bus transaction.
|
||||
* nG: Number/size of accesses on the bus = number/size of accesses
|
||||
* in code.
|
||||
*
|
||||
* 2.Reordering (R/nR)
|
||||
* Determines whether accesses to the same device can be reordered.
|
||||
* nR: Accesses to the same IMPLEMENTATION DEFINED block size will
|
||||
* appear on the bus in program order.
|
||||
*
|
||||
* 3 Early Write Acknowledgment (E/nE)
|
||||
* Indicates to the memory system whether a buffer can send
|
||||
* acknowledgements.
|
||||
* nE: The response should come from the end slave, not buffering in
|
||||
* the interconnect.
|
||||
*/
|
||||
|
||||
#define DEVICE_nGnRnE 0x0U
|
||||
#define DEVICE_nGnRE 0x4U
|
||||
#define DEVICE_nGRE 0x8U
|
||||
#define DEVICE_GRE 0xCU
|
||||
|
||||
/* Read/Write Allocation Configurations for Cacheable Memory
|
||||
* R_NON_W_NON: Do not allocate Read/Write
|
||||
* R_NON_W_ALLOC: Do not allocate Read, Allocate Write
|
||||
* R_ALLOC_W_NON: Allocate Read, Do not allocate Write
|
||||
* R_ALLOC_W_ALLOC: Allocate Read/Write
|
||||
*/
|
||||
|
||||
#define R_NON_W_NON 0x0U
|
||||
#define R_NON_W_ALLOC 0x1U
|
||||
#define R_ALLOC_W_NON 0x2U
|
||||
#define R_ALLOC_W_ALLOC 0x3U
|
||||
|
||||
/* Memory Attributes for Normal Memory
|
||||
* NORMAL_O_WT_NT: Normal, Outer Write-through on-transient
|
||||
* NORMAL_O_WB_NT: Normal, Outer Write-back non-transient
|
||||
* NORMAL_O_NON_C: Normal, Outer Non-Cacheable
|
||||
* NORMAL_I_WT_NT: Normal, Inner Write-through non-transient
|
||||
* NORMAL_I_WB_NT: Normal, Inner Write-back non-transient
|
||||
* NORMAL_I_NON_C: Normal, Inner Non-Cacheable
|
||||
*/
|
||||
#define NORMAL_O_WT_NT 0x80U
|
||||
#define NORMAL_O_WB_NT 0xC0U
|
||||
#define NORMAL_O_NON_C 0x40U
|
||||
#define NORMAL_I_WT_NT 0x08U
|
||||
#define NORMAL_I_WB_NT 0x0CU
|
||||
#define NORMAL_I_NON_C 0x04U
|
||||
|
||||
/* Global MAIR configurations */
|
||||
|
||||
#define MPU_MAIR_INDEX_DEVICE 0U
|
||||
#define MPU_MAIR_ATTR_DEVICE (DEVICE_nGnRnE)
|
||||
|
||||
#define MPU_MAIR_INDEX_FLASH 1U
|
||||
#define MPU_MAIR_ATTR_FLASH \
|
||||
((NORMAL_O_WT_NT | (R_ALLOC_W_NON << 4)) | \
|
||||
(NORMAL_I_WT_NT | R_ALLOC_W_NON))
|
||||
|
||||
#define MPU_MAIR_INDEX_SRAM 2U
|
||||
#define MPU_MAIR_ATTR_SRAM \
|
||||
((NORMAL_O_WB_NT | (R_ALLOC_W_ALLOC << 4)) | \
|
||||
(NORMAL_I_WB_NT | R_ALLOC_W_ALLOC))
|
||||
|
||||
#define MPU_MAIR_INDEX_SRAM_NOCACHE 3U
|
||||
#define MPU_MAIR_ATTR_SRAM_NOCACHE \
|
||||
((NORMAL_O_NON_C | (R_NON_W_NON << 4)) | \
|
||||
(NORMAL_I_NON_C | R_NON_W_NON))
|
||||
|
||||
#define MPU_MAIR_ATTRS \
|
||||
((MPU_MAIR_ATTR_DEVICE << (MPU_MAIR_INDEX_DEVICE * 8)) | \
|
||||
(MPU_MAIR_ATTR_FLASH << (MPU_MAIR_INDEX_FLASH * 8)) | \
|
||||
(MPU_MAIR_ATTR_SRAM << (MPU_MAIR_INDEX_SRAM * 8)) | \
|
||||
(MPU_MAIR_ATTR_SRAM_NOCACHE << (MPU_MAIR_INDEX_SRAM_NOCACHE * 8)))
|
||||
|
||||
/* Some helper defines for common regions.
|
||||
*
|
||||
* Note that the ARMv8-R MPU architecture requires that the
|
||||
* enabled MPU regions are non-overlapping. Therefore, it is
|
||||
* recommended to use these helper defines only for configuring
|
||||
* fixed MPU regions at build-time.
|
||||
*/
|
||||
|
||||
#define REGION_DEVICE_ATTR \
|
||||
{ \
|
||||
/* AP, XN, SH */ \
|
||||
.rbar = NOT_EXEC | P_RW_U_NA_MSK | NON_SHAREABLE_MSK, \
|
||||
/* Cache-ability */ \
|
||||
.mair_idx = MPU_MAIR_INDEX_DEVICE, \
|
||||
}
|
||||
|
||||
#define REGION_RAM_ATTR \
|
||||
{ \
|
||||
/* AP, XN, SH */ \
|
||||
.rbar = NOT_EXEC | P_RW_U_NA_MSK | NON_SHAREABLE_MSK, \
|
||||
/* Cache-ability */ \
|
||||
.mair_idx = MPU_MAIR_INDEX_SRAM, \
|
||||
}
|
||||
|
||||
#define REGION_RAM_TEXT_ATTR \
|
||||
{ \
|
||||
/* AP, XN, SH */ \
|
||||
.rbar = P_RO_U_RO_MSK | NON_SHAREABLE_MSK, \
|
||||
/* Cache-ability */ \
|
||||
.mair_idx = MPU_MAIR_INDEX_SRAM, \
|
||||
}
|
||||
|
||||
#define REGION_RAM_RO_ATTR \
|
||||
{ \
|
||||
/* AP, XN, SH */ \
|
||||
.rbar = NOT_EXEC | P_RO_U_RO_MSK | NON_SHAREABLE_MSK, \
|
||||
/* Cache-ability */ \
|
||||
.mair_idx = MPU_MAIR_INDEX_SRAM, \
|
||||
}
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct arm64_mpu_region_attr
|
||||
{
|
||||
/* Attributes belonging to PRBAR */
|
||||
|
||||
uint8_t rbar : 5;
|
||||
|
||||
/* MAIR index for attribute indirection */
|
||||
|
||||
uint8_t mair_idx : 3;
|
||||
};
|
||||
|
||||
/* Region definition data structure */
|
||||
|
||||
struct arm64_mpu_region
|
||||
{
|
||||
/* Region Base Address */
|
||||
|
||||
uint64_t base;
|
||||
|
||||
/* Region limit Address */
|
||||
|
||||
uint64_t limit;
|
||||
|
||||
/* Region Name */
|
||||
|
||||
const char *name;
|
||||
|
||||
/* Region Attributes */
|
||||
|
||||
struct arm64_mpu_region_attr attr;
|
||||
};
|
||||
|
||||
/* MPU configuration data structure */
|
||||
|
||||
struct arm64_mpu_config
|
||||
{
|
||||
/* Number of regions */
|
||||
|
||||
uint32_t num_regions;
|
||||
|
||||
/* Regions */
|
||||
|
||||
const struct arm64_mpu_region *mpu_regions;
|
||||
};
|
||||
|
||||
#define MPU_REGION_ENTRY(_name, _base, _limit, _attr) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.base = _base, \
|
||||
.limit = _limit, \
|
||||
.attr = _attr, \
|
||||
}
|
||||
|
||||
/* Reference to the MPU configuration.
|
||||
*
|
||||
* This struct is defined and populated for each SoC (in the SoC definition),
|
||||
* and holds the build-time configuration information for the fixed MPU
|
||||
* regions enabled during kernel initialization.
|
||||
*/
|
||||
|
||||
extern const struct arm64_mpu_config mpu_config;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void arm64_mpu_init(bool is_primary_core);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_MPU_H */
|
@ -70,6 +70,26 @@ const struct arm_mmu_config mmu_config =
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm64_el_init
|
||||
*
|
||||
* Description:
|
||||
* The function called from arm64_head.S at very early stage for these
|
||||
* platform, it's use to:
|
||||
* - Handling special hardware initialize routine which is need to
|
||||
* run at high ELs
|
||||
* - Initialize system software such as hypervisor or security firmware
|
||||
* which is need to run at high ELs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void arm64_el_init(void)
|
||||
{
|
||||
write_sysreg(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, cntfrq_el0);
|
||||
|
||||
ARM64_ISB();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm64_chip_boot
|
||||
*
|
||||
|
@ -34,6 +34,12 @@
|
||||
#include "arm64_internal.h"
|
||||
#include "arm64_arch.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 62500000
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
@ -612,7 +612,6 @@ static int qemu_pl011_attach(struct uart_dev_s *dev)
|
||||
data = &sport->data;
|
||||
|
||||
ret = irq_attach(sport->irq_num, qemu_pl011_irq_handler, dev);
|
||||
arm64_gic_irq_set_priority(sport->irq_num, IRQ_TYPE_LEVEL, 0);
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user