diff --git a/CODEOWNERS b/CODEOWNERS index 932148aecba2..77afda033b6f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -18,6 +18,7 @@ /arch/arm/ @MaureenHelm @galak @ioannisg /arch/arm/core/cortex_m/cmse/ @ioannisg /arch/arm/include/cortex_m/cmse.h @ioannisg +/arch/arm/core/cortex_r/ @MaureenHelm @galak @ioannisg @bbolen /arch/common/ @andrewboie @ioannisg @andyross /arch/x86_64/ @andyross /soc/arc/snps_*/ @vonhust @ruuddw @@ -153,6 +154,8 @@ /drivers/serial/uart_liteuart.c @mateusz-holenko @kgugala @pgielda /drivers/serial/Kconfig.rtt @carlescufi @pkral78 /drivers/serial/uart_rtt.c @carlescufi @pkral78 +/drivers/serial/Kconfig.xlnx @wjliang +/drivers/serial/uart_xlnx_ps.c @wjliang /drivers/net/ @jukkar @tbursztyka /drivers/ptp_clock/ @jukkar /drivers/spi/ @tbursztyka @@ -162,6 +165,7 @@ /drivers/timer/altera_avalon_timer_hal.c @wentongwu /drivers/timer/riscv_machine_timer.c @nategraff-sifive @kgugala @pgielda /drivers/timer/litex_timer.c @mateusz-holenko @kgugala @pgielda +/drivers/timer/xlnx_psttc_timer.c @wjliang /drivers/usb/ @jfischer-phytec-iot @finikorg /drivers/usb/device/usb_dc_stm32.c @ydamigos @loicpoulain /drivers/i2c/i2c_ll_stm32* @ldts @ydamigos @@ -183,6 +187,8 @@ /dts/riscv/rv32m1* @MaureenHelm /dts/riscv/riscv32-fe310.dtsi @nategraff-sifive /dts/riscv/riscv32-litex-vexriscv.dtsi @mateusz-holenko @kgugala @pgielda +/dts/arm/armv7-r.dtsi @bbolen +/dts/arm/xilinx/ @bbolen /dts/xtensa/xtensa.dtsi @ydamigos /dts/bindings/ @galak /dts/bindings/can/ @alexanderwachter diff --git a/arch/arm/CMakeLists.txt b/arch/arm/CMakeLists.txt index 456150e1f8e6..b869b036e0d2 100644 --- a/arch/arm/CMakeLists.txt +++ b/arch/arm/CMakeLists.txt @@ -7,6 +7,7 @@ set(ARCH_FOR_cortex-m4 armv7e-m ) set(ARCH_FOR_cortex-m23 armv8-m.base ) set(ARCH_FOR_cortex-m33 armv8-m.main+dsp) set(ARCH_FOR_cortex-m33+nodsp armv8-m.main ) +set(ARCH_FOR_cortex-r4 armv7-r ) if(ARCH_FOR_${GCC_M_CPU}) set(ARCH_FLAG -march=${ARCH_FOR_${GCC_M_CPU}}) diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index 4e407e002d27..7ea2f9fd299f 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt @@ -33,3 +33,5 @@ add_subdirectory_ifdef(CONFIG_ARM_MPU cortex_m/mpu) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M_HAS_CMSE cortex_m/cmse) add_subdirectory_ifdef(CONFIG_ARM_SECURE_FIRMWARE cortex_m/tz) add_subdirectory_ifdef(CONFIG_ARM_NONSECURE_FIRMWARE cortex_m/tz) + +add_subdirectory_ifdef(CONFIG_CPU_CORTEX_R cortex_r) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index eec107f7212f..89d030bbab3e 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -29,6 +29,96 @@ config CPU_CORTEX_M help This option signifies the use of a CPU of the Cortex-M family. +config CPU_CORTEX_R + bool + select CPU_CORTEX + select HAS_FLASH_LOAD_OFFSET + help + This option signifies the use of a CPU of the Cortex-R family. + +config ISA_THUMB2 + bool + help + From: http://www.arm.com/products/processors/technologies/instruction-set-architectures.php + + Thumb-2 technology is the instruction set underlying the ARM Cortex + architecture which provides enhanced levels of performance, energy + efficiency, and code density for a wide range of embedded + applications. + + Thumb-2 technology builds on the success of Thumb, the innovative + high code density instruction set for ARM microprocessor cores, to + increase the power of the ARM microprocessor core available to + developers of low cost, high performance systems. + + The technology is backwards compatible with existing ARM and Thumb + solutions, while significantly extending the features available to + the Thumb instructions set. This allows more of the application to + benefit from the best in class code density of Thumb. + + For performance optimized code Thumb-2 technology uses 31 percent + less memory to reduce system cost, while providing up to 38 percent + higher performance than existing high density code, which can be used + to prolong battery-life or to enrich the product feature set. Thumb-2 + technology is featured in the processor, and in all ARMv7 + architecture-based processors. + +config ISA_ARM + bool + help + From: https://developer.arm.com/products/architecture/instruction-sets/a32-and-t32-instruction-sets + + A32 instructions, known as Arm instructions in pre-Armv8 architectures, + are 32 bits wide, and are aligned on 4-byte boundaries. A32 instructions + are supported by both A-profile and R-profile architectures. + + A32 was traditionally used in applications requiring the highest + performance, or for handling hardware exceptions such as interrupts and + processor start-up. Much of its functionality was subsumed into T32 with + the introduction of Thumb-2 technology. + +config DATA_ENDIANNESS_LITTLE + bool + default y if CPU_CORTEX + help + This is driven by the processor implementation, since it is fixed in + hardware. The board should set this value to 'n' if the data is + implemented as big endian. + +config STACK_ALIGN_DOUBLE_WORD + bool "Align stacks on double-words (8 octets)" + default y + help + This is needed to conform to AAPCS, the procedure call standard for + the ARM. It wastes stack space. The option also enforces alignment + of stack upon exception entry on Cortex-M3 and Cortex-M4 (ARMv7-M). + Note that for ARMv6-M, ARMv8-M, and Cortex-M7 MCUs stack alignment + on exception entry is enabled by default and it is not configurable. + +config RUNTIME_NMI + bool "Attach an NMI handler at runtime" + select REBOOT + help + The kernel provides a simple NMI handler that simply hangs in a tight + loop if triggered. This fills the requirement that there must be an + NMI handler installed when the CPU boots. If a custom handler is + needed, enable this option and attach it via _NmiHandlerSet(). + +config FAULT_DUMP + int "Fault dump level" + default 2 + range 0 2 + help + Different levels for display information when a fault occurs. + + 2: The default. Display specific and verbose information. Consumes + the most memory (long strings). + + 1: Display general and short information. Consumes less memory + (short strings). + + 0: Off. + config BUILTIN_STACK_GUARD bool "Thread Stack Guards based on built-in ARM stack limit checking" depends on CPU_CORTEX_M_HAS_SPLIM @@ -185,6 +275,7 @@ endchoice endmenu source "arch/arm/core/cortex_m/Kconfig" +source "arch/arm/core/cortex_r/Kconfig" source "arch/arm/core/cortex_m/mpu/Kconfig" diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 17ebd61bf56a..bd3516ecd073 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -75,34 +75,6 @@ config CPU_CORTEX_M7 if CPU_CORTEX_M -config ISA_THUMB2 - bool - # Omit prompt to signify "hidden" option - help - From: http://www.arm.com/products/processors/technologies/instruction-set-architectures.php - - Thumb-2 technology is the instruction set underlying the ARM Cortex - architecture which provides enhanced levels of performance, energy - efficiency, and code density for a wide range of embedded - applications. - - Thumb-2 technology builds on the success of Thumb, the innovative - high code density instruction set for ARM microprocessor cores, to - increase the power of the ARM microprocessor core available to - developers of low cost, high performance systems. - - The technology is backwards compatible with existing ARM and Thumb - solutions, while significantly extending the features available to - the Thumb instructions set. This allows more of the application to - benefit from the best in class code density of Thumb. - - For performance optimized code Thumb-2 technology uses 31 percent - less memory to reduce system cost, while providing up to 38 percent - higher performance than existing high density code, which can be used - to prolong battery-life or to enrich the product feature set. Thumb-2 - technology is featured in the processor, and in all ARMv7 - architecture-based processors. - config CPU_CORTEX_M_HAS_SYSTICK bool # Omit prompt to signify "hidden" option @@ -275,48 +247,6 @@ config LDREX_STREX_AVAILABLE bool default y -config DATA_ENDIANNESS_LITTLE - bool - default y - help - This is driven by the processor implementation, since it is fixed in - hardware. The board should set this value to 'n' if the data is - implemented as big endian. - -config STACK_ALIGN_DOUBLE_WORD - bool "Align stacks on double-words (8 octets)" - default y - help - This is needed to conform to AAPCS, the procedure call standard for - the ARM. It wastes stack space. The option also enforces alignment - of stack upon exception entry on Cortex-M3 and Cortex-M4 (ARMv7-M). - Note that for ARMv6-M, ARMv8-M, and Cortex-M7 MCUs stack alignment - on exception entry is enabled by default and it is not configurable. - -config RUNTIME_NMI - bool "Attach an NMI handler at runtime" - select REBOOT - help - The kernel provides a simple NMI handler that simply hangs in a tight - loop if triggered. This fills the requirement that there must be an - NMI handler installed when the CPU boots. If a custom handler is - needed, enable this option and attach it via _NmiHandlerSet(). - -config FAULT_DUMP - int "Fault dump level" - default 2 - range 0 2 - help - Different levels for display information when a fault occurs. - - 2: The default. Display specific and verbose information. Consumes - the most memory (long strings). - - 1: Display general and short information. Consumes less memory - (short strings). - - 0: Off. - config XIP default y diff --git a/arch/arm/core/cortex_r/CMakeLists.txt b/arch/arm/core/cortex_r/CMakeLists.txt new file mode 100644 index 000000000000..a1154a3efb94 --- /dev/null +++ b/arch/arm/core/cortex_r/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + vector_table.S + reset.S + fault.c + reboot.c + stacks.c + ) diff --git a/arch/arm/core/cortex_r/Kconfig b/arch/arm/core/cortex_r/Kconfig new file mode 100644 index 000000000000..526f03e1aba5 --- /dev/null +++ b/arch/arm/core/cortex_r/Kconfig @@ -0,0 +1,98 @@ +# Kconfig - ARM Cortex-R platform configuration options + +# +# Copyright (c) 2018 Marvell +# Copyright (c) 2018 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# NOTE: We have the specific core implementations first and outside of the +# if CPU_CORTEX_R block so that SoCs can select which core they are using +# without having to select all the options related to that core. Everything +# else is captured inside the if CPU_CORTEX_R block so they are not exposed +# if one selects a different ARM Cortex Family (Cortex-A or Cortex-M) + + +config CPU_CORTEX_R4 + bool + select CPU_CORTEX_R + select ARMV7_R + select ARMV7_R_FP if CPU_HAS_FPU + help + This option signifies the use of a Cortex-R4 CPU + +config CPU_CORTEX_R5 + bool + select CPU_CORTEX_R + select ARMV7_R + select ARMV7_R_FP if CPU_HAS_FPU + help + This option signifies the use of a Cortex-R5 CPU + +if CPU_CORTEX_R + +config ARMV7_R + bool + select ATOMIC_OPERATIONS_BUILTIN + select ISA_ARM + help + This option signifies the use of an ARMv7-R processor + implementation. + + From https://developer.arm.com/products/architecture/cpu-architecture/r-profile: + The Armv7-R architecture implements a traditional Arm architecture with + multiple modes and supports a Protected Memory System Architecture + (PMSA) based on a Memory Protection Unit (MPU). It supports the Arm (32) + and Thumb (T32) instruction sets. + +config ARMV7_R_FP + bool + depends on ARMV7_R + help + This option signifies the use of an ARMv7-R processor + implementation supporting the Floating-Point Extension. + +config ARMV7_EXCEPTION_STACK_SIZE + int "Undefined Instruction and Abort stack size (in bytes)" + default 256 + help + This option specifies the size of the stack used by the undefined + instruction and data abort exception handlers. + +config ARMV7_FIQ_STACK_SIZE + int "FIQ stack size (in bytes)" + default 256 + help + This option specifies the size of the stack used by the FIQ handler. + +config ARMV7_SVC_STACK_SIZE + int "SVC stack size (in bytes)" + default 512 + help + This option specifies the size of the stack used by the SVC handler. + +config ARMV7_SYS_STACK_SIZE + int "SYS stack size (in bytes)" + default 1024 + help + This option specifies the size of the stack used by the system mode. + +menu "ARM Cortex-R options" + depends on CPU_CORTEX_R + +config RUNTIME_NMI + default y + +config LDREX_STREX_AVAILABLE + default y + +config GEN_ISR_TABLES + default y + +config GEN_IRQ_VECTOR_TABLE + default n + +endmenu + +endif # CPU_CORTEX_R diff --git a/arch/arm/core/cortex_r/fault.c b/arch/arm/core/cortex_r/fault.c new file mode 100644 index 000000000000..7ae32eb3b02a --- /dev/null +++ b/arch/arm/core/cortex_r/fault.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/** + * + * @brief Fault handler + * + * This routine is called when fatal error conditions are detected by hardware + * and is responsible only for reporting the error. Once reported, it then + * invokes the user provided routine _SysFatalErrorHandler() which is + * responsible for implementing the error handling policy. + * + * This is a stub for more exception handling code to be added later. + */ +void _Fault(z_arch_esf_t *esf, u32_t exc_return) +{ + z_arm_fatal_error(K_ERR_CPU_EXCEPTION, esf); +} + +void z_FaultInit(void) +{ +} diff --git a/arch/arm/core/cortex_r/reboot.c b/arch/arm/core/cortex_r/reboot.c new file mode 100644 index 000000000000..1d38faf421a2 --- /dev/null +++ b/arch/arm/core/cortex_r/reboot.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-R System Control Block interface + */ + +#include +#include +#include + +/** + * + * @brief Reset the system + * + * This routine resets the processor. + * + * @return N/A + */ + +void __weak sys_arch_reboot(int type) +{ + ARG_UNUSED(type); +} diff --git a/arch/arm/core/cortex_r/reset.S b/arch/arm/core/cortex_r/reset.S new file mode 100644 index 000000000000..51388c9f11dd --- /dev/null +++ b/arch/arm/core/cortex_r/reset.S @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Reset handler + * + * Reset handler that prepares the system for running C code. + */ + +#include +#include +#include +#include +#include "vector_table.h" + +_ASM_FILE_PROLOGUE + +GTEXT(__reset) +GDATA(_interrupt_stack) +GDATA(_svc_stack) +GDATA(_sys_stack) +GDATA(_fiq_stack) +GDATA(_abort_stack) +GDATA(_undef_stack) + +#define STACK_MARGIN 4 + + +/** + * + * @brief Reset vector + * + * Ran when the system comes out of reset. The processor is in thread mode with + * privileged level. At this point, the main stack pointer (MSP) is already + * pointing to a valid area in SRAM. + * + * When these steps are completed, jump to _PrepC(), which will finish setting + * up the system for running C code. + * + * @return N/A + */ +SECTION_SUBSEC_FUNC(TEXT, _reset_section, __reset) +SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov r4, #0 + mov r5, #0 + mov r6, #0 + mov r7, #0 + mov r8, #0 + mov r9, #0 + mov r10, #0 + mov r11, #0 + mov r12, #0 + mov r14, #0 + + /* lock interrupts: will get unlocked when switch to main task */ + cpsid if + + /* Setup FIQ stack */ + msr CPSR_c, #(MODE_FIQ | I_BIT | F_BIT) + ldr sp, =(_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE - STACK_MARGIN) + + /* Setup IRQ stack */ + msr CPSR_c, #(MODE_IRQ | I_BIT | F_BIT) + ldr sp, =(_interrupt_stack + CONFIG_ISR_STACK_SIZE - STACK_MARGIN) + + /* Setup data abort stack */ + msr CPSR_c, #(MODE_ABT | I_BIT | F_BIT) + ldr sp, =(_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE - \ + STACK_MARGIN) + + /* Setup undefined mode stack */ + msr CPSR_c, #(MODE_UDF | I_BIT | F_BIT) + ldr sp, =(_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE - \ + STACK_MARGIN) + + /* Setup SVC mode stack */ + msr CPSR_c, #(MODE_SVC | I_BIT | F_BIT) + ldr sp, =(_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE - STACK_MARGIN) + + /* Setup System mode stack */ + msr CPSR_c, #(MODE_SYS | I_BIT | F_BIT) + ldr sp, =(_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE - STACK_MARGIN) + + /* Setup system control register */ + mrc p15, 0, r0, c1, c0, 0 /* SCTLR */ + bic r0, r0, #HIVECS /* Exception vectors from 0-0x1c */ + mcr p15, 0, r0, c1, c0, 0 + +#if defined(CONFIG_WDOG_INIT) + /* board-specific watchdog initialization is necessary */ + bl _WdogInit +#endif + + b _PrepC diff --git a/arch/arm/core/cortex_r/stacks.c b/arch/arm/core/cortex_r/stacks.c new file mode 100644 index 000000000000..445b246dfe0b --- /dev/null +++ b/arch/arm/core/cortex_r/stacks.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +K_THREAD_STACK_DEFINE(_fiq_stack, CONFIG_ARMV7_FIQ_STACK_SIZE); +K_THREAD_STACK_DEFINE(_abort_stack, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); +K_THREAD_STACK_DEFINE(_undef_stack, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); +K_THREAD_STACK_DEFINE(_svc_stack, CONFIG_ARMV7_SVC_STACK_SIZE); +K_THREAD_STACK_DEFINE(_sys_stack, CONFIG_ARMV7_SYS_STACK_SIZE); + +#if defined(CONFIG_INIT_STACKS) +void init_stacks(void) +{ + memset(_fiq_stack, 0xAA, CONFIG_ARMV7_FIQ_STACK_SIZE); + memset(_svc_stack, 0xAA, CONFIG_ARMV7_SVC_STACK_SIZE); + memset(_abort_stack, 0xAA, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); + memset(_undef_stack, 0xAA, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); + memset(&_interrupt_stack, 0xAA, CONFIG_ISR_STACK_SIZE); +} +#endif diff --git a/arch/arm/core/cortex_r/vector_table.S b/arch/arm/core/cortex_r/vector_table.S new file mode 100644 index 000000000000..71ed41949c95 --- /dev/null +++ b/arch/arm/core/cortex_r/vector_table.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 Marvell + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Populated vector table in ROM + */ + +#include +#include +#include "vector_table.h" + +_ASM_FILE_PROLOGUE + +SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) + ldr pc, =__reset /* offset 0 */ + ldr pc, =__undef_instruction /* undef instruction offset 4 */ + ldr pc, =__svc /* svc offset 8 */ + ldr pc, =__prefetch_abort /* prefetch abort offset 0xc */ + ldr pc, =__data_abort /* data abort offset 0x10 */ + nop /* offset 0x14 */ + ldr pc, =_isr_wrapper /* IRQ offset 0x18 */ + ldr pc, =__nmi /* FIQ offset 0x1c */ diff --git a/arch/arm/core/cortex_r/vector_table.h b/arch/arm/core/cortex_r/vector_table.h new file mode 100644 index 000000000000..f10e0f82dd98 --- /dev/null +++ b/arch/arm/core/cortex_r/vector_table.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Marvell + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Definitions for the boot vector table + * + * + * Definitions for the boot vector table. + * + * System exception handler names all have the same format: + * + * __ + * + * No other symbol has the same format, so they are easy to spot. + */ + +#ifndef _VECTOR_TABLE__H_ +#define _VECTOR_TABLE__H_ + +#ifdef _ASMLANGUAGE + +#include +#include +#include + +GTEXT(__start) +GTEXT(_vector_table) + +GTEXT(__nmi) +GTEXT(__undef_instruction) +GTEXT(__svc) +GTEXT(__prefetch_abort) +GTEXT(__data_abort) + +GTEXT(__pendsv) +GTEXT(__reserved) + +GTEXT(_PrepC) +GTEXT(_isr_wrapper) + +#else + +extern void *_vector_table[]; + +#endif /* _ASMLANGUAGE */ + +#endif /* _VECTOR_TABLE__H_ */ diff --git a/arch/arm/core/cpu_idle.S b/arch/arm/core/cpu_idle.S index 30279cb71333..bcd359210b9e 100644 --- a/arch/arm/core/cpu_idle.S +++ b/arch/arm/core/cpu_idle.S @@ -24,12 +24,14 @@ GTEXT(z_CpuIdleInit) GTEXT(k_cpu_idle) GTEXT(k_cpu_atomic_idle) +#if defined(CONFIG_CPU_CORTEX_M) #define _SCB_SCR 0xE000ED10 #define _SCB_SCR_SEVONPEND (1 << 4) #define _SCB_SCR_SLEEPDEEP (1 << 2) #define _SCB_SCR_SLEEPONEXIT (1 << 1) #define _SCR_INIT_BITS _SCB_SCR_SEVONPEND +#endif /** * @@ -46,9 +48,11 @@ GTEXT(k_cpu_atomic_idle) */ SECTION_FUNC(TEXT, z_CpuIdleInit) +#if defined(CONFIG_CPU_CORTEX_M) ldr r1, =_SCB_SCR movs.n r2, #_SCR_INIT_BITS str r2, [r1] +#endif bx lr /** @@ -79,7 +83,8 @@ SECTION_FUNC(TEXT, k_cpu_idle) #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ #endif /* CONFIG_TRACING */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) cpsie i #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) /* clear BASEPRI so wfi is awakened by incoming interrupts */ @@ -140,7 +145,8 @@ SECTION_FUNC(TEXT, k_cpu_atomic_idle) /* r0: interrupt mask from caller */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) /* No BASEPRI, call wfe directly (SEVONPEND set in z_CpuIdleInit()) */ wfe diff --git a/arch/arm/core/exc_exit.S b/arch/arm/core/exc_exit.S index d074ce622df4..5247103359cc 100644 --- a/arch/arm/core/exc_exit.S +++ b/arch/arm/core/exc_exit.S @@ -24,6 +24,9 @@ _ASM_FILE_PROLOGUE GTEXT(z_ExcExit) GTEXT(_IntExit) GDATA(_kernel) +#if defined(CONFIG_CPU_CORTEX_R) +GTEXT(__pendsv) +#endif /** * @@ -66,6 +69,9 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, _IntExit) */ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_ExcExit) +#if defined(CONFIG_CPU_CORTEX_R) + push {r0, lr} +#endif #ifdef CONFIG_PREEMPT_ENABLED ldr r0, =_kernel @@ -76,10 +82,16 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_ExcExit) cmp r0, r1 beq _EXIT_EXC +#if defined(CONFIG_CPU_CORTEX_M) /* context switch required, pend the PendSV exception */ ldr r1, =_SCS_ICSR ldr r2, =_SCS_ICSR_PENDSV str r2, [r1] +#elif defined(CONFIG_CPU_CORTEX_R) + push {r0, lr} + bl __pendsv + pop {r0, lr} +#endif _ExcExitWithGdbStub: @@ -96,4 +108,31 @@ _EXIT_EXC: pop {r0, lr} #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ #endif /* CONFIG_STACK_SENTINEL */ + +#if defined(CONFIG_CPU_CORTEX_M) bx lr +#elif defined(CONFIG_CPU_CORTEX_R) + /* + * r0-r3 are either the values from the thread before it was switched out + * or they are the args to _new_thread for a new thread + */ + pop {r0, lr} + push {r4, r5} + + cmp r0, #RET_FROM_SVC + cps #MODE_SYS + ldmia sp!, {r0-r5} + beq _svc_exit + + cps #MODE_IRQ + b _exc_exit + +_svc_exit: + cps #MODE_SVC + +_exc_exit: + mov r12, r4 + mov lr, r5 + pop {r4, r5} + movs pc, lr +#endif diff --git a/arch/arm/core/fault_s.S b/arch/arm/core/fault_s.S index 472fd01da7f7..785f49d01a7a 100644 --- a/arch/arm/core/fault_s.S +++ b/arch/arm/core/fault_s.S @@ -30,6 +30,10 @@ GTEXT(__usage_fault) GTEXT(__secure_fault) #endif /* CONFIG_ARM_SECURE_FIRMWARE*/ GTEXT(__debug_monitor) +#elif defined(CONFIG_ARMV7_R) +GTEXT(__undef_instruction) +GTEXT(__prefetch_abort) +GTEXT(__data_abort) #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -70,6 +74,10 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__usage_fault) SECTION_SUBSEC_FUNC(TEXT,__fault,__secure_fault) #endif /* CONFIG_ARM_SECURE_FIRMWARE */ SECTION_SUBSEC_FUNC(TEXT,__fault,__debug_monitor) +#elif defined(CONFIG_ARMV7_R) +SECTION_SUBSEC_FUNC(TEXT,__fault,__undef_instruction) +SECTION_SUBSEC_FUNC(TEXT,__fault,__prefetch_abort) +SECTION_SUBSEC_FUNC(TEXT,__fault,__data_abort) #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -127,6 +135,12 @@ _s_stack_frame_msp: mrs r0, MSP _s_stack_frame_endif: #endif /* CONFIG_ARM_SECURE_FIRMWARE || CONFIG_ARM_NONSECURE_FIRMWARE */ +#elif defined(CONFIG_ARMV7_R) + /* + * Pass null for the esf to _Fault for now. A future PR will add better + * exception debug for Cortex-R that subsumes what esf provides. + */ + mov r0, #0 #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -146,6 +160,11 @@ _s_stack_frame_endif: push {r0, lr} bl _Fault +#if defined(CONFIG_CPU_CORTEX_M) pop {r0, pc} +#elif defined(CONFIG_CPU_CORTEX_R) + pop {r0, lr} + subs pc, lr, #8 +#endif .end diff --git a/arch/arm/core/irq_manage.c b/arch/arm/core/irq_manage.c index dfbea870127e..a4ebcc5faeee 100644 --- a/arch/arm/core/irq_manage.c +++ b/arch/arm/core/irq_manage.c @@ -16,7 +16,12 @@ #include #include +#if defined(CONFIG_CPU_CORTEX_M) #include +#elif defined(CONFIG_CPU_CORTEX_R) +#include +#include +#endif #include #include #include @@ -27,6 +32,7 @@ extern void __reserved(void); +#if defined(CONFIG_CPU_CORTEX_M) #define NUM_IRQS_PER_REG 32 #define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG) #define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG) @@ -115,6 +121,74 @@ void z_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) NVIC_SetPriority((IRQn_Type)irq, prio); } +#elif defined(CONFIG_CPU_CORTEX_R) + +/** + * + * @brief Enable an interrupt line + * + * Enable the interrupt. After this call, the CPU will receive interrupts for + * the specified . + * + * @return N/A + */ +void z_arch_irq_enable(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + irq_enable_next_level(dev, (irq >> 8) - 1); +} + +/** + * + * @brief Disable an interrupt line + * + * Disable an interrupt line. After this call, the CPU will stop receiving + * interrupts for the specified . + * + * @return N/A + */ +void z_arch_irq_disable(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + irq_disable_next_level(dev, (irq >> 8) - 1); +} + +/** + * @brief Return IRQ enable state + * + * @param irq IRQ line + * @return interrupt enable state, true or false + */ +int z_arch_irq_is_enabled(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + return irq_is_enabled_next_level(dev); +} + +/** + * @internal + * + * @brief Set an interrupt's priority + * + * The priority is verified if ASSERT_ON is enabled. The maximum number + * of priority levels is a little complex, as there are some hardware + * priority levels which are reserved: three for various types of exceptions, + * and possibly one additional to support zero latency interrupts. + * + * @return N/A + */ +void z_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) +{ + struct device *dev = _sw_isr_table[0].arg; + + irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); +} + +#endif + /** * * @brief Spurious interrupt handler @@ -144,7 +218,8 @@ void z_irq_spurious(void *unused) #ifdef CONFIG_SYS_POWER_MANAGEMENT void _arch_isr_direct_pm(void) { -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) unsigned int key; /* irq_lock() does what we wan for this CPU */ @@ -166,7 +241,8 @@ void _arch_isr_direct_pm(void) z_sys_power_save_idle_exit(idle_val); } -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) irq_unlock(key); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) __asm__ volatile("cpsie i" : : : "memory"); diff --git a/arch/arm/core/isr_wrapper.S b/arch/arm/core/isr_wrapper.S index 026b2ea6eab9..5b05e8ad6c24 100644 --- a/arch/arm/core/isr_wrapper.S +++ b/arch/arm/core/isr_wrapper.S @@ -41,7 +41,24 @@ GTEXT(_IntExit) */ SECTION_FUNC(TEXT, _isr_wrapper) +#if defined(CONFIG_CPU_CORTEX_M) push {r0,lr} /* r0, lr are now the first items on the stack */ +#elif defined(CONFIG_CPU_CORTEX_R) + /* + * Save away r0-r3 from previous context to the process stack since they + * are clobbered here. Also, save away lr since we may swap processes + * and return to a different thread. + */ + push {r4, r5} + mov r4, r12 + sub r5, lr, #4 + + cps #MODE_SYS + stmdb sp!, {r0-r5} + cps #MODE_IRQ + + pop {r4, r5} +#endif #ifdef CONFIG_EXECUTION_BENCHMARKING bl read_timer_start_of_isr @@ -82,6 +99,13 @@ _idle_state_cleared: /* clear kernel idle state */ strne r1, [r2, #_kernel_offset_to_idle] blne z_sys_power_save_idle_exit +#elif defined(CONFIG_ARMV7_R) + beq _idle_state_cleared + movs r1, #0 + /* clear kernel idle state */ + str r1, [r2, #_kernel_offset_to_idle] + bl z_sys_power_save_idle_exit +_idle_state_cleared: #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -89,7 +113,9 @@ _idle_state_cleared: cpsie i /* re-enable interrupts (PRIMASK = 0) */ #endif +#if defined(CONFIG_CPU_CORTEX_M) mrs r0, IPSR /* get exception number */ +#endif #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) ldr r1, =16 subs r0, r1 /* get IRQ number */ @@ -97,6 +123,12 @@ _idle_state_cleared: #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) sub r0, r0, #16 /* get IRQ number */ lsl r0, r0, #3 /* table is 8-byte wide */ +#elif defined(CONFIG_ARMV7_R) + /* + * Cortex-R only has one IRQ line so the main handler will be at + * offset 0 of the table. + */ + mov r0, #0 #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -128,12 +160,23 @@ _idle_state_cleared: mov lr, r3 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) pop {r0, lr} +#elif defined(CONFIG_ARMV7_R) + /* + * r0,lr were saved on the process stack since a swap could + * happen. exc_exit will handle getting those values back + * from the process stack to return to the correct location + * so there is no need to do anything here. + */ #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ +#if defined(CONFIG_CPU_CORTEX_R) + mov r0, #RET_FROM_IRQ +#endif + /* Use 'bx' instead of 'b' because 'bx' can jump further, and use * 'bx' instead of 'blx' because exception return is done in * _IntExit() */ - ldr r0, =_IntExit - bx r0 + ldr r1, =_IntExit + bx r1 diff --git a/arch/arm/core/offsets/offsets.c b/arch/arm/core/offsets/offsets.c index a7747c1796d5..b58945c07b62 100644 --- a/arch/arm/core/offsets/offsets.c +++ b/arch/arm/core/offsets/offsets.c @@ -65,6 +65,10 @@ GEN_OFFSET_SYM(_callee_saved_t, v6); GEN_OFFSET_SYM(_callee_saved_t, v7); GEN_OFFSET_SYM(_callee_saved_t, v8); GEN_OFFSET_SYM(_callee_saved_t, psp); +#if defined(CONFIG_CPU_CORTEX_R) +GEN_OFFSET_SYM(_callee_saved_t, spsr); +GEN_OFFSET_SYM(_callee_saved_t, lr); +#endif /* size of the entire preempt registers structure */ diff --git a/arch/arm/core/prep_c.c b/arch/arm/core/prep_c.c index 83e97d0817c4..7154d53aab29 100644 --- a/arch/arm/core/prep_c.c +++ b/arch/arm/core/prep_c.c @@ -21,7 +21,12 @@ #include #include #include +#include +#if defined(CONFIG_CPU_CORTEX_M) #include +#elif defined(CONFIG_ARMV7_R) +#include +#endif #if defined(__GNUC__) /* @@ -150,9 +155,6 @@ extern FUNC_NORETURN void z_cstart(void); * * @return N/A */ - -extern void z_IntLibInit(void); - #ifdef CONFIG_BOOT_TIME_MEASUREMENT extern u64_t __start_time_stamp; #endif @@ -162,6 +164,9 @@ void _PrepC(void) enable_floating_point(); z_bss_zero(); z_data_copy(); +#if defined(CONFIG_ARMV7_R) && defined(CONFIG_INIT_STACKS) + init_stacks(); +#endif #ifdef CONFIG_BOOT_TIME_MEASUREMENT __start_time_stamp = 0U; #endif diff --git a/arch/arm/core/swap.c b/arch/arm/core/swap.c index 26792c3620b6..7759b1017fb7 100644 --- a/arch/arm/core/swap.c +++ b/arch/arm/core/swap.c @@ -55,11 +55,16 @@ int __swap(int key) _current->arch.basepri = key; _current->arch.swap_return_value = _k_neg_eagain; +#if defined(CONFIG_CPU_CORTEX_M) /* set pending bit to make sure we will take a PendSV exception */ SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; /* clear mask or enable all irqs to take a pendsv */ irq_unlock(0); +#elif defined(CONFIG_CPU_CORTEX_R) + cortex_r_svc(); + irq_unlock(key); +#endif /* Context switch is performed here. Returning implies the * thread has been context-switched-in again. diff --git a/arch/arm/core/swap_helper.S b/arch/arm/core/swap_helper.S index 52549a710e5d..636d95dc8c4b 100644 --- a/arch/arm/core/swap_helper.S +++ b/arch/arm/core/swap_helper.S @@ -64,7 +64,9 @@ SECTION_FUNC(TEXT, __pendsv) add r0, r2 /* save callee-saved + psp in thread */ +#if defined(CONFIG_CPU_CORTEX_M) mrs ip, PSP +#endif #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) /* Store current r4-r7 */ @@ -99,6 +101,10 @@ out_fp_active: out_fp_endif: str r0, [r2, #_thread_offset_to_mode] #endif /* CONFIG_FP_SHARING */ +#elif defined(CONFIG_ARMV7_R) + /* Store rest of process context */ + mrs r12, SPSR + stm r0, {r4-r12,sp,lr}^ #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -110,6 +116,11 @@ out_fp_endif: movs.n r0, #_EXC_IRQ_DEFAULT_PRIO msr BASEPRI, r0 isb /* Make the effect of disabling interrupts be realized immediately */ +#elif defined(CONFIG_ARMV7_R) + /* + * Interrupts are still disabled from __swap so empty clause + * here to avoid the preprocessor error below + */ #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -121,8 +132,10 @@ out_fp_endif: * to pend PendSV have been taken with the current kernel * state and this is what we're handling currently. */ +#if defined(CONFIG_CPU_CORTEX_M) ldr v4, =_SCS_ICSR ldr v3, =_SCS_ICSR_UNPENDSV +#endif /* _kernel is still in r1 */ @@ -141,7 +154,9 @@ out_fp_endif: */ /* _SCS_ICSR is still in v4 and _SCS_ICSR_UNPENDSV in v3 */ +#if defined(CONFIG_CPU_CORTEX_M) str v3, [v4, #0] +#endif /* Restore previous interrupt disable state (irq_lock key) */ #if (defined(CONFIG_CPU_CORTEX_M0PLUS) || defined(CONFIG_CPU_CORTEX_M0)) && \ @@ -158,7 +173,7 @@ out_fp_endif: str r3, [r4] #else ldr r0, [r2, #_thread_offset_to_basepri] - movs.n r3, #0 + movs r3, #0 str r3, [r2, #_thread_offset_to_basepri] #endif @@ -254,6 +269,19 @@ in_fp_endif: /* load callee-saved + psp from thread */ add r0, r2, #_thread_offset_to_callee_saved ldmia r0, {v1-v8, ip} +#elif defined(CONFIG_ARMV7_R) +_thread_irq_disabled: + /* load _kernel into r1 and current k_thread into r2 */ + ldr r1, =_kernel + ldr r2, [r1, #_kernel_offset_to_current] + + /* addr of callee-saved regs in thread in r0 */ + ldr r0, =_thread_offset_to_callee_saved + add r0, r2 + + /* restore r4-r12 for incoming thread, plus system sp and lr */ + ldm r0, {r4-r12,sp,lr}^ + msr SPSR_fsxc, r12 #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -264,7 +292,9 @@ in_fp_endif: msr PSPLIM, r0 #endif /* CONFIG_BUILTIN_STACK_GUARD */ +#if defined(CONFIG_CPU_CORTEX_M) msr PSP, ip +#endif #ifdef CONFIG_BUILTIN_STACK_GUARD /* r2 contains k_thread */ @@ -486,7 +516,80 @@ valid_syscall_id: bx lr #endif +#elif defined(CONFIG_ARMV7_R) +SECTION_FUNC(TEXT, __svc) + /* + * Switch to system mode to store r0-r3 to the process stack pointer. + * Save r12 and the lr as we will be swapping in another process and + * returning to a different location. + */ + push {r4, r5} + mov r4, r12 + mov r5, lr + + cps #MODE_SYS + stmdb sp!, {r0-r5} + cps #MODE_SVC + + pop {r4, r5} + + /* Get SVC number */ + mrs r0, spsr + tst r0, #0x20 + + ldreq r1, [lr, #-4] + biceq r1, #0xff000000 + beq demux + + ldr r1, [lr, #-2] + bic r1, #0xff00 + + /* + * grab service call number: + * 0: context switch + * 1: irq_offload (if configured) + * 2: kernel panic or oops (software generated fatal exception) + * Planned implementation of system calls for memory protection will + * expand this case. + */ +demux: + cmp r1, #_SVC_CALL_CONTEXT_SWITCH + beq _context_switch + + cmp r1, #_SVC_CALL_RUNTIME_EXCEPT + beq _oops + +#if CONFIG_IRQ_OFFLOAD + push {r0, lr} + blx z_irq_do_offload /* call C routine which executes the offload */ + pop {r0, lr} + + /* exception return is done in _IntExit() */ + mov r0, #RET_FROM_SVC + b _IntExit +#endif + +_context_switch: + /* handler mode exit, to PendSV */ + push {r0, lr} + bl __pendsv + pop {r0, lr} + + mov r0, #RET_FROM_SVC + b _IntExit + +_oops: + push {r0, lr} + blx z_do_kernel_oops + pop {r0, lr} + cpsie i + movs pc, lr + +GTEXT(cortex_r_svc) +SECTION_FUNC(TEXT, cortex_r_svc) + svc #0 + bx lr + #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - diff --git a/arch/arm/core/thread.c b/arch/arm/core/thread.c index 742482abea5f..42812a62366f 100644 --- a/arch/arm/core/thread.c +++ b/arch/arm/core/thread.c @@ -138,8 +138,10 @@ void z_new_thread(struct k_thread *thread, k_thread_stack_t *stack, pInitCtx->basic.pc = (u32_t)z_thread_entry; #endif +#if defined(CONFIG_CPU_CORTEX_M) /* force ARM mode by clearing LSB of address */ pInitCtx->basic.pc &= 0xfffffffe; +#endif pInitCtx->basic.a1 = (u32_t)pEntry; pInitCtx->basic.a2 = (u32_t)parameter1; @@ -149,6 +151,11 @@ void z_new_thread(struct k_thread *thread, k_thread_stack_t *stack, 0x01000000UL; /* clear all, thumb bit is 1, even if RO */ thread->callee_saved.psp = (u32_t)pInitCtx; +#if defined(CONFIG_CPU_CORTEX_R) + pInitCtx->basic.lr = (u32_t)pInitCtx->basic.pc; + thread->callee_saved.spsr = A_BIT | T_BIT | MODE_SYS; + thread->callee_saved.lr = (u32_t)pInitCtx->basic.pc; +#endif thread->arch.basepri = 0; #if defined(CONFIG_USERSPACE) || defined(CONFIG_FP_SHARING) diff --git a/arch/arm/include/cortex_r/exc.h b/arch/arm/include/cortex_r/exc.h new file mode 100644 index 000000000000..be1a06e061a5 --- /dev/null +++ b/arch/arm/include/cortex_r/exc.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Exception/interrupt context helpers for Cortex-R CPUs + * + * Exception/interrupt context helpers. + */ + +#ifndef _ARM_CORTEXR_ISR__H_ +#define _ARM_CORTEXR_ISR__H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _ASMLANGUAGE + +/* nothing */ + +#else + +#include + +#ifdef CONFIG_IRQ_OFFLOAD +extern volatile irq_offload_routine_t offload_routine; +#endif + +/** + * + * @brief Find out if running in an ISR context + * + * Check the CPSR mode bits to see if we are in IRQ or FIQ mode + * + * @return 1 if in ISR, 0 if not. + */ +static ALWAYS_INLINE bool z_IsInIsr(void) +{ + unsigned int status; + + __asm__ volatile( + " mrs %0, cpsr" + : "=r" (status) : : "memory", "cc"); + status &= MODE_MASK; + + return (status == MODE_FIQ) || (status == MODE_IRQ); +} + +/** + * @brief Setup system exceptions + * + * Enable fault exceptions. + * + * @return N/A + */ +static ALWAYS_INLINE void z_ExcSetup(void) +{ +} + +/** + * @brief Clear Fault exceptions + * + * Clear out exceptions for Mem, Bus, Usage and Hard Faults + * + * @return N/A + */ +static ALWAYS_INLINE void z_clearfaults(void) +{ +} + +extern void cortex_r_svc(void); + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _ARM_CORTEXRM_ISR__H_ */ diff --git a/arch/arm/include/cortex_r/stack.h b/arch/arm/include/cortex_r/stack.h new file mode 100644 index 000000000000..200da41be934 --- /dev/null +++ b/arch/arm/include/cortex_r/stack.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Stack helpers for Cortex-R CPUs + * + * Stack helper functions. + */ + +#ifndef _ARM_CORTEXR_STACK__H_ +#define _ARM_CORTEXR_STACK__H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _ASMLANGUAGE + +/* nothing */ + +#else + +extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE); + +extern void init_stacks(void); + +/** + * + * @brief Setup interrupt stack + * + * On Cortex-R, the interrupt stack is set up by reset.S + * + * @return N/A + */ +static ALWAYS_INLINE void z_InterruptStackSetup(void) +{ +} + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ARM_CORTEXR_STACK__H_ */ diff --git a/arch/arm/include/kernel_arch_data.h b/arch/arm/include/kernel_arch_data.h index f025bcd17475..37d822fa37cd 100644 --- a/arch/arm/include/kernel_arch_data.h +++ b/arch/arm/include/kernel_arch_data.h @@ -52,6 +52,9 @@ typedef struct __basic_sf _basic_sf_t; #ifdef CONFIG_CPU_CORTEX_M #include #include +#elif defined(CONFIG_CPU_CORTEX_R) +#include +#include #endif #ifndef _ASMLANGUAGE diff --git a/arch/arm/include/kernel_arch_func.h b/arch/arm/include/kernel_arch_func.h index b6e63f73aa22..26ed8ac6d432 100644 --- a/arch/arm/include/kernel_arch_func.h +++ b/arch/arm/include/kernel_arch_func.h @@ -109,8 +109,12 @@ z_arch_switch_to_main_thread(struct k_thread *main_thread, */ __asm__ volatile ( "mov r0, %0 \n\t" /* Store _main in R0 */ +#if defined(CONFIG_CPU_CORTEX_M) "msr PSP, %1 \n\t" /* __set_PSP(start_of_main_stack) */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#endif + +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) "cpsie i \n\t" /* __enable_irq() */ #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) "cpsie if \n\t" /* __enable_irq(); __enable_fault_irq() */ diff --git a/arch/arm/include/kernel_arch_thread.h b/arch/arm/include/kernel_arch_thread.h index f8691e85b56b..a359e8f816f0 100644 --- a/arch/arm/include/kernel_arch_thread.h +++ b/arch/arm/include/kernel_arch_thread.h @@ -31,7 +31,13 @@ struct _callee_saved { u32_t v6; /* r9 */ u32_t v7; /* r10 */ u32_t v8; /* r11 */ +#if defined(CONFIG_CPU_CORTEX_R) + u32_t spsr;/* r12 */ u32_t psp; /* r13 */ + u32_t lr; /* r14 */ +#else + u32_t psp; /* r13 */ +#endif }; typedef struct _callee_saved _callee_saved_t; diff --git a/boards/arm/qemu_cortex_r5/Kconfig.board b/boards/arm/qemu_cortex_r5/Kconfig.board new file mode 100644 index 000000000000..9e8fb7fc8dec --- /dev/null +++ b/boards/arm/qemu_cortex_r5/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_QEMU_CORTEX_R5 + bool "Cortex-R5 Emulation (QEMU)" + depends on SOC_XILINX_ZYNQMP diff --git a/boards/arm/qemu_cortex_r5/Kconfig.defconfig b/boards/arm/qemu_cortex_r5/Kconfig.defconfig new file mode 100644 index 000000000000..c3aa118d4ac1 --- /dev/null +++ b/boards/arm/qemu_cortex_r5/Kconfig.defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_QEMU_CORTEX_R5 + +config BUILD_OUTPUT_BIN + default n + +config BOARD + default "qemu_cortex_r5" + +endif # BOARD_QEMU_CORTEX_R5 diff --git a/boards/arm/qemu_cortex_r5/board.cmake b/boards/arm/qemu_cortex_r5/board.cmake new file mode 100644 index 000000000000..d87553cf65c3 --- /dev/null +++ b/boards/arm/qemu_cortex_r5/board.cmake @@ -0,0 +1,20 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set(EMU_PLATFORM qemu) +set(QEMU_ARCH aarch64) + +set(QEMU_CPU_TYPE_${ARCH} cortex-r5) +set(QEMU_FLAGS_${ARCH} + -nographic + -machine xlnx-zcu102 + -global xlnx,zynqmp.boot-cpu="rpu-cpu[0]" + -smp 6 + ) + +set(QEMU_KERNEL_OPTION + "-device;loader,file=$,cpu-num=4" + ) + +board_set_debugger_ifnset(qemu) diff --git a/boards/arm/qemu_cortex_r5/qemu_cortex_r5.dts b/boards/arm/qemu_cortex_r5/qemu_cortex_r5.dts new file mode 100644 index 000000000000..8deeab3ba3b2 --- /dev/null +++ b/boards/arm/qemu_cortex_r5/qemu_cortex_r5.dts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include + +/ { + model = "QEMU Cortex-R5"; + compatible = "xlnx,zynqmp-qemu"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + clock-frequency = <99999901>; +}; + +&ttc0 { + status = "okay"; + clock-frequency = <100000000>; +}; diff --git a/boards/arm/qemu_cortex_r5/qemu_cortex_r5.yaml b/boards/arm/qemu_cortex_r5/qemu_cortex_r5.yaml new file mode 100644 index 000000000000..d673b6c52ed7 --- /dev/null +++ b/boards/arm/qemu_cortex_r5/qemu_cortex_r5.yaml @@ -0,0 +1,48 @@ +identifier: qemu_cortex_r5 +name: QEMU Emulation for Cortex-R5 +type: qemu +simulation: qemu +arch: arm +toolchain: + - zephyr + - gccarmemb + - xtools +ram: 64 +flash: 256 +testing: + default: false + ignore_tags: + - base64 + - benchmark + - clib + - cmsis_rtos_v1 + - cmsis_rtos_v1_philosopher + - cmsis_rtos_v1_synchronization + - cmsis_rtos_v2 + - cmsis_rtos_v2_philosopher + - cmsis_rtos_v2_synchronization + - cpp + - crypto + - drivers + - external + - fdtable + - gen_inc_file + - interrupt + - introduction + - json + - libc + - logging + - kernel + - memory_protection + - net + - posix + - rbtree + - ring_buffer + - shell + - sleep + - test_framework + - timeutils + - timer + - userspace + - util + - xip diff --git a/boards/arm/qemu_cortex_r5/qemu_cortex_r5_defconfig b/boards/arm/qemu_cortex_r5/qemu_cortex_r5_defconfig new file mode 100644 index 000000000000..6033c3c99e65 --- /dev/null +++ b/boards/arm/qemu_cortex_r5/qemu_cortex_r5_defconfig @@ -0,0 +1,19 @@ +CONFIG_ARM=y +CONFIG_SOC_XILINX_ZYNQMP=y +CONFIG_BOARD_QEMU_CORTEX_R5=y +CONFIG_XIP=n + +CONFIG_ISR_STACK_SIZE=512 +CONFIG_THREAD_STACK_INFO=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable serial port +CONFIG_UART_XLNX_PS=y + +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/cmake/emu/qemu.cmake b/cmake/emu/qemu.cmake index d68d52df45fa..441f7f334c35 100644 --- a/cmake/emu/qemu.cmake +++ b/cmake/emu/qemu.cmake @@ -2,6 +2,8 @@ if("${ARCH}" STREQUAL "x86") set_ifndef(QEMU_binary_suffix i386) +elseif(DEFINED QEMU_ARCH) + set_ifndef(QEMU_binary_suffix ${QEMU_ARCH}) else() set_ifndef(QEMU_binary_suffix ${ARCH}) endif() diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index 8ae884301e7c..df8a3934bd48 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -22,6 +22,10 @@ if("${ARCH}" STREQUAL "arm") else() set(GCC_M_CPU cortex-m33+nodsp) endif() + elseif(CONFIG_CPU_CORTEX_R4) + set(GCC_M_CPU cortex-r4) + elseif(CONFIG_CPU_CORTEX_R5) + set(GCC_M_CPU cortex-r5) else() message(FATAL_ERROR "Expected CONFIG_CPU_CORTEX_x to be defined") endif() diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index e73d0fff2c84..96fab705736e 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_ARCV2_INTERRUPT_UNIT arcv2_irq_unit.c) +zephyr_sources_ifdef(CONFIG_GIC gic-400.c) zephyr_sources_ifdef(CONFIG_IOAPIC ioapic_intr.c) zephyr_sources_ifdef(CONFIG_LOAPIC loapic_intr.c system_apic.c) zephyr_sources_ifdef(CONFIG_LOAPIC_SPURIOUS_VECTOR loapic_spurious.S) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 0fc1b16ff3ed..b67e53d8bd11 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -147,6 +147,13 @@ config DW_ICTL_INIT_PRIORITY help DesignWare Interrupt Controller initialization priority. +config GIC + bool "ARM Generic Interrupt Controller (GIC)" + depends on CPU_CORTEX_R + help + The ARM Generic Interrupt Controller works with Cortex-A and + Cortex-R processors. + source "drivers/interrupt_controller/Kconfig.stm32" source "drivers/interrupt_controller/Kconfig.multilevel" diff --git a/drivers/interrupt_controller/gic-400.c b/drivers/interrupt_controller/gic-400.c new file mode 100644 index 000000000000..774aedb5118a --- /dev/null +++ b/drivers/interrupt_controller/gic-400.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2018 Marvell + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_GIC_DIST_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_0 +#define DT_GIC_CPU_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_1 + +#define GICD_CTRL (DT_GIC_DIST_BASE + 0) +#define GICD_TYPER (DT_GIC_DIST_BASE + 0x4) +#define GICD_IIDR (DT_GIC_DIST_BASE + 0x8) +#define GICD_IGROUPRn (DT_GIC_DIST_BASE + 0x80) +#define GICD_ISENABLERn (DT_GIC_DIST_BASE + 0x100) +#define GICD_ICENABLERn (DT_GIC_DIST_BASE + 0x180) +#define GICD_ISPENDRn (DT_GIC_DIST_BASE + 0x200) +#define GICD_ICPENDRn (DT_GIC_DIST_BASE + 0x280) +#define GICD_ISACTIVERn (DT_GIC_DIST_BASE + 0x300) +#define GICD_ICACTIVERn (DT_GIC_DIST_BASE + 0x380) +#define GICD_IPRIORITYRn (DT_GIC_DIST_BASE + 0x400) +#define GICD_ITARGETSRn (DT_GIC_DIST_BASE + 0x800) +#define GICD_ICFGRn (DT_GIC_DIST_BASE + 0xc00) +#define GICD_SGIR (DT_GIC_DIST_BASE + 0xf00) + +#define GICC_CTRL (DT_GIC_CPU_BASE + 0x00) +#define GICC_PMR (DT_GIC_CPU_BASE + 0x04) +#define GICC_BPR (DT_GIC_CPU_BASE + 0x08) +#define GICC_IAR (DT_GIC_CPU_BASE + 0x0c) +#define GICC_EOIR (DT_GIC_CPU_BASE + 0x10) + +#define GICC_ENABLE 3 +#define GICC_DIS_BYPASS_MASK 0x1e0 + +#define NO_GIC_INT_PENDING 1023 + +#define GIC_SPI_INT_BASE 32 + +#define GIC_INT_TYPE_MASK 0x3 +#define GIC_INT_TYPE_EDGE (1 << 1) + +struct gic_ictl_config { + u32_t isr_table_offset; +}; + +static void gic_dist_init(void) +{ + unsigned int gic_irqs, i; + + gic_irqs = sys_read32(GICD_TYPER) & 0x1f; + gic_irqs = (gic_irqs + 1) * 32; + if (gic_irqs > 1020) + gic_irqs = 1020; + + /* + * Disable the forwarding of pending interrupts + * from the Distributor to the CPU interfaces + */ + sys_write32(0, GICD_CTRL); + + /* + * Set all global interrupts to this CPU only. + */ + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) + sys_write32(0x01010101, GICD_ITARGETSRn + i); + + /* + * Set all global interrupts to be level triggered, active low. + */ + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) + sys_write32(0, GICD_ICFGRn + i / 4); + + /* Set priority on all global interrupts. */ + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) + sys_write32(0, GICD_IPRIORITYRn + i); + + /* Set all interrupts to group 0 */ + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) + sys_write32(0, GICD_IGROUPRn + i / 8); + + /* + * Disable all interrupts. Leave the PPI and SGIs alone + * as these enables are banked registers. + */ + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) { + sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8); + sys_write32(0xffffffff, GICD_ICENABLERn + i / 8); + } + + /* + * Enable the forwarding of pending interrupts + * from the Distributor to the CPU interfaces + */ + sys_write32(1, GICD_CTRL); +} + +static void gic_cpu_init(void) +{ + int i; + u32_t val; + + /* + * Deal with the banked PPI and SGI interrupts - disable all + * PPI interrupts, ensure all SGI interrupts are enabled. + */ + sys_write32(0xffffffff, GICD_ICACTIVERn); + sys_write32(0xffff0000, GICD_ICENABLERn); + sys_write32(0x0000ffff, GICD_ISENABLERn); + + /* + * Set priority on PPI and SGI interrupts + */ + for (i = 0; i < 32; i += 4) + sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i); + + sys_write32(0xf0, GICC_PMR); + + /* + * Enable interrupts and signal them using the IRQ signal. + */ + val = sys_read32(GICC_CTRL); + val &= GICC_DIS_BYPASS_MASK; + val |= GICC_ENABLE; + sys_write32(val, GICC_CTRL); +} + +static void gic_irq_enable(struct device *dev, unsigned int irq) +{ + int int_grp, int_off; + + irq += GIC_SPI_INT_BASE; + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4)); +} + +static void gic_irq_disable(struct device *dev, unsigned int irq) +{ + int int_grp, int_off; + + irq += GIC_SPI_INT_BASE; + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4)); +} + +static unsigned int gic_irq_get_state(struct device *dev) +{ + return 1; +} + +static void gic_irq_set_priority(struct device *dev, + unsigned int irq, unsigned int prio, u32_t flags) +{ + int int_grp, int_off; + u8_t val; + + irq += GIC_SPI_INT_BASE; + + /* Set priority */ + sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq); + + /* Set interrupt type */ + int_grp = irq / 4; + int_off = (irq % 4) * 2; + + val = sys_read8(GICD_ICFGRn + int_grp); + val &= ~(GIC_INT_TYPE_MASK << int_off); + if (flags & IRQ_TYPE_EDGE) + val |= (GIC_INT_TYPE_EDGE << int_off); + sys_write8(val, GICD_ICFGRn + int_grp); +} + +static void gic_isr(void *arg) +{ + struct device *dev = arg; + const struct gic_ictl_config *cfg = dev->config->config_info; + void (*gic_isr_handle)(void *); + int irq, isr_offset; + + irq = sys_read32(GICC_IAR); + irq &= 0x3ff; + + if (irq == NO_GIC_INT_PENDING) { + printk("gic: Invalid interrupt\n"); + return; + } + + isr_offset = cfg->isr_table_offset + irq - GIC_SPI_INT_BASE; + + gic_isr_handle = _sw_isr_table[isr_offset].isr; + if (gic_isr_handle) + gic_isr_handle(_sw_isr_table[isr_offset].arg); + else + printk("gic: no handler found for int %d\n", irq); + + /* set to inactive */ + sys_write32(irq, GICC_EOIR); +} + +static int gic_init(struct device *unused); +static const struct irq_next_level_api gic_apis = { + .intr_enable = gic_irq_enable, + .intr_disable = gic_irq_disable, + .intr_get_state = gic_irq_get_state, + .intr_set_priority = gic_irq_set_priority, +}; + +static const struct gic_ictl_config gic_config = { + .isr_table_offset = CONFIG_2ND_LVL_ISR_TBL_OFFSET, +}; + +DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL, + gic_init, NULL, &gic_config, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &gic_apis); + +/** + * + * @brief Initialize the GIC device driver + * + * + * @return N/A + */ +#define GIC_PARENT_IRQ 0 +#define GIC_PARENT_IRQ_PRI 0 +#define GIC_PARENT_IRQ_FLAGS 0 +static int gic_init(struct device *unused) +{ + IRQ_CONNECT(GIC_PARENT_IRQ, GIC_PARENT_IRQ_PRI, gic_isr, + DEVICE_GET(arm_gic), GIC_PARENT_IRQ_FLAGS); + + /* Init of Distributor interface registers */ + gic_dist_init(); + + /* Init CPU interface registers */ + gic_cpu_init(); + + return 0; +} diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 6f38414ec7e2..ea509aa1827b 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -30,6 +30,7 @@ zephyr_library_sources_if_kconfig(uart_pl011.c) zephyr_library_sources_if_kconfig(uart_rv32m1_lpuart.c) zephyr_library_sources_if_kconfig(uart_liteuart.c) zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c) +zephyr_library_sources_if_kconfig(uart_xlnx_ps.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a93fcd98c16c..8a47de290e96 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -127,4 +127,6 @@ source "drivers/serial/Kconfig.litex" source "drivers/serial/Kconfig.rtt" +source "drivers/serial/Kconfig.xlnx" + endif # SERIAL diff --git a/drivers/serial/Kconfig.xlnx b/drivers/serial/Kconfig.xlnx new file mode 100644 index 000000000000..8a8a21cb7d91 --- /dev/null +++ b/drivers/serial/Kconfig.xlnx @@ -0,0 +1,13 @@ +# Kconfig - Xilinx UART configuration +# +# Copyright (c) 2018 Xilinx Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig UART_XLNX_PS + bool "Xilinx serial driver for MPSoC" + depends on SOC_XILINX_ZYNQMP + select SERIAL_HAS_DRIVER + help + This option enables the UART driver for Xilinx MPSoC platforms. diff --git a/drivers/serial/uart_xlnx_ps.c b/drivers/serial/uart_xlnx_ps.c new file mode 100644 index 000000000000..2ee326d0fbdd --- /dev/null +++ b/drivers/serial/uart_xlnx_ps.c @@ -0,0 +1,709 @@ +/* uart_xlnx_ps.c - Xilinx Zynq family serial driver */ + +/* + * Copyright (c) 2018 Xilinx, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Xilnx Zynq Family Serial Driver + * + * This is the driver for the Xilinx Zynq family cadence serial device. + * + * Before individual UART port can be used, uart_xlnx_ps_init() has to be + * called to setup the port. + * + * - the following macro for the number of bytes between register addresses: + * + * UART_REG_ADDR_INTERVAL + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define XUARTPS_CR_OFFSET 0x0000U /**< Control Register [8:0] */ +#define XUARTPS_MR_OFFSET 0x0004U /**< Mode Register [9:0] */ +#define XUARTPS_IER_OFFSET 0x0008U /**< Interrupt Enable [12:0] */ +#define XUARTPS_IDR_OFFSET 0x000CU /**< Interrupt Disable [12:0] */ +#define XUARTPS_IMR_OFFSET 0x0010U /**< Interrupt Mask [12:0] */ +#define XUARTPS_ISR_OFFSET 0x0014U /**< Interrupt Status [12:0]*/ +#define XUARTPS_BAUDGEN_OFFSET 0x0018U /**< Baud Rate Generator [15:0] */ +#define XUARTPS_RXTOUT_OFFSET 0x001CU /**< RX Timeout [7:0] */ +#define XUARTPS_RXWM_OFFSET 0x0020U /**< RX FIFO Trigger Level [5:0] */ +#define XUARTPS_MODEMCR_OFFSET 0x0024U /**< Modem Control [5:0] */ +#define XUARTPS_MODEMSR_OFFSET 0x0028U /**< Modem Status [8:0] */ +#define XUARTPS_SR_OFFSET 0x002CU /**< Channel Status [14:0] */ +#define XUARTPS_FIFO_OFFSET 0x0030U /**< FIFO [7:0] */ +#define XUARTPS_BAUDDIV_OFFSET 0x0034U /**< Baud Rate Divider [7:0] */ +#define XUARTPS_FLOWDEL_OFFSET 0x0038U /**< Flow Delay [5:0] */ +#define XUARTPS_TXWM_OFFSET 0x0044U /**< TX FIFO Trigger Level [5:0] */ +#define XUARTPS_RXBS_OFFSET 0x0048U /**< RX FIFO Byte Status [11:0] */ + +/* Control Register Bits Definition */ +#define XUARTPS_CR_STOPBRK 0x00000100U /**< Stop transmission of break */ +#define XUARTPS_CR_STARTBRK 0x00000080U /**< Set break */ +#define XUARTPS_CR_TORST 0x00000040U /**< RX timeout counter restart */ +#define XUARTPS_CR_TX_DIS 0x00000020U /**< TX disabled. */ +#define XUARTPS_CR_TX_EN 0x00000010U /**< TX enabled */ +#define XUARTPS_CR_RX_DIS 0x00000008U /**< RX disabled. */ +#define XUARTPS_CR_RX_EN 0x00000004U /**< RX enabled */ +#define XUARTPS_CR_EN_DIS_MASK 0x0000003CU /**< Enable/disable Mask */ +#define XUARTPS_CR_TXRST 0x00000002U /**< TX logic reset */ +#define XUARTPS_CR_RXRST 0x00000001U /**< RX logic reset */ + +/* Mode Register Bits Definition */ +#define XUARTPS_MR_CCLK 0x00000400U /**< Input clock select */ +#define XUARTPS_MR_CHMODE_R_LOOP 0x00000300U /**< Remote loopback mode */ +#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200U /**< Local loopback mode */ +#define XUARTPS_MR_CHMODE_ECHO 0x00000100U /**< Auto echo mode */ +#define XUARTPS_MR_CHMODE_NORM 0x00000000U /**< Normal mode */ +#define XUARTPS_MR_CHMODE_SHIFT 8U /**< Mode shift */ +#define XUARTPS_MR_CHMODE_MASK 0x00000300U /**< Mode mask */ +#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080U /**< 2 stop bits */ +#define XUARTPS_MR_STOPMODE_1_5_BIT 0x00000040U /**< 1.5 stop bits */ +#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000U /**< 1 stop bit */ +#define XUARTPS_MR_STOPMODE_SHIFT 6U /**< Stop bits shift */ +#define XUARTPS_MR_STOPMODE_MASK 0x000000A0U /**< Stop bits mask */ +#define XUARTPS_MR_PARITY_NONE 0x00000020U /**< No parity mode */ +#define XUARTPS_MR_PARITY_MARK 0x00000018U /**< Mark parity mode */ +#define XUARTPS_MR_PARITY_SPACE 0x00000010U /**< Space parity mode */ +#define XUARTPS_MR_PARITY_ODD 0x00000008U /**< Odd parity mode */ +#define XUARTPS_MR_PARITY_EVEN 0x00000000U /**< Even parity mode */ +#define XUARTPS_MR_PARITY_SHIFT 3U /**< Parity setting shift */ +#define XUARTPS_MR_PARITY_MASK 0x00000038U /**< Parity mask */ +#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006U /**< 6 bits data */ +#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004U /**< 7 bits data */ +#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000U /**< 8 bits data */ +#define XUARTPS_MR_CHARLEN_SHIFT 1U /**< Data Length shift */ +#define XUARTPS_MR_CHARLEN_MASK 0x00000006U /**< Data length mask */ +#define XUARTPS_MR_CLKSEL 0x00000001U /**< Input clock select */ + +/* Interrupt Register Bits Definition */ +#define XUARTPS_IXR_RBRK 0x00002000U /**< Rx FIFO break detect interrupt */ +#define XUARTPS_IXR_TOVR 0x00001000U /**< Tx FIFO Overflow interrupt */ +#define XUARTPS_IXR_TNFUL 0x00000800U /**< Tx FIFO Nearly Full interrupt */ +#define XUARTPS_IXR_TTRIG 0x00000400U /**< Tx Trig interrupt */ +#define XUARTPS_IXR_DMS 0x00000200U /**< Modem status change interrupt */ +#define XUARTPS_IXR_TOUT 0x00000100U /**< Timeout error interrupt */ +#define XUARTPS_IXR_PARITY 0x00000080U /**< Parity error interrupt */ +#define XUARTPS_IXR_FRAMING 0x00000040U /**< Framing error interrupt */ +#define XUARTPS_IXR_RXOVR 0x00000020U /**< Overrun error interrupt */ +#define XUARTPS_IXR_TXFULL 0x00000010U /**< TX FIFO full interrupt. */ +#define XUARTPS_IXR_TXEMPTY 0x00000008U /**< TX FIFO empty interrupt. */ +#define XUARTPS_IXR_RXFULL 0x00000004U /**< RX FIFO full interrupt. */ +#define XUARTPS_IXR_RXEMPTY 0x00000002U /**< RX FIFO empty interrupt. */ +#define XUARTPS_IXR_RTRIG 0x00000001U /**< RX FIFO trigger interrupt. */ +#define XUARTPS_IXR_MASK 0x00003FFFU /**< Valid bit mask */ + +/* Channel Status Register */ +#define XUARTPS_SR_TNFUL 0x00004000U /**< TX FIFO Nearly Full Status */ +#define XUARTPS_SR_TTRIG 0x00002000U /**< TX FIFO Trigger Status */ +#define XUARTPS_SR_FLOWDEL 0x00001000U /**< RX FIFO fill over flow delay */ +#define XUARTPS_SR_TACTIVE 0x00000800U /**< TX active */ +#define XUARTPS_SR_RACTIVE 0x00000400U /**< RX active */ +#define XUARTPS_SR_TXFULL 0x00000010U /**< TX FIFO full */ +#define XUARTPS_SR_TXEMPTY 0x00000008U /**< TX FIFO empty */ +#define XUARTPS_SR_RXFULL 0x00000004U /**< RX FIFO full */ +#define XUARTPS_SR_RXEMPTY 0x00000002U /**< RX FIFO empty */ +#define XUARTPS_SR_RTRIG 0x00000001U /**< RX FIFO fill over trigger */ + +struct uart_xlnx_ps_dev_config { + struct uart_device_config uconf; + u32_t baud_rate; +}; + +/** Device data structure */ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +struct uart_xlnx_ps_dev_data_t { + uart_irq_callback_user_data_t user_cb; + void *user_data; +}; +#endif + +#define DEV_CFG(dev) \ + ((const struct uart_xlnx_ps_dev_config * const) \ + (dev)->config->config_info) +#define DEV_DATA(dev) \ + ((struct uart_xlnx_ps_dev_data_t *)(dev)->driver_data) + +static const struct uart_driver_api uart_xlnx_ps_driver_api; + +static void xlnx_ps_disable_uart(u32_t reg_base) +{ + u32_t regval; + + regval = sys_read32(reg_base + XUARTPS_CR_OFFSET); + regval &= (~XUARTPS_CR_EN_DIS_MASK); + regval |= XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS; + sys_write32(regval, reg_base + XUARTPS_CR_OFFSET); +} + +static void xlnx_ps_enable_uart(u32_t reg_base) +{ + u32_t regval; + + regval = sys_read32(reg_base + XUARTPS_CR_OFFSET); + regval &= (~XUARTPS_CR_EN_DIS_MASK); + regval |= XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN; + sys_write32(regval, reg_base + XUARTPS_CR_OFFSET); +} + +static void set_baudrate(struct device *dev, u32_t baud_rate) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t divisor, generator; + u32_t baud; + u32_t clk_freq; + u32_t reg_base; + + baud = dev_cfg->baud_rate; + clk_freq = dev_cfg->uconf.sys_clk_freq; + + /* Calculate divisor and baud rate generator value */ + if ((baud != 0) && (clk_freq != 0)) { + /* Covering case where input clock is so slow */ + if (clk_freq < 1000000U && baud > 4800U) { + baud = 4800; + } + + for (divisor = 4; divisor < 255; divisor++) { + u32_t tmpbaud, bauderr; + + generator = clk_freq / (baud * (divisor + 1)); + if (generator < 2 || generator > 65535) { + continue; + } + tmpbaud = clk_freq / (generator * (divisor + 1)); + + if (baud > tmpbaud) { + bauderr = baud - tmpbaud; + } else { + bauderr = tmpbaud - baud; + } + if (((bauderr * 100) / baud) < 3) { + break; + } + } + + /* Disable uart before changing baud rate */ + reg_base = dev_cfg->uconf.regs; + xlnx_ps_disable_uart(reg_base); + + /* Set baud rate divisor and generator */ + sys_write32(divisor, reg_base + XUARTPS_BAUDDIV_OFFSET); + sys_write32(generator, reg_base + XUARTPS_BAUDGEN_OFFSET); + xlnx_ps_enable_uart(reg_base); + } +} + +/** + * @brief Initialize individual UART port + * + * This routine is called to reset the chip in a quiescent state. + * + * @param dev UART device struct + * + * @return 0 if successful, failed otherwise + */ +static int uart_xlnx_ps_init(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_val; + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + xlnx_ps_disable_uart(reg_base); + + /* Set mode */ + reg_val = sys_read32(reg_base + XUARTPS_MR_OFFSET); + reg_val &= (~(XUARTPS_MR_CHARLEN_MASK | XUARTPS_MR_STOPMODE_MASK | + XUARTPS_MR_PARITY_MASK)); + reg_val |= XUARTPS_MR_CHARLEN_8_BIT | XUARTPS_MR_STOPMODE_1_BIT | + XUARTPS_MR_PARITY_NONE; + sys_write32(reg_val, reg_base + XUARTPS_MR_OFFSET); + + /* Set RX FIFO trigger at 8 data bytes. */ + sys_write32(0x08U, reg_base + XUARTPS_RXWM_OFFSET); + + /* Set RX timeout to 1, which will be 4 character time */ + sys_write32(0x1U, reg_base + XUARTPS_RXTOUT_OFFSET); + + /* Disable all interrupts, polling mode is default */ + sys_write32(XUARTPS_IXR_MASK, reg_base + XUARTPS_IDR_OFFSET); + + set_baudrate(dev, dev_cfg->baud_rate); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + dev_cfg->uconf.irq_config_func(dev); +#endif + + xlnx_ps_enable_uart(reg_base); + + return 0; +} + +/** + * @brief Poll the device for input. + * + * @param dev UART device struct + * @param c Pointer to character + * + * @return 0 if a character arrived, -1 if the input buffer if empty. + */ +static int uart_xlnx_ps_poll_in(struct device *dev, unsigned char *c) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_val; + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + if ((reg_val & XUARTPS_SR_RXEMPTY) == 0) { + *c = (unsigned char)sys_read32(reg_base + + XUARTPS_FIFO_OFFSET); + return 0; + } else { + return -1; + } +} + +/** + * @brief Output a character in polled mode. + * + * Checks if the transmitter is empty. If empty, a character is written to + * the data register. + * + * If the hardware flow control is enabled then the handshake signal CTS has to + * be asserted in order to send a character. + * + * @param dev UART device struct + * @param c Character to send + * + * @return Sent character + */ +static void uart_xlnx_ps_poll_out(struct device *dev, unsigned char c) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_val; + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + /* wait for transmitter to ready to accept a character */ + do { + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + } while ((reg_val & XUARTPS_SR_TXEMPTY) == 0); + + sys_write32((u32_t)(c & 0xFF), reg_base + XUARTPS_FIFO_OFFSET); + + do { + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + } while ((reg_val & XUARTPS_SR_TXEMPTY) == 0); +} + +#if CONFIG_UART_INTERRUPT_DRIVEN + +/** + * @brief Fill FIFO with data + * + * @param dev UART device struct + * @param tx_data Data to transmit + * @param size Number of bytes to send + * + * @return Number of bytes sent + */ +static int uart_xlnx_ps_fifo_fill(struct device *dev, const u8_t *tx_data, + int size) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_val; + u32_t reg_base; + int onum = 0; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + while (onum < size && (reg_val & XUARTPS_SR_TXFULL) == 0) { + sys_write32((u32_t)(tx_data[onum] & 0xFF), + reg_base + XUARTPS_FIFO_OFFSET); + onum++; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + } + + return onum; +} + +/** + * @brief Read data from FIFO + * + * @param dev UART device struct + * @param rxData Data container + * @param size Container size + * + * @return Number of bytes read + */ +static int uart_xlnx_ps_fifo_read(struct device *dev, u8_t *rx_data, + const int size) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_val; + u32_t reg_base; + int inum = 0; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + + while (inum < size && (reg_val & XUARTPS_SR_RXEMPTY) == 0) { + rx_data[inum] = (u8_t)sys_read32(reg_base + + XUARTPS_FIFO_OFFSET); + inum++; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + } + + return inum; +} + +/** + * @brief Enable TX interrupt in IER + * + * @param dev UART device struct + * + * @return N/A + */ +static void uart_xlnx_ps_irq_tx_enable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_TTRIG, reg_base + XUARTPS_IER_OFFSET); +} + +/** + * @brief Disable TX interrupt in IER + * + * @param dev UART device struct + * + * @return N/A + */ +static void uart_xlnx_ps_irq_tx_disable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_TTRIG, reg_base + XUARTPS_IDR_OFFSET); +} + +/** + * @brief Check if Tx IRQ has been raised + * + * @param dev UART device struct + * + * @return 1 if an IRQ is ready, 0 otherwise + */ +static int uart_xlnx_ps_irq_tx_ready(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + u32_t reg_val; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_ISR_OFFSET); + if ((reg_val & XUARTPS_IXR_TTRIG) == 0) { + return 0; + } else { + return 1; + } +} + +/** + * @brief Check if nothing remains to be transmitted + * + * @param dev UART device struct + * + * @return 1 if nothing remains to be transmitted, 0 otherwise + */ +static int uart_xlnx_ps_irq_tx_complete(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + u32_t reg_val; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET); + if ((reg_val & XUARTPS_SR_TXEMPTY) == 0) { + return 0; + } else { + return 1; + } +} + +/** + * @brief Enable RX interrupt in IER + * + * @param dev UART device struct + * + * @return N/A + */ +static void uart_xlnx_ps_irq_rx_enable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_RTRIG, reg_base + XUARTPS_IER_OFFSET); +} + +/** + * @brief Disable RX interrupt in IER + * + * @param dev UART device struct + * + * @return N/A + */ +static void uart_xlnx_ps_irq_rx_disable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_RTRIG, reg_base + XUARTPS_IDR_OFFSET); +} + +/** + * @brief Check if Rx IRQ has been raised + * + * @param dev UART device struct + * + * @return 1 if an IRQ is ready, 0 otherwise + */ +static int uart_xlnx_ps_irq_rx_ready(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + u32_t reg_val; + + reg_base = dev_cfg->uconf.regs; + reg_val = sys_read32(reg_base + XUARTPS_ISR_OFFSET); + if ((reg_val & XUARTPS_IXR_RTRIG) == 0) { + return 0; + } else { + return 1; + } +} + +/** + * @brief Enable error interrupt in IER + * + * @param dev UART device struct + * + * @return N/A + */ +static void uart_xlnx_ps_irq_err_enable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING, + reg_base + XUARTPS_IER_OFFSET); +} + +/** + * @brief Disable error interrupt in IER + * + * @param dev UART device struct + * + * @return 1 if an IRQ is ready, 0 otherwise + */ +static void uart_xlnx_ps_irq_err_disable(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + + reg_base = dev_cfg->uconf.regs; + sys_write32(XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING, + reg_base + XUARTPS_IDR_OFFSET); +} + +/** + * @brief Check if any IRQ is pending + * + * @param dev UART device struct + * + * @return 1 if an IRQ is pending, 0 otherwise + */ +static int uart_xlnx_ps_irq_is_pending(struct device *dev) +{ + const struct uart_xlnx_ps_dev_config *dev_cfg = DEV_CFG(dev); + u32_t reg_base; + u32_t reg_imr; + u32_t reg_isr; + + reg_base = dev_cfg->uconf.regs; + reg_imr = sys_read32(reg_base + XUARTPS_IMR_OFFSET); + reg_isr = sys_read32(reg_base + XUARTPS_ISR_OFFSET); + + if ((reg_imr & reg_isr) != 0) { + return 1; + } else { + return 0; + } +} + +/** + * @brief Update cached contents of IIR + * + * @param dev UART device struct + * + * @return Always 1 + */ +static int uart_xlnx_ps_irq_update(struct device *dev) +{ + (void)dev; + return 1; +} + +/** + * @brief Set the callback function pointer for IRQ. + * + * @param dev UART device struct + * @param cb Callback function pointer. + * + * @return N/A + */ +static void uart_xlnx_ps_irq_callback_set(struct device *dev, + uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct uart_xlnx_ps_dev_data_t *dev_data = DEV_DATA(dev); + + dev_data->user_cb = cb; + dev_data->user_data = cb_data; +} + +/** + * @brief Interrupt ce routine. + * + * This simply calls the callback function, if one exists. + * + * @param arg Argument to ISR. + * + * @return N/A + */ +static void uart_xlnx_ps_isr(void *arg) +{ + struct device *dev = arg; + const struct uart_xlnx_ps_dev_data_t *data = DEV_DATA(dev); + + if (data->user_cb) { + data->user_cb(data->user_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_xlnx_ps_driver_api = { + .poll_in = uart_xlnx_ps_poll_in, + .poll_out = uart_xlnx_ps_poll_out, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + + .fifo_fill = uart_xlnx_ps_fifo_fill, + .fifo_read = uart_xlnx_ps_fifo_read, + .irq_tx_enable = uart_xlnx_ps_irq_tx_enable, + .irq_tx_disable = uart_xlnx_ps_irq_tx_disable, + .irq_tx_ready = uart_xlnx_ps_irq_tx_ready, + .irq_tx_complete = uart_xlnx_ps_irq_tx_complete, + .irq_rx_enable = uart_xlnx_ps_irq_rx_enable, + .irq_rx_disable = uart_xlnx_ps_irq_rx_disable, + .irq_rx_ready = uart_xlnx_ps_irq_rx_ready, + .irq_err_enable = uart_xlnx_ps_irq_err_enable, + .irq_err_disable = uart_xlnx_ps_irq_err_disable, + .irq_is_pending = uart_xlnx_ps_irq_is_pending, + .irq_update = uart_xlnx_ps_irq_update, + .irq_callback_set = uart_xlnx_ps_irq_callback_set, + +#endif +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +#define UART_XLNX_PS_IRQ_CONF_FUNC_SET(port) \ + .irq_config_func = uart_xlnx_ps_irq_config_##port, + +#define UART_XLNX_PS_IRQ_CONF_FUNC(port) \ +DEVICE_DECLARE(uart_xlnx_ps_##port); \ +\ +static void uart_xlnx_ps_irq_config_0(struct device *dev) \ +{ \ + IRQ_CONNECT(DT_INST_##port##_XLNX_XUARTPS_IRQ_0, \ + DT_INST_##port##_XLNX_XUARTPS_IRQ_0_PRIORITY, \ + uart_xlnx_ps_isr, DEVICE_GET(uart_xlnx_ps_##port), \ + 0); \ + irq_enable(DT_INST_##port##_XLNX_XUARTPS_IRQ_0); \ +} + +#define UART_XLNX_PS_DEV_DATA(port) \ +static struct uart_xlnx_ps_dev_data_t uart_xlnx_ps_dev_data_##port + +#else + +#define UART_XLNX_PS_IRQ_CONF_FUNC_SET(port) +#define UART_XLNX_PS_IRQ_CONF_FUNC(port) +#define UART_XLNX_PS_DEV_DATA(port) + +#endif /*CONFIG_UART_INTERRUPT_DRIVEN */ + +#define UART_XLNX_PS_DEV_CFG(port) \ +static struct uart_xlnx_ps_dev_config uart_xlnx_ps_dev_cfg_##port = { \ + .uconf = { \ + .regs = DT_INST_##port##_XLNX_XUARTPS_BASE_ADDRESS, \ + .base = (u8_t *)DT_INST_##port##_XLNX_XUARTPS_BASE_ADDRESS, \ + .sys_clk_freq = DT_INST_##port##_XLNX_XUARTPS_CLOCK_FREQUENCY, \ + UART_XLNX_PS_IRQ_CONF_FUNC_SET(port) \ + }, \ + .baud_rate = DT_INST_##port##_XLNX_XUARTPS_CURRENT_SPEED, \ +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define UART_XLNX_PS_INIT(port) \ +DEVICE_AND_API_INIT(uart_xlnx_ps_##port, DT_INST_##port##_XLNX_XUARTPS_LABEL, \ + uart_xlnx_ps_init, \ + &uart_xlnx_ps_dev_data_##port, \ + &uart_xlnx_ps_dev_cfg_##port, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_xlnx_ps_driver_api) +#else +#define UART_XLNX_PS_INIT(port) \ +DEVICE_AND_API_INIT(uart_xlnx_ps_##port, DT_INST_##port##_XLNX_XUARTPS_LABEL, \ + uart_xlnx_ps_init, \ + NULL, \ + &uart_xlnx_ps_dev_cfg_##port, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_xlnx_ps_driver_api) +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#ifdef DT_INST_0_XLNX_XUARTPS_BASE_ADDRESS +UART_XLNX_PS_IRQ_CONF_FUNC(0); +UART_XLNX_PS_DEV_DATA(0); +UART_XLNX_PS_DEV_CFG(0); +UART_XLNX_PS_INIT(0); +#endif + +#ifdef DT_INST_1_XLNX_XUARTPS_BASE_ADDRESS +UART_XLNX_PS_IRQ_CONF_FUNC(1); +UART_XLNX_PS_DEV_DATA(1); +UART_XLNX_PS_DEV_CFG(1); +UART_XLNX_PS_INIT(1); +#endif + + diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index ef8cb2bbd06a..b124c6ff6641 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_sources_if_kconfig( native_posix_timer.c) zephyr_sources_if_kconfig( sam0_rtc_timer.c) zephyr_sources_if_kconfig( litex_timer.c) zephyr_sources_if_kconfig( mchp_xec_rtos_timer.c) +zephyr_sources_if_kconfig( xlnx_psttc_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 90b0a709a41a..7c6807181206 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -241,6 +241,23 @@ config MCHP_XEC_RTOS_TIMER XEC series RTOS timer and provides the standard "system clock driver" interfaces. +config XLNX_PSTTC_TIMER + bool "Xilinx PS ttc timer support" + default y + depends on SOC_XILINX_ZYNQMP + help + This module implements a kernel device driver for the Xilinx ZynqMP + platform provides the standard "system clock driver" interfaces. + If unchecked, no timer will be used. + +config XLNX_PSTTC_TIMER_INDEX + int "Xilinx PS ttc timer index" + range 0 3 + default 0 + depends on XLNX_PSTTC_TIMER + help + This is the index of TTC timer picked to provide system clock. + config SYSTEM_CLOCK_DISABLE bool "API to disable system clock" help diff --git a/drivers/timer/xlnx_psttc_timer.c b/drivers/timer/xlnx_psttc_timer.c new file mode 100644 index 000000000000..5ec46ab3e2da --- /dev/null +++ b/drivers/timer/xlnx_psttc_timer.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2018 Xilinx, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "irq.h" +#include "legacy_api.h" + +#define TIMER_FREQ CONFIG_SYS_CLOCK_TICKS_PER_SEC + +#if (CONFIG_XLNX_PSTTC_TIMER_INDEX == 0) +#define TIMER_INPUT_CLKHZ DT_INST_0_CDNS_TTC_CLOCK_FREQUENCY +#define TIMER_IRQ DT_INST_0_CDNS_TTC_IRQ_0 +#define TIMER_BASEADDR DT_INST_0_CDNS_TTC_BASE_ADDRESS +#else +#error ("No timer is specified") +#endif + +#define XTTCPS_CLK_CNTRL_OFFSET 0x00000000U /**< Clock Control Register */ +#define XTTCPS_CNT_CNTRL_OFFSET 0x0000000CU /**< Counter Control Register*/ +#define XTTCPS_COUNT_VALUE_OFFSET 0x00000018U /**< Current Counter Value */ +#define XTTCPS_INTERVAL_VAL_OFFSET 0x00000024U /**< Interval Count Value */ +#define XTTCPS_MATCH_0_OFFSET 0x00000030U /**< Match 1 value */ +#define XTTCPS_MATCH_1_OFFSET 0x0000003CU /**< Match 2 value */ +#define XTTCPS_MATCH_2_OFFSET 0x00000048U /**< Match 3 value */ +#define XTTCPS_ISR_OFFSET 0x00000054U /**< Interrupt Status Register */ +#define XTTCPS_IER_OFFSET 0x00000060U /**< Interrupt Enable Register */ + +/* Clock Control Register definitions */ +#define XTTCPS_CLK_CNTRL_PS_EN_MASK 0x00000001U /**< Prescale enable */ +#define XTTCPS_CLK_CNTRL_PS_VAL_MASK 0x0000001EU /**< Prescale value */ +#define XTTCPS_CLK_CNTRL_PS_VAL_SHIFT 1U /**< Prescale shift */ +#define XTTCPS_CLK_CNTRL_PS_DISABLE 16U /**< Prescale disable */ +#define XTTCPS_CLK_CNTRL_SRC_MASK 0x00000020U /**< Clock source */ +#define XTTCPS_CLK_CNTRL_EXT_EDGE_MASK 0x00000040U /**< External Clock edge */ + +/* Counter Control Register definitions */ +#define XTTCPS_CNT_CNTRL_DIS_MASK 0x00000001U /**< Disable the counter */ +#define XTTCPS_CNT_CNTRL_INT_MASK 0x00000002U /**< Interval mode */ +#define XTTCPS_CNT_CNTRL_DECR_MASK 0x00000004U /**< Decrement mode */ +#define XTTCPS_CNT_CNTRL_MATCH_MASK 0x00000008U /**< Match mode */ +#define XTTCPS_CNT_CNTRL_RST_MASK 0x00000010U /**< Reset counter */ +#define XTTCPS_CNT_CNTRL_EN_WAVE_MASK 0x00000020U /**< Enable waveform */ +#define XTTCPS_CNT_CNTRL_POL_WAVE_MASK 0x00000040U /**< Waveform polarity */ +#define XTTCPS_CNT_CNTRL_RESET_VALUE 0x00000021U /**< Reset value */ + +/* Interrupt register masks */ +#define XTTCPS_IXR_INTERVAL_MASK 0x00000001U /**< Interval Interrupt */ +#define XTTCPS_IXR_MATCH_0_MASK 0x00000002U /**< Match 1 Interrupt */ +#define XTTCPS_IXR_MATCH_1_MASK 0x00000004U /**< Match 2 Interrupt */ +#define XTTCPS_IXR_MATCH_2_MASK 0x00000008U /**< Match 3 Interrupt */ +#define XTTCPS_IXR_CNT_OVR_MASK 0x00000010U /**< Counter Overflow */ +#define XTTCPS_IXR_ALL_MASK 0x0000001FU /**< All valid Interrupts */ + +#define XTTC_MAX_INTERVAL_COUNT 0xFFFFFFFFU /**< Maximum value of interval counter */ + +static u32_t accumulated_cycles; +static s32_t _sys_idle_elapsed_ticks = 1; + +static int xttc_calculate_interval(u32_t *interval, u8_t *prescaler) +{ + u32_t tmpinterval = 0; + u8_t tmpprescaler = 0; + unsigned int tmpval; + + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / TIMER_FREQ); + + if (tmpval < (u32_t)65536U) { + /* no prescaler is required */ + tmpinterval = tmpval; + tmpprescaler = 0; + } else { + for (tmpprescaler = 1U; tmpprescaler < 16; tmpprescaler++) { + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / + (TIMER_FREQ * (1U << tmpprescaler))); + if (tmpval < (u32_t)65536U) { + tmpinterval = tmpval; + break; + } + } + } + + if (tmpinterval != 0) { + *interval = tmpinterval; + *prescaler = tmpprescaler; + return 0; + } + + /* TBD: Is there a way to adjust the sys clock parameters such as + * ticks per sec if it failed to configure the timer as specified + */ + return -EINVAL; +} + +/** + * @brief System timer tick handler + * + * This routine handles the system clock tick interrupt. A TICK_EVENT event + * is pushed onto the kernel stack. + * + * The symbol for this routine is either _timer_int_handler. + * + * @return N/A + */ +void _timer_int_handler(void *unused) +{ + ARG_UNUSED(unused); + + u32_t regval; + + regval = sys_read32(TIMER_BASEADDR + XTTCPS_ISR_OFFSET); + accumulated_cycles += sys_clock_hw_cycles_per_tick(); + z_clock_announce(_sys_idle_elapsed_ticks); +} + +/** + * @brief Initialize and enable the system clock + * + * This routine is used to program the systick to deliver interrupts at the + * rate specified via the 'sys_clock_us_per_tick' global variable. + * + * @return 0 + */ +int z_clock_driver_init(struct device *device) +{ + int ret; + u32_t interval; + u8_t prescaler; + u32_t regval; + + /* Stop timer */ + sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK, + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Calculate prescaler */ + ret = xttc_calculate_interval(&interval, &prescaler); + if (ret < 0) { + printk("Failed to calculate prescaler.\n"); + return ret; + } + + /* Reset registers */ + sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE, + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_0_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_1_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_2_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_IER_OFFSET); + sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASEADDR + XTTCPS_ISR_OFFSET); + /* Reset counter value */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval |= XTTCPS_CNT_CNTRL_RST_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Set options */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval |= XTTCPS_CNT_CNTRL_INT_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Set interval and prescaller */ + sys_write32(interval, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); + regval = (u32_t)((prescaler & 0xFU) << 1); + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); + + /* Enable timer interrupt */ + IRQ_CONNECT(TIMER_IRQ, 0, _timer_int_handler, 0, 0); + irq_enable(TIMER_IRQ); + regval = sys_read32(TIMER_BASEADDR + XTTCPS_IER_OFFSET); + regval |= XTTCPS_IXR_INTERVAL_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_IER_OFFSET); + + /* Start timer */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval &= (~XTTCPS_CNT_CNTRL_DIS_MASK); + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + return 0; +} + + +/** + * @brief Read the platform's timer hardware + * + * This routine returns the current time in terms of timer hardware clock + * cycles. + * + * @return up counter of elapsed clock cycles + */ +u32_t z_timer_cycle_get_32(void) +{ + return accumulated_cycles; +} diff --git a/dts/arm/armv7-r.dtsi b/dts/arm/armv7-r.dtsi new file mode 100644 index 000000000000..30ce1e237e1e --- /dev/null +++ b/dts/arm/armv7-r.dtsi @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "skeleton.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "Cortex-R"; + reg = <0>; + }; + + core_intc: core_intc@0 { + compatible = "armv7-r,core-intc"; + reg = <0x00 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + }; +}; + diff --git a/dts/arm/xilinx/zynqmp.dtsi b/dts/arm/xilinx/zynqmp.dtsi new file mode 100644 index 000000000000..f9dbfe702642 --- /dev/null +++ b/dts/arm/xilinx/zynqmp.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + +/ { + soc { + interrupt-parent = <&gic>; + + gic: interrupt-controller@f9010000 { + compatible = "arm,gic"; + reg = <0xf9010000 0x1000>, + <0xf9020000 0x100>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&core_intc 0>; + label = "GIC"; + status = "okay"; + }; + + flash0: flash@c0000000 { + compatible = "soc-nv-flash"; + reg = <0xc0000000 DT_SIZE_K(64)>; + }; + + sram0: memory@0 { + compatible = "mmio-sram"; + reg = <0 DT_SIZE_K(256)>; + }; + + uart0: uart@ff000000 { + compatible = "xlnx,xuartps"; + reg = <0xff000000 0x4c>; + status = "disabled"; + interrupts = <21 0 IRQ_TYPE_LEVEL>; + interrupt-names = "irq_0"; + label = "UART_0"; + }; + + ttc0: timer@ff110000 { + compatible = "cdns,ttc"; + status = "disabled"; + interrupts = <36 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <37 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <38 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>; + interrupt-names = "irq_0", "irq_1", "irq_2"; + reg = <0xff110000 0x1000>; + label = "ttc0"; + }; + + ttc1: timer@ff120000 { + compatible = "cdns,ttc"; + status = "disabled"; + interrupts = <39 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <40 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <41 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>; + interrupt-names = "irq_0", "irq_1", "irq_2"; + reg = <0xff120000 0x1000>; + label = "ttc1"; + }; + + ttc2: timer@ff130000 { + compatible = "cdns,ttc"; + status = "disabled"; + interrupts = <42 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <43 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <44 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>; + interrupt-names = "irq_0", "irq_1", "irq_2"; + reg = <0xff130000 0x1000>; + label = "ttc2"; + }; + + ttc3: timer@ff140000 { + compatible = "cdns,ttc"; + status = "disabled"; + interrupts = <45 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <46 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>, + <47 IRQ_DEFAULT_PRIORITY IRQ_TYPE_LEVEL>; + interrupt-names = "irq_0", "irq_1", "irq_2"; + reg = <0xff140000 0x1000>; + label = "ttc3"; + }; + }; +}; diff --git a/dts/bindings/interrupt-controller/arm,gic.yaml b/dts/bindings/interrupt-controller/arm,gic.yaml new file mode 100644 index 000000000000..87b7df9dde33 --- /dev/null +++ b/dts/bindings/interrupt-controller/arm,gic.yaml @@ -0,0 +1,29 @@ +# +# Copyright (c) 2018 Marvell +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: ARMv7-R Generic Interrupt Controller + +description: > + This binding describes the ARM Generic Interrupt Controller. + +inherits: + !include base.yaml + +properties: + compatible: + constraint: "arm,gic" + + reg: + category: required + + label: + category: required + +"#cells": + - irq + - priority + - flags +... diff --git a/dts/bindings/serial/xlnx,uartps.yaml b/dts/bindings/serial/xlnx,uartps.yaml new file mode 100644 index 000000000000..8d0715e04273 --- /dev/null +++ b/dts/bindings/serial/xlnx,uartps.yaml @@ -0,0 +1,16 @@ +--- +title: Xilinx PS UART + +description: > + This binding gives a base representation of the Xilinx PS UART + +inherits: + !include uart.yaml + +properties: + compatible: + constraint: "xlnx,xuartps" + + reg: + category: required +... diff --git a/dts/bindings/timer/xlnx,ttcps.yaml b/dts/bindings/timer/xlnx,ttcps.yaml new file mode 100644 index 000000000000..dc2d35213925 --- /dev/null +++ b/dts/bindings/timer/xlnx,ttcps.yaml @@ -0,0 +1,24 @@ +--- +title: Xilinx ZynqMP PS TTC TIMERS + +description: > + This binding gives a base representation of the Xilinx ZynqMP PS TTC TIMERS + +inherits: + !include base.yaml + +properties: + compatible: + constraint: "cdns,ttc" + + label: + category: required + + reg: + category: required + + clock-frequency: + type: int + category: optional + description: Clock frequency information for Timer operation +... diff --git a/include/arch/arm/arch.h b/include/arch/arm/arch.h index bbce87d8b481..322136f3ef4d 100644 --- a/include/arch/arm/arch.h +++ b/include/arch/arm/arch.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -35,6 +34,10 @@ #ifdef CONFIG_CPU_CORTEX_M #include #include +#include +#elif defined(CONFIG_CPU_CORTEX_R) +#include +#include #endif #ifdef __cplusplus diff --git a/include/arch/arm/asm_inline_gcc.h b/include/arch/arm/asm_inline_gcc.h index 148444846cba..122104e29bca 100644 --- a/include/arch/arm/asm_inline_gcc.h +++ b/include/arch/arm/asm_inline_gcc.h @@ -90,6 +90,12 @@ static ALWAYS_INLINE unsigned int z_arch_irq_lock(void) : "=r"(key), "=r"(tmp) : "i"(_EXC_IRQ_DEFAULT_PRIO) : "memory"); +#elif defined(CONFIG_ARMV7_R) + __asm__ volatile("mrs %0, cpsr;" + "cpsid i" + : "=r" (key) + : + : "memory", "cc"); #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -132,6 +138,11 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) "msr BASEPRI, %0;" "isb;" : : "r"(key) : "memory"); +#elif defined(CONFIG_ARMV7_R) + __asm__ volatile("msr cpsr_c, %0" + : + : "r" (key) + : "memory", "cc"); #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ diff --git a/include/arch/arm/cortex_r/cpu.h b/include/arch/arm/cortex_r/cpu.h new file mode 100644 index 000000000000..9ce788a511bd --- /dev/null +++ b/include/arch/arm/cortex_r/cpu.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _CORTEX_R_CPU_H +#define _CORTEX_R_CPU_H + +#define MODE_USR 0x10 +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UDF 0x1b +#define MODE_SYS 0x1f +#define MODE_MASK 0x1f + +#define A_BIT (1 << 8) +#define I_BIT (1 << 7) +#define F_BIT (1 << 6) +#define T_BIT (1 << 5) + +#define HIVECS (1 << 13) + +#define RET_FROM_SVC 0 +#define RET_FROM_IRQ 1 + +#define __ISB() __asm__ volatile ("isb sy" : : : "memory") +#define __DMB() __asm__ volatile ("dmb sy" : : : "memory") + +#endif diff --git a/include/arch/arm/cortex_r/scripts/app_data_alignment.ld b/include/arch/arm/cortex_r/scripts/app_data_alignment.ld new file mode 100644 index 000000000000..a9257f14ee89 --- /dev/null +++ b/include/arch/arm/cortex_r/scripts/app_data_alignment.ld @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Set initial alignment to the 32 byte minimum for all MPUs */ +_app_data_align = 32; +. = ALIGN(32); diff --git a/include/arch/arm/cortex_r/scripts/linker.ld b/include/arch/arm/cortex_r/scripts/linker.ld new file mode 100644 index 000000000000..e4a8e9fdaa79 --- /dev/null +++ b/include/arch/arm/cortex_r/scripts/linker.ld @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the Cortex-R platforms. + */ + +#define _LINKER +#define _ASMLANGUAGE + +#include +#include +#include + +#include +#include + +/* physical address of RAM */ +#ifdef CONFIG_XIP + #define ROMABLE_REGION FLASH + #define RAMABLE_REGION SRAM +#else + #define ROMABLE_REGION SRAM + #define RAMABLE_REGION SRAM +#endif + +#if defined(CONFIG_XIP) + #define _DATA_IN_ROM __data_rom_start +#else + #define _DATA_IN_ROM +#endif + +#if !defined(SKIP_TO_KINETIS_FLASH_CONFIG) + #define SKIP_TO_KINETIS_FLASH_CONFIG +#endif + +#if !defined(CONFIG_XIP) && (CONFIG_FLASH_SIZE == 0) +#define ROM_ADDR RAM_ADDR +#else +#define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) +#endif + +#ifdef CONFIG_TI_CCFG_PRESENT + #define CCFG_SIZE 88 + #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET - \ + CCFG_SIZE) + #define CCFG_ADDR (ROM_ADDR + ROM_SIZE) +#else +#if CONFIG_FLASH_LOAD_SIZE > 0 + #define ROM_SIZE CONFIG_FLASH_LOAD_SIZE +#else + #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET) +#endif +#endif + +#if defined(CONFIG_XIP) + #if defined(CONFIG_IS_BOOTLOADER) + #define RAM_SIZE (CONFIG_BOOTLOADER_SRAM_SIZE * 1K) + #define RAM_ADDR (CONFIG_SRAM_BASE_ADDRESS + \ + (CONFIG_SRAM_SIZE * 1K - RAM_SIZE)) + #else + #define RAM_SIZE (CONFIG_SRAM_SIZE * 1K) + #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS + #endif +#else + #define RAM_SIZE (CONFIG_SRAM_SIZE * 1K - CONFIG_BOOTLOADER_SRAM_SIZE * 1K) + #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS +#endif + +/* Set alignment to CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE + * to make linker section alignment comply with MPU granularity. + */ +#if defined(CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE) +_region_min_align = CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE; +#else +/* If building without MPU support, use default 4-byte alignment. */ +_region_min_align = 4; +#endif + +#if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) +#define MPU_ALIGN(region_size) \ + . = ALIGN(_region_min_align); \ + . = ALIGN( 1 << LOG2CEIL(region_size)) +#else +#define MPU_ALIGN(region_size) \ + . = ALIGN(_region_min_align) +#endif + +MEMORY + { + FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE +#ifdef CONFIG_TI_CCFG_PRESENT + FLASH_CCFG (rwx): ORIGIN = CCFG_ADDR, LENGTH = CCFG_SIZE +#endif +#ifdef DT_CCM_BASE_ADDRESS + CCM (rw) : ORIGIN = DT_CCM_BASE_ADDRESS, LENGTH = DT_CCM_SIZE * 1K +#endif + SRAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE +#ifdef CONFIG_BT_STM32_IPM + SRAM1 (rw) : ORIGIN = RAM1_ADDR, LENGTH = RAM1_SIZE + SRAM2 (rw) : ORIGIN = RAM2_ADDR, LENGTH = RAM2_SIZE +#endif + /* Used by and documented in include/linker/intlist.ld */ + IDT_LIST (wx) : ORIGIN = (RAM_ADDR + RAM_SIZE), LENGTH = 2K + } + +ENTRY(CONFIG_KERNEL_ENTRY) + +SECTIONS + { + +#include + + /* + * .plt and .iplt are here according to 'arm-zephyr-elf-ld --verbose', + * before text section. + */ + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + GROUP_START(ROMABLE_REGION) + + _image_rom_start = ROM_ADDR; + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { +#ifdef CONFIG_CC3220SF_DEBUG + /* Add CC3220SF flash header to disable flash verification */ + . = 0x0; + KEEP(*(.dbghdr)) + KEEP(*(".dbghdr.*")) +#endif + +#ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER + KEEP(*(.boot_hdr.conf)) + . = CONFIG_IMAGE_VECTOR_TABLE_OFFSET; + KEEP(*(.boot_hdr.ivt)) + KEEP(*(.boot_hdr.data)) +#ifdef CONFIG_DEVICE_CONFIGURATION_DATA + KEEP(*(.boot_hdr.dcd_data)) +#endif +#endif + + . = CONFIG_TEXT_SECTION_OFFSET; + +#if defined(CONFIG_SW_VECTOR_RELAY) + KEEP(*(.vector_relay_table)) + KEEP(*(".vector_relay_table.*")) + KEEP(*(.vector_relay_handler)) + KEEP(*(".vector_relay_handler.*")) +#endif + + _vector_start = .; + KEEP(*(.exc_vector_table)) + KEEP(*(".exc_vector_table.*")) + + KEEP(*(IRQ_VECTOR_TABLE)) + + KEEP(*(.vectors)) + + KEEP(*(.openocd_dbg)) + KEEP(*(".openocd_dbg.*")) + + /* Kinetis has to write 16 bytes at 0x400 */ + SKIP_TO_KINETIS_FLASH_CONFIG + KEEP(*(.kinetis_flash_config)) + KEEP(*(".kinetis_flash_config.*")) + + _vector_end = .; + } GROUP_LINK_IN(ROMABLE_REGION) + +#ifdef CONFIG_CODE_DATA_RELOCATION + +#include + +#endif /* CONFIG_CODE_DATA_RELOCATION */ + + SECTION_PROLOGUE(_TEXT_SECTION_NAME_2,,) + { + _image_text_start = .; + *(.text) + *(".text.*") + *(.gnu.linkonce.t.*) + + /* + * These are here according to 'arm-zephyr-elf-ld --verbose', + * after .gnu.linkonce.t.* + */ + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + +#include +#include + + } GROUP_LINK_IN(ROMABLE_REGION) + + _image_text_end = .; + +#if defined (CONFIG_CPLUSPLUS) + SECTION_PROLOGUE(.ARM.extab,,) + { + /* + * .ARM.extab section containing exception unwinding information. + */ + *(.ARM.extab* .gnu.linkonce.armextab.*) + } GROUP_LINK_IN(ROMABLE_REGION) +#endif + + SECTION_PROLOGUE(.ARM.exidx,,) + { + /* + * This section, related to stack and exception unwinding, is placed + * explicitly to prevent it from being shared between multiple regions. + * It must be defined for gcc to support 64-bit math and avoid + * section overlap. + */ + __exidx_start = .; +#if defined (__GCC_LINKER_CMD__) + *(.ARM.exidx* gnu.linkonce.armexidx.*) +#endif + __exidx_end = .; + } GROUP_LINK_IN(ROMABLE_REGION) + + _image_rodata_start = .; + +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + *(.rodata) + *(".rodata.*") + *(.gnu.linkonce.r.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include +#ifdef CONFIG_SOC_RODATA_LD +#include +#endif + +#ifdef CONFIG_CUSTOM_RODATA_LD +/* Located in project source directory */ +#include +#endif + +#include +#include + + /* + * For XIP images, in order to avoid the situation when __data_rom_start + * is 32-bit aligned, but the actual data is placed right after rodata + * section, which may not end exactly at 32-bit border, pad rodata + * section, so __data_rom_start points at data and it is 32-bit aligned. + * + * On non-XIP images this may enlarge image size up to 3 bytes. This + * generally is not an issue, since modern ROM and FLASH memory is + * usually 4k aligned. + */ + . = ALIGN(4); + } GROUP_LINK_IN(ROMABLE_REGION) + + _image_rodata_end = .; + MPU_ALIGN(_image_rodata_end -_image_rom_start); + _image_rom_end = .; + + GROUP_END(ROMABLE_REGION) + +/* Some TI SoCs have a special configuration footer, at the end of flash. */ +#ifdef CONFIG_TI_CCFG_PRESENT + SECTION_PROLOGUE(.ti_ccfg,,) + { + KEEP(*(TI_CCFG)) + } > FLASH_CCFG +#endif + + /* + * These are here according to 'arm-zephyr-elf-ld --verbose', + * before data section. + */ + SECTION_PROLOGUE(.got,,) + { + *(.got.plt) + *(.igot.plt) + *(.got) + *(.igot) + } + + GROUP_START(RAMABLE_REGION) + + . = RAM_ADDR; + /* Align the start of image SRAM with the + * minimum granularity required by MPU. + */ + . = ALIGN(_region_min_align); + _image_ram_start = .; + +#if defined(CONFIG_SOC_SERIES_STM32F0X) && !defined(CONFIG_IS_BOOTLOADER) + /* Must be first in ramable region */ + SECTION_PROLOGUE(.st_stm32f0x_vt,(NOLOAD),) + { + _ram_vector_start = .; + . += _vector_end - _vector_start; + _ram_vector_end = .; + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) +#endif + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#if defined(CONFIG_USERSPACE) +#define APP_SHARED_ALIGN . = ALIGN(_region_min_align); +#define SMEM_PARTITION_ALIGN MPU_ALIGN + +#include + + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); +#endif /* CONFIG_USERSPACE */ + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes + */ + . = ALIGN(4); + __bss_start = .; + __kernel_ram_start = .; + + *(.bss) + *(".bss.*") + *(COMMON) + *(".kernel_bss.*") + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + /* + * As memory is cleared in words only, it is simpler to ensure the BSS + * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. + */ + __bss_end = ALIGN(4); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + + SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) + { + /* + * This section is used for non-initialized objects that + * will not be cleared during the boot process. + */ + *(.noinit) + *(".noinit.*") + *(".kernel_noinit.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include +#ifdef CONFIG_SOC_NOINIT_LD +#include +#endif + + } GROUP_LINK_IN(RAMABLE_REGION) + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + __data_ram_start = .; + *(.data) + *(".data.*") + *(".kernel.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include +#ifdef CONFIG_SOC_RWDATA_LD +#include +#endif + +#ifdef CONFIG_CUSTOM_RWDATA_LD +/* Located in project source directory */ +#include +#endif + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + + __data_rom_start = LOADADDR(_DATA_SECTION_NAME); + +#include +#include +#include + +#include + + __data_ram_end = .; + + + /* Define linker symbols */ + + _image_ram_end = .; + _end = .; /* end of image */ + + __kernel_ram_end = RAM_ADDR + RAM_SIZE; + __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; + + GROUP_END(RAMABLE_REGION) + +#ifdef CONFIG_CUSTOM_SECTIONS_LD +/* Located in project source directory */ +#include +#endif + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#include + + SECTION_PROLOGUE(.ARM.attributes, 0,) + { + KEEP(*(.ARM.attributes)) + KEEP(*(.gnu.attributes)) + } + +#if defined(CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS) +#if CONFIG_ARM_NSC_REGION_BASE_ADDRESS != 0 + #define NSC_ALIGN . = ABSOLUTE(CONFIG_ARM_NSC_REGION_BASE_ADDRESS) +#elif defined(CONFIG_CPU_HAS_NRF_IDAU) + /* The nRF9160 needs the NSC region to be at the end of a 32 kB region. */ + #define NSC_ALIGN . = ALIGN(0x8000) - (1 << LOG2CEIL(__sg_size)) +#else + #define NSC_ALIGN . = ALIGN(4) +#endif + +#ifdef CONFIG_CPU_HAS_NRF_IDAU + #define NSC_ALIGN_END . = ALIGN(0x8000) +#else + #define NSC_ALIGN_END . = ALIGN(4) +#endif + +SECTION_PROLOGUE(.gnu.sgstubs,,) +{ + NSC_ALIGN; + __sg_start = .; + /* No input section necessary, since the Secure Entry Veneers are + automatically placed after the .gnu.sgstubs output section. */ +} GROUP_LINK_IN(ROMABLE_REGION) +__sg_end = .; +__sg_size = __sg_end - __sg_start; +NSC_ALIGN_END; +__nsc_size = . - __sg_start; + +#ifdef CONFIG_CPU_HAS_NRF_IDAU + ASSERT(1 << LOG2CEIL(0x8000 - (__sg_start % 0x8000)) + == (0x8000 - (__sg_start % 0x8000)) + && (0x8000 - (__sg_start % 0x8000)) >= 32 + && (0x8000 - (__sg_start % 0x8000)) <= 4096, + "The Non-Secure Callable region size must be a power of 2 \ +between 32 and 4096 bytes.") +#endif +#endif /* CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS */ + +/* Must be last in romable region */ +SECTION_PROLOGUE(.last_section,(NOLOAD),) +{ +} GROUP_LINK_IN(ROMABLE_REGION) + +/* To provide the image size as a const expression, + * calculate this value here. */ +_flash_used = LOADADDR(.last_section) - _image_rom_start; + + } diff --git a/include/arch/arm/cortex_r/sys_io.h b/include/arch/arm/cortex_r/sys_io.h new file mode 100644 index 000000000000..918002ca99b0 --- /dev/null +++ b/include/arch/arm/cortex_r/sys_io.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015, Wind River Systems, Inc. + * Copyright (c) 2017, Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* "Arch" bit manipulation functions in non-arch-specific C code (uses some + * gcc builtins) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_SYS_IO_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_SYS_IO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE + +#include +#include + +/* Memory mapped registers I/O functions */ + +static ALWAYS_INLINE u8_t sys_read8(mem_addr_t addr) +{ + u8_t val = *(volatile u8_t *)addr; + + __DMB(); + return val; +} + +static ALWAYS_INLINE void sys_write8(u8_t data, mem_addr_t addr) +{ + __DMB(); + *(volatile u8_t *)addr = data; +} + +static ALWAYS_INLINE u16_t sys_read16(mem_addr_t addr) +{ + u16_t val = *(volatile u16_t *)addr; + + __DMB(); + return val; +} + +static ALWAYS_INLINE void sys_write16(u16_t data, mem_addr_t addr) +{ + __DMB(); + *(volatile u16_t *)addr = data; +} + +static ALWAYS_INLINE u32_t sys_read32(mem_addr_t addr) +{ + u32_t val = *(volatile u32_t *)addr; + + __DMB(); + return val; +} + +static ALWAYS_INLINE void sys_write32(u32_t data, mem_addr_t addr) +{ + __DMB(); + *(volatile u32_t *)addr = data; +} + +/* Memory bit manipulation functions */ + +static ALWAYS_INLINE void sys_set_bit(mem_addr_t addr, unsigned int bit) +{ + u32_t temp = *(volatile u32_t *)addr; + + *(volatile u32_t *)addr = temp | (1 << bit); +} + +static ALWAYS_INLINE void sys_clear_bit(mem_addr_t addr, unsigned int bit) +{ + u32_t temp = *(volatile u32_t *)addr; + + *(volatile u32_t *)addr = temp & ~(1 << bit); +} + +static ALWAYS_INLINE int sys_test_bit(mem_addr_t addr, unsigned int bit) +{ + u32_t temp = *(volatile u32_t *)addr; + + return temp & (1 << bit); +} + +static ALWAYS_INLINE + void sys_bitfield_set_bit(mem_addr_t addr, unsigned int bit) +{ + /* Doing memory offsets in terms of 32-bit values to prevent + * alignment issues + */ + sys_set_bit(addr + ((bit >> 5) << 2), bit & 0x1F); +} + +static ALWAYS_INLINE + void sys_bitfield_clear_bit(mem_addr_t addr, unsigned int bit) +{ + sys_clear_bit(addr + ((bit >> 5) << 2), bit & 0x1F); +} + +static ALWAYS_INLINE + int sys_bitfield_test_bit(mem_addr_t addr, unsigned int bit) +{ + return sys_test_bit(addr + ((bit >> 5) << 2), bit & 0x1F); +} + +static ALWAYS_INLINE + int sys_test_and_set_bit(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = sys_test_bit(addr, bit); + sys_set_bit(addr, bit); + + return ret; +} + +static ALWAYS_INLINE + int sys_test_and_clear_bit(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = sys_test_bit(addr, bit); + sys_clear_bit(addr, bit); + + return ret; +} + +static ALWAYS_INLINE + int sys_bitfield_test_and_set_bit(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = sys_bitfield_test_bit(addr, bit); + sys_bitfield_set_bit(addr, bit); + + return ret; +} + +static ALWAYS_INLINE + int sys_bitfield_test_and_clear_bit(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = sys_bitfield_test_bit(addr, bit); + sys_bitfield_clear_bit(addr, bit); + + return ret; +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_SYS_IO_H_ */ diff --git a/include/arch/arm/error.h b/include/arch/arm/error.h index ad563671415d..35a66eabbe8a 100644 --- a/include/arch/arm/error.h +++ b/include/arch/arm/error.h @@ -53,6 +53,8 @@ extern "C" { : "memory"); \ CODE_UNREACHABLE; \ } while (false) +#elif defined(CONFIG_ARMV7_R) +/* Pick up the default definition in kernel.h for now */ #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ diff --git a/include/arch/arm/irq.h b/include/arch/arm/irq.h index c365e23611d2..6eded9e57950 100644 --- a/include/arch/arm/irq.h +++ b/include/arch/arm/irq.h @@ -34,6 +34,14 @@ extern int z_arch_irq_is_enabled(unsigned int irq); extern void _IntExit(void); +#if defined(CONFIG_ARMV7_R) +static ALWAYS_INLINE void z_IntLibInit(void) +{ +} +#else +extern void z_IntLibInit(void); +#endif + /* macros convert value of it's argument to a string */ #define DO_TOSTR(s) #s #define TOSTR(s) DO_TOSTR(s) diff --git a/include/arch/arm/syscall.h b/include/arch/arm/syscall.h index d774a4a1c2b2..b6ce4c0dc0eb 100644 --- a/include/arch/arm/syscall.h +++ b/include/arch/arm/syscall.h @@ -16,6 +16,7 @@ #ifndef ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ #define ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ +#define _SVC_CALL_CONTEXT_SWITCH 0 #define _SVC_CALL_IRQ_OFFLOAD 1 #define _SVC_CALL_RUNTIME_EXCEPT 2 #define _SVC_CALL_SYSTEM_CALL 3 diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h new file mode 100644 index 000000000000..5fbba6d10956 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/arm-gic.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __DT_BINDING_ARM_GIC_H +#define __DT_BINDING_ARM_GIC_H + +/* CPU Interrupt numbers */ +#define GIC_INT_VIRT_MAINT 25 +#define GIC_INT_HYP_TIMER 26 +#define GIC_INT_VIRT_TIMER 27 +#define GIC_INT_LEGACY_FIQ 28 +#define GIC_INT_PHYS_TIMER 29 +#define GIC_INT_NS_PHYS_TIMER 30 +#define GIC_INT_LEGACY_IRQ 31 + +#define IRQ_TYPE_LEVEL 0x0 +#define IRQ_TYPE_EDGE 0x1 + +#define IRQ_DEFAULT_PRIORITY 0xa + +#endif diff --git a/include/irq_nextlevel.h b/include/irq_nextlevel.h index f8140861f234..d118d9c7cdac 100644 --- a/include/irq_nextlevel.h +++ b/include/irq_nextlevel.h @@ -23,11 +23,14 @@ extern "C" { */ typedef void (*irq_next_level_func_t)(struct device *dev, unsigned int irq); typedef unsigned int (*irq_next_level_get_state_t)(struct device *dev); +typedef void (*irq_next_level_priority_t)(struct device *dev, + unsigned int irq, unsigned int prio, u32_t flags); struct irq_next_level_api { irq_next_level_func_t intr_enable; irq_next_level_func_t intr_disable; irq_next_level_get_state_t intr_get_state; + irq_next_level_priority_t intr_set_priority; }; /** * @endcond @@ -84,6 +87,28 @@ static inline unsigned int irq_is_enabled_next_level(struct device *dev) return api->intr_get_state(dev); } +/** + * @brief Set IRQ priority. + * + * This routine indicates if any interrupts are enabled in the interrupt + * controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @param irq IRQ to be disabled. + * @param prio priority for irq in the interrupt controller. + * @param flags controller specific flags. + * + * @return N/A + */ +static inline void irq_set_priority_next_level(struct device *dev, u32_t irq, + u32_t prio, u32_t flags) +{ + const struct irq_next_level_api *api = dev->driver_api; + + if (api->intr_set_priority) + api->intr_set_priority(dev, irq, prio, flags); +} + /** * @} */ diff --git a/include/toolchain/gcc.h b/include/toolchain/gcc.h index 615f1ed96b2d..b701e15abe91 100644 --- a/include/toolchain/gcc.h +++ b/include/toolchain/gcc.h @@ -184,6 +184,11 @@ do { \ #define FUNC_CODE() .thumb; #define FUNC_INSTR(a) +#elif defined(CONFIG_ISA_ARM) + +#define FUNC_CODE() .code 32 +#define FUNC_INSTR(a) + #else #error unknown instruction set diff --git a/soc/arm/xilinx_zynqmp/CMakeLists.txt b/soc/arm/xilinx_zynqmp/CMakeLists.txt new file mode 100644 index 000000000000..3d770db77d01 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c +) diff --git a/soc/arm/xilinx_zynqmp/Kconfig.defconfig b/soc/arm/xilinx_zynqmp/Kconfig.defconfig new file mode 100644 index 000000000000..5cfed9364497 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/Kconfig.defconfig @@ -0,0 +1,35 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_XILINX_ZYNQMP + +config SOC + default "xilinx_zynqmp" + +config NUM_IRQS + int + # must be >= the highest interrupt number used + # - include the UART interrupts + default 220 + +config 2ND_LVL_ISR_TBL_OFFSET + default 1 + +config MAX_IRQ_PER_AGGREGATOR + default 219 + +config NUM_2ND_LEVEL_AGGREGATORS + default 1 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 12000000 + +config FLASH_SIZE + default $(dt_int_val,DT_FLASH_SIZE) + +config FLASH_BASE_ADDRESS + default $(dt_hex_val,DT_FLASH_BASE_ADDRESS) + +endif diff --git a/soc/arm/xilinx_zynqmp/Kconfig.soc b/soc/arm/xilinx_zynqmp/Kconfig.soc new file mode 100644 index 000000000000..4ad0bc70fa29 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2019 Lexmark International, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +config SOC_XILINX_ZYNQMP + bool "Xilinx ZynqMP" + select CPU_CORTEX_R5 + select GIC + select MULTI_LEVEL_INTERRUPTS + select 2ND_LEVEL_INTERRUPTS diff --git a/soc/arm/xilinx_zynqmp/dts_fixup.h b/soc/arm/xilinx_zynqmp/dts_fixup.h new file mode 100644 index 000000000000..70b231a114d6 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/dts_fixup.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#undef DT_INST_0_XLNX_XUARTPS_IRQ_0 +#define DT_INST_0_XLNX_XUARTPS_IRQ_0 ((DT_INST_0_XLNX_XUARTPS_IRQ_IRQ_0 + 1) << 8) + +#undef DT_INST_0_CDNS_TTC_IRQ_0 +#define DT_INST_0_CDNS_TTC_IRQ_0 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_0 + 1) << 8) +#undef DT_INST_0_CDNS_TTC_IRQ_1 +#define DT_INST_0_CDNS_TTC_IRQ_1 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_1 + 1) << 8) +#undef DT_INST_0_CDNS_TTC_IRQ_2 +#define DT_INST_0_CDNS_TTC_IRQ_2 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_2 + 1) << 8) diff --git a/soc/arm/xilinx_zynqmp/linker.ld b/soc/arm/xilinx_zynqmp/linker.ld new file mode 100644 index 000000000000..507494c0d42c --- /dev/null +++ b/soc/arm/xilinx_zynqmp/linker.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include diff --git a/soc/arm/xilinx_zynqmp/soc.c b/soc/arm/xilinx_zynqmp/soc.c new file mode 100644 index 000000000000..68fae6a2c8d0 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/soc.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + +#include +/** + * + * @brief Perform basic hardware initialization + * + * @return 0 + */ + +static int soc_init(struct device *arg) +{ + ARG_UNUSED(arg); + + /* Install default handler that simply resets the CPU + * if configured in the kernel, NOP otherwise + */ + NMI_INIT(); + return 0; +} + +SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/xilinx_zynqmp/soc.h b/soc/arm/xilinx_zynqmp/soc.h new file mode 100644 index 000000000000..6c212d1c99d1 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/soc.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef _BOARD__H_ +#define _BOARD__H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE + +#include +#include + +#endif /* !_ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BOARD__H_ */ diff --git a/subsys/testsuite/include/test_asm_inline_gcc.h b/subsys/testsuite/include/test_asm_inline_gcc.h index 518952eebd31..28d8e3f0a241 100644 --- a/subsys/testsuite/include/test_asm_inline_gcc.h +++ b/subsys/testsuite/include/test_asm_inline_gcc.h @@ -36,6 +36,12 @@ static inline void timestamp_serialize(void) /* isb is available in all Cortex-M */ __ISB(); } +#elif defined(CONFIG_CPU_CORTEX_R) +#include +static inline void timestamp_serialize(void) +{ + __ISB(); +} #elif defined(CONFIG_CPU_ARCV2) #define timestamp_serialize() #elif defined(CONFIG_ARCH_POSIX) diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index 14b96db44b63..d4cca0f9e3f2 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -67,6 +67,8 @@ #define TICK_IRQ DT_LITEX_TIMER0_E0002800_IRQ_0 #elif defined(CONFIG_RV32M1_LPTMR_TIMER) #define TICK_IRQ DT_OPENISA_RV32M1_LPTMR_SYSTEM_LPTMR_IRQ_0 +#elif defined(CONFIG_XLNX_PSTTC_TIMER) +#define TICK_IRQ DT_INST_0_CDNS_TTC_IRQ_0 #elif defined(CONFIG_CPU_CORTEX_M) /* * The Cortex-M use the SYSTICK exception for the system timer, which is