diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 417b779ba2c7..3e7604c8e86d 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -200,4 +200,9 @@ config SW_VECTOR_RELAY Add Cortex-M0 Vector Table relay handler and relay vector table, to relay interrupts based on a vector table pointer. +config PLATFORM_SPECIFIC_INIT + bool + prompt "Enable platform (SOC) specific startup hook" + default n + endmenu diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index f5737a0e73ba..3006f8c8c1ef 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -33,12 +33,18 @@ _GENERIC_SECTION(.vt_pointer_section) void *_vector_table_pointer; #define VECTOR_ADDRESS 0 void __weak relocate_vector_table(void) { -#if defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \ +#if defined(CONFIG_SW_VECTOR_RELAY) + _vector_table_pointer = _vector_start; +#elif defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \ !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0) +#if defined(CONFIG_CPU_CORTEX_M0_HAS_VECTOR_TABLE_REMAP) + SCB->VTOR = ((u32_t)_vector_start) & SCB_VTOR_TBLOFF_Msk; + __DSB(); + __ISB(); +#else size_t vector_size = (size_t)_vector_end - (size_t)_vector_start; memcpy(VECTOR_ADDRESS, _vector_start, vector_size); -#elif defined(CONFIG_SW_VECTOR_RELAY) - _vector_table_pointer = _vector_start; +#endif #endif } diff --git a/arch/arm/core/cortex_m/reset.S b/arch/arm/core/cortex_m/reset.S index 0cf37bf059e8..0ac6914b7868 100644 --- a/arch/arm/core/cortex_m/reset.S +++ b/arch/arm/core/cortex_m/reset.S @@ -23,6 +23,9 @@ _ASM_FILE_PROLOGUE GTEXT(__reset) GTEXT(memset) GDATA(_interrupt_stack) +#if defined(CONFIG_PLATFORM_SPECIFIC_INIT) +GTEXT(_PlatformInit) +#endif /** * @@ -57,6 +60,10 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__reset) */ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) +#if defined(CONFIG_PLATFORM_SPECIFIC_INIT) + bl _PlatformInit +#endif + /* lock interrupts: will get unlocked when switch to main task */ #if defined(CONFIG_ARMV6_M) cpsid i diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114 b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114 index 6d4809ad6a27..bfbdf61ff375 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114 +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114 @@ -32,4 +32,12 @@ config USART_MCUX_LPC endif # SERIAL +config SLAVE_CORE_MCUX + bool "Enable LPC54114 Cortex-M0 slave core" + default n + depends on HAS_MCUX + help + Driver for slave core startup + + endif # SOC_LPC54114 diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114_m0 b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114_m0 new file mode 100644 index 000000000000..fe045e2435b7 --- /dev/null +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.defconfig.lpc54114_m0 @@ -0,0 +1,42 @@ +# Kconfig - NXP LPC54114 M0 platform configuration options + +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_LPC54114_M0 + +config SOC + string + default lpc54114_m0 + +config CPU_CORTEX_M0_HAS_VECTOR_TABLE_REMAP + def_bool y + +if PINMUX + +config PINMUX_MCUX_LPC + def_bool n + +endif # PINMUX + +config GPIO + def_bool n + +if GPIO + +config GPIO_MCUX_LPC + def_bool n + +endif # GPIO + +if SERIAL + +config USART_MCUX_LPC + def_bool n + +endif # SERIAL + +endif # SOC_LPC54114_M0 diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.series b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.series index 03320d031273..e13f5c6ab053 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.series +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.series @@ -8,7 +8,7 @@ config SOC_SERIES_LPC54XXX bool "LPC LPC54xxx Series MCU" select CPU_CORTEX_M - select CPU_CORTEX_M4 + select HAS_MCUX select SOC_FAMILY_LPC select SYS_POWER_LOW_POWER_STATE_SUPPORTED select CPU_HAS_SYSTICK diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.soc b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.soc index aec026ee41a4..1edf8f0f4bdb 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.soc +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/Kconfig.soc @@ -11,7 +11,12 @@ depends on SOC_SERIES_LPC54XXX config SOC_LPC54114 bool "SOC_LPC54114" - select HAS_MCUX + select CPU_CORTEX_M4 + select PLATFORM_SPECIFIC_INIT + +config SOC_LPC54114_M0 + bool "SOC_LPC54114_M0" + select CPU_CORTEX_M0PLUS endchoice diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/linker.ld b/arch/arm/soc/nxp_lpc/lpc54xxx/linker.ld index 47bbe42cf7d8..1f79754d50d5 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/linker.ld +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/linker.ld @@ -13,4 +13,41 @@ #include +/* Specify the memory areas */ +MEMORY +{ + m_core1_image (RX) : ORIGIN = 0x00030000, LENGTH = 0x00010000 +} + +/* Define output sections */ +SECTIONS +{ + /* section for storing the secondary core image */ + .m0code : + { + . = ALIGN(4) ; + KEEP (*(.m0code)) + *(.m0code*) + . = ALIGN(4) ; + } > m_core1_image +} + +#ifdef CONFIG_MULTICORE_RPMSG_LITE +/* Specify the shared memory area */ +MEMORY +{ + rpmsg_sh_mem (RW) : ORIGIN = 0x20026800, LENGTH = 0x1800 +} + +SECTIONS +{ + /* NOINIT section for rpmsg_sh_mem */ + .noinit_rpmsg_sh_mem (NOLOAD) : ALIGN(4) + { + *(.noinit.$rpmsg_sh_mem*) + . = ALIGN(4) ; + } > rpmsg_sh_mem +} +#endif + #include diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/soc.c b/arch/arm/soc/nxp_lpc/lpc54xxx/soc.c index 692d038ee766..75459cae3b55 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/soc.c +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/soc.c @@ -36,6 +36,8 @@ static ALWAYS_INLINE void clkInit(void) { + +#ifdef CONFIG_SOC_LPC54114 /* Set up the clock sources */ /* Ensure FRO is on */ @@ -63,6 +65,7 @@ static ALWAYS_INLINE void clkInit(void) /* Attach 12 MHz clock to FLEXCOMM0 */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0); +#endif /* CONFIG_SOC_LPC54114 */ } /** @@ -103,3 +106,55 @@ static int nxp_lpc54114_init(struct device *arg) } SYS_INIT(nxp_lpc54114_init, PRE_KERNEL_1, 0); + + +#ifdef CONFIG_SLAVE_CORE_MCUX + +/** + * + * @brief Slave Init + * + * This routine boots the secondary core + * @return N/A + */ +/* This function is also called at deep sleep resume. */ +int _slave_init(struct device *arg) +{ + s32_t temp; + + ARG_UNUSED(arg); + + /* Enable SRAM2, used by other core */ + SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL_SRAM2_MASK; + + /* Copy second core image to SRAM */ + memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, CORE1_IMAGE_SIZE); + + /* Setup the reset handler pointer (PC) and stack pointer value. + * This is used once the second core runs its startup code. + * The second core first boots from flash (address 0x00000000) + * and then detects its identity (Cortex-M0, slave) and checks + * registers CPBOOT and CPSTACK and use them to continue the + * boot process. + * Make sure the startup code for current core (Cortex-M4) is + * appropriate and shareable with the Cortex-M0 core! + */ + SYSCON->CPBOOT = SYSCON_CPBOOT_BOOTADDR( + *(uint32_t *)((uint8_t *)CORE1_BOOT_ADDRESS + 0x4)); + SYSCON->CPSTACK = SYSCON_CPSTACK_STACKADDR( + *(uint32_t *)CORE1_BOOT_ADDRESS); + + /* Reset the secondary core and start its clocks */ + temp = SYSCON->CPCTRL; + temp |= 0xc0c48000; + SYSCON->CPCTRL = (temp | SYSCON_CPCTRL_CM0CLKEN_MASK + | SYSCON_CPCTRL_CM0RSTEN_MASK); + SYSCON->CPCTRL = (temp | SYSCON_CPCTRL_CM0CLKEN_MASK) + & (~SYSCON_CPCTRL_CM0RSTEN_MASK); + + return 0; +} + +SYS_INIT(_slave_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif /*CONFIG_SLAVE_CORE_MCUX*/ diff --git a/arch/arm/soc/nxp_lpc/lpc54xxx/soc.h b/arch/arm/soc/nxp_lpc/lpc54xxx/soc.h index acac87399b5e..b2268fc68c0a 100644 --- a/arch/arm/soc/nxp_lpc/lpc54xxx/soc.h +++ b/arch/arm/soc/nxp_lpc/lpc54xxx/soc.h @@ -23,6 +23,17 @@ extern "C" { #include #include #include + +/* Address of RAM, where the image for core1 should be copied */ +#define CORE1_BOOT_ADDRESS ((void *)0x20010000) +extern const char m0_image_start[]; +extern const char *m0_image_end; +extern int m0_image_size; +#define CORE1_IMAGE_START ((void *)m0_image_start) +#define CORE1_IMAGE_SIZE (m0_image_size) + + + #endif /* !_ASMLANGUAGE */ #ifdef __cplusplus diff --git a/boards/arm/lpcxpresso54114/dts.fixup b/boards/arm/lpcxpresso54114/dts.fixup index 2a8d280b7406..a9069e092c65 100644 --- a/boards/arm/lpcxpresso54114/dts.fixup +++ b/boards/arm/lpcxpresso54114/dts.fixup @@ -10,3 +10,8 @@ #define CONFIG_USART_MCUX_LPC_0_BAUD_RATE NXP_LPC_USART_40086000_CURRENT_SPEED #define CONFIG_USART_MCUX_LPC_0_IRQ_PRI NXP_LPC_USART_40086000_IRQ_0_PRIORITY #define CONFIG_USART_MCUX_LPC_0_NAME NXP_LPC_USART_40086000_LABEL + +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ NXP_LPC_MAILBOX_4008B000_IRQ_0 +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI NXP_LPC_MAILBOX_4008B000_IRQ_0_PRIORITY +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME NXP_LPC_MAILBOX_4008B000_LABEL + diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114.dts b/boards/arm/lpcxpresso54114/lpcxpresso54114.dts index 27821533b3e1..67636f0f9059 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114.dts +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114.dts @@ -14,10 +14,11 @@ aliases{ usart_0 = &usart0; + mailbox_0 = &mailbox0; }; chosen { - zephyr,sram = &sram1; + zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,console = &usart0; }; @@ -28,3 +29,7 @@ status = "ok"; current-speed = <115200>; }; + +&mailbox0 { + status = "ok"; +}; diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114_defconfig b/boards/arm/lpcxpresso54114/lpcxpresso54114_defconfig index aa35e07a0d4e..ad3ace81ba43 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114_defconfig +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114_defconfig @@ -15,3 +15,7 @@ CONFIG_CORTEX_M_SYSTICK=y CONFIG_GPIO=y CONFIG_PINMUX=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=48000000 + +# Heap is needed by OpenAMP: +CONFIG_HEAP_MEM_POOL_SIZE=4096 + diff --git a/boards/arm/lpcxpresso54114_m0/CMakeLists.txt b/boards/arm/lpcxpresso54114_m0/CMakeLists.txt new file mode 100644 index 000000000000..e47a608bb0fc --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +if(CONFIG_PINMUX_MCUX_LPC) + zephyr_library() + zephyr_library_include_directories(${PROJECT_SOURCE_DIR}/drivers) + zephyr_library_sources(pinmux.c) +endif() diff --git a/boards/arm/lpcxpresso54114_m0/Kconfig.board b/boards/arm/lpcxpresso54114_m0/Kconfig.board new file mode 100644 index 000000000000..2c4dec247b97 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/Kconfig.board @@ -0,0 +1,11 @@ +# Kconfig - LPCXpresso54114 board +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_LPCXPRESSO54114_M0 + bool "NXP LPCXPRESSO-54114 M0" + depends on SOC_SERIES_LPC54XXX + select SOC_PART_NUMBER_LPC54114J256BD64 diff --git a/boards/arm/lpcxpresso54114_m0/Kconfig.defconfig b/boards/arm/lpcxpresso54114_m0/Kconfig.defconfig new file mode 100644 index 000000000000..7b9b3cafd436 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/Kconfig.defconfig @@ -0,0 +1,41 @@ +# Kconfig - LPCXpresso54114 board +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +if BOARD_LPCXPRESSO54114_M0 + +config BOARD + default lpcxpresso54114_m0 + +if USART_MCUX_LPC +config USART_MCUX_LPC_0 + def_bool n if UART_CONSOLE + +endif # USART_MCUX_LPC + +config PINMUX + def_bool n + +if PINMUX_MCUX_LPC + +config PINMUX_MCUX_LPC_PORT0 + def_bool n + +config PINMUX_MCUX_LPC_PORT1 + def_bool n +endif # PINMUX_MCUX_LPC + +if GPIO_MCUX_LPC + +config GPIO_MCUX_LPC_PORT0 + def_bool n + +config GPIO_MCUX_LPC_PORT1 + def_bool n + +endif # GPIO_MCUX_LPC + +endif # BOARD_LPCXPRESSO54114_M0 diff --git a/boards/arm/lpcxpresso54114_m0/board.cmake b/boards/arm/lpcxpresso54114_m0/board.cmake new file mode 100644 index 000000000000..883a83f05295 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/board.cmake @@ -0,0 +1,16 @@ +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +set_ifndef(LPCLINK_FW jlink) + +if(LPCLINK_FW STREQUAL jlink) + set_ifndef(BOARD_DEBUG_RUNNER jlink) + set_ifndef(BOARD_FLASH_RUNNER jlink) +endif() + +board_runner_args(jlink "--device=LPC54114J256_M0") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/lpcxpresso54114_m0/board.h b/boards/arm/lpcxpresso54114_m0/board.h new file mode 100644 index 000000000000..d224d2c1fb3e --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/board.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __INC_BOARD_H +#define __INC_BOARD_H + +#include + +/* Red LED */ +#define RED_GPIO_NAME CONFIG_GPIO_MCUX_LPC_PORT0_NAME +#define RED_GPIO_PIN 29 + +/* Green LED */ +#define GREEN_GPIO_NAME CONFIG_GPIO_MCUX_LPC_PORT1_NAME +#define GREEN_GPIO_PIN 10 + +/* Blue LED */ +#define BLUE_GPIO_NAME CONFIG_GPIO_MCUX_LPC_PORT1_NAME +#define BLUE_GPIO_PIN 9 + +/* LED0. There is no physical LED on the board with this name, so create an + * alias to the green LED to make various samples work. + */ +#define LED0_GPIO_PORT GREEN_GPIO_NAME +#define LED0_GPIO_PIN GREEN_GPIO_PIN + +/* LED1. There is no physical LED on the board with this name, so create an + * alias to the blue LED to make various samples work. + */ +#define LED1_GPIO_PORT BLUE_GPIO_NAME +#define LED1_GPIO_PIN BLUE_GPIO_PIN + +#endif /* __INC_BOARD_H */ diff --git a/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.png b/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.png new file mode 100644 index 000000000000..75b25ef52c26 Binary files /dev/null and b/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.png differ diff --git a/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.rst b/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.rst new file mode 100644 index 000000000000..d08e613df17e --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/doc/lpcxpresso54114.rst @@ -0,0 +1,168 @@ +.. _lpcxpresso54114: + +NXP LPCXPRESSO54114 +##################### + +Overview +******** + +The LPCXpresso54114 board has been developed by NXP to enable evaluation of and +prototyping with the LPC54110 family of MCUs and with the low-power LPC54110 +family of MCUs. LPCXpresso* is a low-cost development platform available from +NXP supporting NXP's ARM-based microcontrollers. LPCXpresso is an end-to-end +solution enabling embedded engineers to develop their applications from initial +evaluation to final production. + +.. image:: lpcxpresso54114.png + :width: 720px + :align: center + :alt: LPCXPRESSO54114 + +Hardware +******** + +- LPC54114 dual-core (M4F and dual M0) MCU running at up to 100 MHz +- On-board high-speed USB based debug probe with CMSIS-DAP and J-Link protocol + support, can debug the on-board LPC54114 or an external target +- External debug probe option +- Tri-color LED, target Reset, ISP & interrupt/user buttons for easy testing of + software functionality +- Expansion options based on Arduino UNO and Pmod™, plus additional expansion + port pins +- On-board 1.8 V and 3.3 V regulators plus external power supply option +- 8 Mb Macronix MX25R SPI flash +- Built-in MCU power consumption and supply voltage measurement +- UART, I²C and SPI port bridging from LPC54114 target to USB via the on-board + debug probe +- FTDI UART connector + +For more information about the LPC54114 SoC and LPCXPRESSO54114 board: + +- `LPC54114 SoC Website`_ +- `LPC54114 Datasheet`_ +- `LPC54114 Reference Manual`_ +- `LPCXPRESSO54114 Website`_ +- `LPCXPRESSO54114 User Guide`_ +- `LPCXPRESSO54114 Schematics`_ + +Supported Features +================== + +The lpcxpresso54114 board configuration supports the following hardware +features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| IOCON | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| USART | on-chip | serial port-polling | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + + ``boards/arm/lpcxpresso54114/lpcxpresso54114_defconfig`` + +Other hardware features are not currently supported by the port. + +Connections and IOs +=================== + +The LPC54114 SoC has IOCON registers, which can be used to configure the +functionality of a pin. + ++---------+-----------------+----------------------------+ +| Name | Function | Usage | ++=========+=================+============================+ +| PIO0_0 | USART | USART RX | ++---------+-----------------+----------------------------+ +| PIO0_1 | USART | USART TX | ++---------+-----------------+----------------------------+ +| PIO0_29 | GPIO | RED LED | ++---------+-----------------+----------------------------+ +| PIO1_9 | GPIO | BLUE_LED | ++---------+-----------------+----------------------------+ +| PIO1_10 | GPIO | GREEN LED | ++---------+-----------------+----------------------------+ + +System Clock +============ + +The LPC54114 SoC is configured to use the internal FRO at 48MHz as a source for +the system clock. Other sources for the system clock are provided in the SOC, +depending on your system requirements. + +Serial Port +=========== + +The LPC54114 SoC has 8 FLEXCOMM interfaces for serial communication. One is +configured as USART for the console and the remaining are not used. + +Programming and Debugging +************************* + +The LPCXpresso54114 includes the LPC-Link2 serial and debug adapter built into +the board to provide debugging, flash programming, and serial communication +over USB. LPC-Link2 can be configured with Segger J-Link or CMSIS-DAP firmware +variants to support corresponding debug tools. Currently only the Segger J-Link +tools are supported for this board in Zephyr, therefore you should use the +Segger J-Link firmware variant. + +Before you start using Zephyr on the LPCXpresso54114, download and run +`LPCScrypt`_ to update the LPC-Link2 firmware to the latest version. Serial +communication problems, such as dropping characters, have been observed with +older versions of the firmware. + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: lpcxpresso54114 + :goals: debug + +Open a serial terminal (minicom, putty, etc.) and connect the board with the +following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and the following message will appear on the corresponding +serial port: + +.. code-block:: console + + Hello World! arm + + +.. _LPC54114 SoC Website: + http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-cortex-m-mcus/lpc54000-series-cortex-m4-mcus/low-power-microcontrollers-mcus-based-on-arm-cortex-m4-cores-with-optional-cortex-m0-plus-co-processor:LPC541XX + +.. _LPC54114 Datasheet: + http://www.nxp.com/docs/en/data-sheet/LPC5411X.pdf + +.. _LPC54114 Reference Manual: + http://www.nxp.com/docs/en/user-guide/UM10914.pdf + +.. _LPCXPRESSO54114 Website: + http://www.nxp.com/products/developer-resources/software-development-tools/software-tools/lpcxpresso-boards/lpcxpresso54114-board:OM13089 + +.. _LPCXPRESSO54114 User Guide: + http://www.nxp.com/docs/en/user-guide/UM10973.pdf + +.. _LPCXPRESSO54114 Schematics: + http://www.nxp.com/downloads/en/design-support/LPCX5411x_Schematic_Rev_A1.pdf + +.. _LPCScrypt: + https://www.nxp.com/support/developer-resources/software-development-tools/lpc-developer-resources-/lpc-microcontroller-utilities/lpcscrypt-v1.8.2:LPCSCRYPT?&tab=Design_Tools_Tab diff --git a/boards/arm/lpcxpresso54114_m0/dts.fixup b/boards/arm/lpcxpresso54114_m0/dts.fixup new file mode 100644 index 000000000000..92e874be47d2 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/dts.fixup @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define CONFIG_NUM_IRQ_PRIO_BITS ARM_V6M_NVIC_E000E100_ARM_NUM_IRQ_PRIORITY_BITS + +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ NXP_LPC_MAILBOX_4008B000_IRQ_0 +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI NXP_LPC_MAILBOX_4008B000_IRQ_0_PRIORITY +#define CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME NXP_LPC_MAILBOX_4008B000_LABEL diff --git a/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts new file mode 100644 index 000000000000..f6b5ddedb9b5 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "NXP LPCXPRESSO54114 board"; + compatible = "nxp,lpc54xxx","nxp,lpc"; + + aliases{ + usart_0 = &usart0; + mailbox_0 = &mailbox0; + }; + chosen { + zephyr,sram = &sram2; + zephyr,flash = &sram1; + /*zephyr,console = &usart0; uncomment to use console on M0 */ + }; + +}; + +&usart0 { + status = "disabled"; /* enable for console, if needed */ + current-speed = <115200>; +}; + +&mailbox0 { + status = "ok"; +}; diff --git a/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.yaml b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.yaml new file mode 100644 index 000000000000..2df5d146d15c --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: lpcxpresso54114 +name: NXP LPCXpresso54114 +type: mcu +arch: arm +ram: 64 +flash: 256 +toolchain: + - zephyr + - gccarmemb diff --git a/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0_defconfig b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0_defconfig new file mode 100644 index 000000000000..28cc404b931e --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/lpcxpresso54114_m0_defconfig @@ -0,0 +1,20 @@ +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_ARM=y +CONFIG_SOC_LPC54114_M0=y +CONFIG_SOC_SERIES_LPC54XXX=y +CONFIG_BOARD_LPCXPRESSO54114_M0=y +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_CORTEX_M_SYSTICK=y +CONFIG_GPIO=n +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=48000000 + +# Heap is needed by OpenAMP: +CONFIG_HEAP_MEM_POOL_SIZE=4096 + diff --git a/boards/arm/lpcxpresso54114_m0/pinmux.c b/boards/arm/lpcxpresso54114_m0/pinmux.c new file mode 100644 index 000000000000..394012edbd64 --- /dev/null +++ b/boards/arm/lpcxpresso54114_m0/pinmux.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017, NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define IOCON_PIO_DIGITAL_EN 0x80u +#define IOCON_PIO_FUNC0 0x00u +#define IOCON_PIO_FUNC1 0x01u +#define IOCON_PIO_FUNC2 0x02u +#define IOCON_PIO_INPFILT_OFF 0x0100u +#define IOCON_PIO_INV_DI 0x00u +#define IOCON_PIO_MODE_INACT 0x00u +#define IOCON_PIO_OPENDRAIN_DI 0x00u +#define IOCON_PIO_SLEW_STANDARD 0x00u +#define IOCON_PIO_MODE_PULLUP 0x10u + +static int lpcxpresso_54114_pinmux_init(struct device *dev) +{ + ARG_UNUSED(dev); + +#ifdef CONFIG_PINMUX_MCUX_LPC_PORT0 + struct device *port0 = + device_get_binding(CONFIG_PINMUX_MCUX_LPC_PORT0_NAME); +#endif + +#ifdef CONFIG_PINMUX_MCUX_LPC_PORT1 + struct device *port1 = + device_get_binding(CONFIG_PINMUX_MCUX_LPC_PORT1_NAME); +#endif + +#ifdef CONFIG_USART_MCUX_LPC_0 + /* USART0 RX, TX */ + const u32_t port0_pin0_config = ( + IOCON_PIO_FUNC1 | + IOCON_PIO_MODE_INACT | + IOCON_PIO_INV_DI | + IOCON_PIO_DIGITAL_EN | + IOCON_PIO_INPFILT_OFF | + IOCON_PIO_SLEW_STANDARD | + IOCON_PIO_OPENDRAIN_DI + ); + + const u32_t port0_pin1_config = ( + IOCON_PIO_FUNC1 | + IOCON_PIO_MODE_INACT | + IOCON_PIO_INV_DI | + IOCON_PIO_DIGITAL_EN | + IOCON_PIO_INPFILT_OFF | + IOCON_PIO_SLEW_STANDARD | + IOCON_PIO_OPENDRAIN_DI + ); + + pinmux_pin_set(port0, 0, port0_pin0_config); + pinmux_pin_set(port0, 1, port0_pin1_config); + +#endif + +#ifdef CONFIG_GPIO_MCUX_LPC_PORT0 + const u32_t port0_pin29_config = ( + IOCON_PIO_FUNC0 | + IOCON_PIO_MODE_PULLUP | + IOCON_PIO_INV_DI | + IOCON_PIO_DIGITAL_EN | + IOCON_PIO_INPFILT_OFF | + IOCON_PIO_OPENDRAIN_DI + ); + + pinmux_pin_set(port0, 29, port0_pin29_config); +#endif + +#ifdef CONFIG_GPIO_MCUX_LPC_PORT1 + const u32_t port1_pin10_config = ( + IOCON_PIO_FUNC0 | + IOCON_PIO_MODE_PULLUP | + IOCON_PIO_INV_DI | + IOCON_PIO_DIGITAL_EN | + IOCON_PIO_INPFILT_OFF | + IOCON_PIO_SLEW_STANDARD | + IOCON_PIO_OPENDRAIN_DI + ); + + pinmux_pin_set(port1, 10, port1_pin10_config); +#endif + + return 0; +} + +SYS_INIT(lpcxpresso_54114_pinmux_init, PRE_KERNEL_1, + CONFIG_PINMUX_INIT_PRIORITY); diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index 4ddb74798c35..c6e209f0a43d 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -1,3 +1,5 @@ zephyr_sources_ifdef(CONFIG_IPM_QUARK_SE ipm_quark_se.c) zephyr_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c) + +zephyr_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index 9ff83ffdf6aa..b8f0aa6aa406 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -22,3 +22,10 @@ config IPM_QUARK_SE_MASTER Sets up the initial interrupt mask and clears out all channels. Should be turned on for one CPU only. +config IPM_MCUX + bool "MCUX IPM driver" + default n + depends on IPM && HAS_MCUX + help + Driver for MCUX mailbox + diff --git a/drivers/ipm/ipm_mcux.c b/drivers/ipm/ipm_mcux.c new file mode 100644 index 000000000000..852a441b8114 --- /dev/null +++ b/drivers/ipm/ipm_mcux.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define MCUX_IPM_DATA_REGS 1 +#define MCUX_IPM_MAX_ID_VAL 0 + + +struct mcux_mailbox_config { + MAILBOX_Type *base; + void (*irq_config_func)(struct device *dev); +}; + +struct mcux_mailbox_data { + ipm_callback_t callback; + void *callback_ctx; +}; + +static void mcux_mailbox_isr(void *arg) +{ + struct device *dev = arg; + struct mcux_mailbox_data *data = dev->driver_data; + mailbox_cpu_id_t cpu_id; +#if defined(__CM4_CMSIS_VERSION) + cpu_id = kMAILBOX_CM4; +#else + cpu_id = kMAILBOX_CM0Plus; +#endif + + volatile u32_t value = MAILBOX_GetValue(MAILBOX, cpu_id); + + __ASSERT(value, "spurious MAILBOX interrupt"); + + /* Clear or the interrupt gets called intermittently */ + MAILBOX_ClearValueBits(MAILBOX, cpu_id, value); + + if (data->callback) { + /* Only one MAILBOX, id is unused and set to 0 */ + data->callback(data->callback_ctx, 0, &value); + } + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F + * Store immediate overlapping exception return operation + * might vector to incorrect interrupt + */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + + +static int mcux_mailbox_ipm_send(struct device *d, int wait, u32_t id, + const void *data, int size) +{ + u32_t data32[MCUX_IPM_DATA_REGS]; /* Until we change API + * to u32_t array + */ + int flags; + int i; + + ARG_UNUSED(wait); + + if (id > MCUX_IPM_MAX_ID_VAL) { + return -EINVAL; + } + + if (size > MCUX_IPM_DATA_REGS * sizeof(u32_t)) { + return -EMSGSIZE; + } + + flags = irq_lock(); + + /* Actual message is passing using 32 bits registers */ + memcpy(data32, data, size); + + for (i = 0; i < ARRAY_SIZE(data32); ++i) { +#if defined(__CM4_CMSIS_VERSION) + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM0Plus, data32[i]); +#else + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM4, data32[i]); +#endif + } + + irq_unlock(flags); + + return 0; +} + + +static int mcux_mailbox_ipm_max_data_size_get(struct device *d) +{ + ARG_UNUSED(d); + /* Only a single 32-bit register available */ + return MCUX_IPM_DATA_REGS*sizeof(u32_t); +} + + +static u32_t mcux_mailbox_ipm_max_id_val_get(struct device *d) +{ + ARG_UNUSED(d); + /* Only a single instance of MAILBOX available for this platform */ + return MCUX_IPM_MAX_ID_VAL; +} + +static void mcux_mailbox_ipm_register_callback(struct device *d, + ipm_callback_t cb, + void *context) +{ + struct mcux_mailbox_data *driver_data = d->driver_data; + + driver_data->callback = cb; + driver_data->callback_ctx = context; +} + + +static int mcux_mailbox_ipm_set_enabled(struct device *d, int enable) +{ + /* For now: nothing to be done */ + return 0; +} + + +static int mcux_mailbox_init(struct device *dev) +{ + const struct mcux_mailbox_config *config = dev->config->config_info; + + MAILBOX_Init(config->base); + config->irq_config_func(dev); + return 0; +} + +static const struct ipm_driver_api mcux_mailbox_driver_api = { + .send = mcux_mailbox_ipm_send, + .register_callback = mcux_mailbox_ipm_register_callback, + .max_data_size_get = mcux_mailbox_ipm_max_data_size_get, + .max_id_val_get = mcux_mailbox_ipm_max_id_val_get, + .set_enabled = mcux_mailbox_ipm_set_enabled +}; + + +/* Config MAILBOX 0 */ + +static void mcux_mailbox_config_func_0(struct device *dev); + +static const struct mcux_mailbox_config mcux_mailbox_0_config = { + .base = MAILBOX, + .irq_config_func = mcux_mailbox_config_func_0, +}; + +static struct mcux_mailbox_data mcux_mailbox_0_data; + +DEVICE_AND_API_INIT(mailbox_0, CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME, + &mcux_mailbox_init, + &mcux_mailbox_0_data, &mcux_mailbox_0_config, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &mcux_mailbox_driver_api); + + +static void mcux_mailbox_config_func_0(struct device *dev) +{ + IRQ_CONNECT(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ, + CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI, + mcux_mailbox_isr, DEVICE_GET(mailbox_0), 0); + + irq_enable(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ); +} + diff --git a/drivers/ipm/ipm_mcux_mailbox.c b/drivers/ipm/ipm_mcux_mailbox.c new file mode 100644 index 000000000000..74d218170333 --- /dev/null +++ b/drivers/ipm/ipm_mcux_mailbox.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +struct mcux_mailbox_config { + MAILBOX_Type *base; + void (*irq_config_func)(struct device *dev); +}; + +struct mcux_mailbox_data { + ipm_callback_t callback; + void *callback_ctx; +}; + +static void mcux_mailbox_isr(void *arg) +{ + struct device *dev = arg; + struct mcux_mailbox_data *data = dev->driver_data; + mailbox_cpu_id_t cpu_id; +#if defined(__CM4_CMSIS_VERSION) + cpu_id = kMAILBOX_CM4; +#else + cpu_id = kMAILBOX_CM0Plus; +#endif + + volatile u32_t value = MAILBOX_GetValue(MAILBOX, cpu_id); + + __ASSERT(value, "spurious MAILBOX interrupt"); + + if (data->callback) { + /* Only one MAILBOX, id is unused and set to 0 */ + data->callback(data->callback_ctx, 0, &value); + } + /* Clear or the interrupt gets called intermittently */ + MAILBOX_ClearValueBits(MAILBOX, cpu_id, value); + + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F + * Store immediate overlapping exception return operation might + * vector to incorrect interrupt + */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + + +static int mcux_mailbox_ipm_send(struct device *d, int wait, u32_t id, + const void *data, int size) +{ + volatile struct quark_se_ipm *ipm = config->ipm; + u32_t data32[MCUX_IPM_DATA_REGS]; /* Until we change API + * to u32_t array + */ + int flags; + int i; + + ARG_UNUSED(wait); + + if (id > MCUX_IPM_MAX_ID_VAL) { + return -EINVAL; + } + + if (size > MCUX_IPM_DATA_REGS * sizeof(u32_t)) { + return -EMSGSIZE; + } + + flags = irq_lock(); + + /* Actual message is passing using 32 bits registers */ + memcpy(data32, data, size); + + for (i = 0; i < ARRAY_SIZE(data32); ++i) { +#if defined(__CM4_CMSIS_VERSION) + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM0Plus, data32[i]); +#else + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM4, data32[i]); +#endif + } + + irq_unlock(flags); + + return 0; +} + + +static int mcux_mailbox_ipm_max_data_size_get(struct device *d) +{ + ARG_UNUSED(d); + /* Only a single 32-bit register available */ + return MCUX_IPM_DATA_REGS*sizeof(u32_t); +} + + +static u32_t mcux_mailbox_ipm_max_id_val_get(struct device *d) +{ + ARG_UNUSED(d); + /* Only a single instance of MAILBOX available for this platform */ + return MCUX_IPM_MAX_ID_VAL; +} + +static void mcux_mailbox_ipm_register_callback(struct device *d, + ipm_callback_t cb, + void *context) +{ + struct mcux_mailbox_data *driver_data = d->driver_data; + + driver_data->callback = cb; + driver_data->callback_ctx = context; +} + + +static int mcux_mailbox_ipm_set_enabled(struct device *d, int enable) +{ + /* For now: nothing to be done */ + return 0; +} + + +static int mcux_mailbox_init(struct device *dev) +{ + const struct mcux_mailbox_config *config = dev->config->config_info; + + MAILBOX_Init(config->base); + config->irq_config_func(dev); + return 0; +} + +static const struct ipm_driver_api mcux_mailbox_driver_api = { + + .send = mcux_mailbox_ipm_send; + .register_callback = mcux_mailbox_ipm_register_callback; + .max_data_size_get = mcux_mailbox_ipm_max_data_size_get; + .max_id_val_get = mcux_mailbox_ipm_max_id_val_get; + .set_enabled = mcux_mailbox_ipm_set_enabled; +}; + + +/* Config MAILBOX 0 */ + +static void mcux_mailbox_config_func_0(struct device *dev); + +static const struct mcux_mailbox_config mcux_mailbox_0_config = { + .base = MAILBOX, + .irq_config_func = mcux_mailbox_config_func_0, +}; + +static struct mcux_mailbox_data mcux_mailbox_0_data; + +DEVICE_AND_API_INIT(mailbox_0, CONFIG_MAILBOX_MCUX_MAILBOX_0_NAME, + &mcux_mailbox_init, + &mcux_mailbox_0_data, &mcux_mailbox_0_config, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &mcux_mailbox_driver_api); + + +static void mcux_mailbox_config_func_0(struct device *dev) +{ + IRQ_CONNECT(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ, + CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ_PRI, + mcux_mailbox_isr, DEVICE_GET(mailbox_0), 0); + + irq_enable(CONFIG_MAILBOX_MCUX_MAILBOX_0_IRQ); +} + diff --git a/dts/arm/nxp/nxp_lpc54xxx.dtsi b/dts/arm/nxp/nxp_lpc54xxx.dtsi index 3346e9f15edd..d27961133575 100644 --- a/dts/arm/nxp/nxp_lpc54xxx.dtsi +++ b/dts/arm/nxp/nxp_lpc54xxx.dtsi @@ -21,15 +21,6 @@ reg = <0x20000000 0x10000>; }; - sram1:memory@20010000 { - compatible = "mmio-sram"; - reg = <0x20010000 0x10000>; - }; - - sram2:memory@20020000 { - compatible = "mmio-sram"; - reg = <0x20020000 0x8000>; - }; sramx:memory@40000000{ compatible = "mmio-sram"; @@ -39,7 +30,10 @@ soc { flash0:flash@0 { - reg = <0 0x40000>; + /* reduced from 0x40000 to 0x30000 + * to leave room for secondary core + */ + reg = <0 0x30000>; }; usart0:usart@40086000 { @@ -49,9 +43,18 @@ label = "USART_0"; status = "disabled"; }; + + mailbox0:mailbox@4008B000 { + compatible = "nxp,lpc-mailbox"; + reg = <0x4008B000 0xEC>; + interrupts = <31 0>; + label = "MAILBOX_0"; + status = "disabled"; + }; }; }; &nvic { arm,num-irq-priority-bits = <3>; }; + diff --git a/dts/arm/nxp/nxp_lpc54xxx_m0.dtsi b/dts/arm/nxp/nxp_lpc54xxx_m0.dtsi new file mode 100644 index 000000000000..39ae07d351be --- /dev/null +++ b/dts/arm/nxp/nxp_lpc54xxx_m0.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-m4f"; + }; + cpu@1 { + compatible = "arm,cortex-m0+"; + }; + }; + + sram1:memory@20010000 { + compatible = "mmio-sram"; + reg = <0x20010000 0x10000>; + }; + +#ifdef CONFIG_MULTICORE_RPMSG_LITE + sram2:memory@20020000 { + compatible = "mmio-sram"; + reg = <0x20020000 0x6800>; + }; + sram3:memory@20026800 { + compatible = "mmio-sram"; + reg = <0x20026800 0x1800>; + }; +#else + sram2:memory@20020000 { + compatible = "mmio-sram"; + reg = <0x20020000 0x8000>; + }; +#endif + sramx:memory@40000000{ + compatible = "mmio-sram"; + reg = <0x40000000 0x8000>; + }; + + soc { + + flash0:flash@30000 { + reg = <0x30000 0x10000>; + }; + + usart0:usart@40086000 { + compatible = "nxp,lpc-usart"; + reg = <0x40086000 0xE44>; + interrupts = <14 0>; + label = "USART_0"; + status = "disabled"; + }; + + mailbox0:mailbox@4008B000 { + compatible = "nxp,lpc-mailbox"; + reg = <0x4008B000 0xEC>; + interrupts = <31 0>; + label = "MAILBOX_0"; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <2>; +}; diff --git a/dts/bindings/arm/nxp,lpc-mailbox.yaml b/dts/bindings/arm/nxp,lpc-mailbox.yaml new file mode 100644 index 000000000000..d2b9dca96d6f --- /dev/null +++ b/dts/bindings/arm/nxp,lpc-mailbox.yaml @@ -0,0 +1,39 @@ +# +# Copyright (c) 2017, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: LPC MAILBOX +id: nxp,lpc-mailbox +version: 0.1 + +description: > + This binding gives a base representation of the LPC MAILBOX + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "nxp,lpc-mailbox" + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define + + label: + type: string + category: required + description: Human readable string describing the device (used by Zephyr for API name) + generation: define + +... diff --git a/ext/Kconfig b/ext/Kconfig index 4242d5e0c3f3..bfcbdaab93b1 100644 --- a/ext/Kconfig +++ b/ext/Kconfig @@ -14,4 +14,6 @@ source "ext/lib/crypto/Kconfig" source "ext/debug/Kconfig" +source "ext/multicore/rpmsg_lite/Kconfig" + endmenu diff --git a/ext/hal/nxp/mcux/CMakeLists.txt b/ext/hal/nxp/mcux/CMakeLists.txt index 2372bb5f937e..dd694ab3048a 100644 --- a/ext/hal/nxp/mcux/CMakeLists.txt +++ b/ext/hal/nxp/mcux/CMakeLists.txt @@ -5,7 +5,12 @@ string(TOUPPER ${CONFIG_SOC} MCUX_DEVICE) if("${MCUX_DEVICE}" STREQUAL "LPC54114") set(MCUX_CPU CPU_${CONFIG_SOC_PART_NUMBER}_cm4) else() - set(MCUX_CPU CPU_${CONFIG_SOC_PART_NUMBER}) + if("${MCUX_DEVICE}" STREQUAL "LPC54114_M0") + set(MCUX_CPU CPU_${CONFIG_SOC_PART_NUMBER}_cm0plus) + set(MCUX_DEVICE LPC54114) + else() + set(MCUX_CPU CPU_${CONFIG_SOC_PART_NUMBER}) + endif() endif() zephyr_include_directories(devices/${MCUX_DEVICE}) @@ -30,3 +35,7 @@ add_subdirectory_ifdef( CONFIG_IEEE802154_KW41Z middleware/wireless/framework_5.3.3 ) + +enable_language(C ASM) + +zephyr_sources_ifdef(CONFIG_SOC_LPC54114 devices/${MCUX_DEVICE}/amp_startup.S) diff --git a/ext/hal/nxp/mcux/devices/LPC54114/amp_startup.S b/ext/hal/nxp/mcux/devices/LPC54114/amp_startup.S new file mode 100644 index 000000000000..4481ece4ba61 --- /dev/null +++ b/ext/hal/nxp/mcux/devices/LPC54114/amp_startup.S @@ -0,0 +1,140 @@ +/** + * @file + * @brief System/hardware module for nxp_lpc54114 platform + * + * This module provides routines to initialize and support board-level + * hardware for the nxp_lpc54114 platform. + */ + +/* ---------------------------------------------------------------------------------------*/ +/* @file: startup_LPC54114_cm4.S */ +/* @purpose: CMSIS Cortex-M4 Core Device Startup File */ +/* LPC54114_cm4 */ +/* @version: 1.0 */ +/* @date: 2016-11-2 */ +/* @build: b161214 */ +/* ---------------------------------------------------------------------------------------*/ +/* */ +/* Copyright 1997-2016 Freescale Semiconductor, Inc. */ +/* Copyright 2016-2017 NXP */ +/* Redistribution and use in source and binary forms, with or without modification, */ +/* are permitted provided that the following conditions are met: */ +/* */ +/* 1. Redistributions of source code must retain the above copyright notice, this list */ +/* of conditions and the following disclaimer. */ +/* */ +/* 2. Redistributions in binary form must reproduce the above copyright notice, this */ +/* list of conditions and the following disclaimer in the documentation and/or */ +/* other materials provided with the distribution. */ +/* */ +/* 3. Neither the name of the copyright holder nor the names of its */ +/* contributors may be used to endorse or promote products derived from this */ +/* software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ +/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ +/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ +/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ +/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ +/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ +/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ +/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*****************************************************************************/ +/* Version: GCC for ARM Embedded Processors */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PLATFORM_SPECIFIC_INIT) && defined(CONFIG_SOC_LPC54114) + + .syntax unified + .arch armv7-m + .text + .thumb + +rel_vals: + .long 0xE000ED00 /* cpu_id */ + .long 0x40000800 /* cpu_ctrl */ + .long 0x40000804 /* coproc_boot */ + .long 0x40000808 /* coproc_stack */ + .short 0x0FFF + .short 0x0C24 + +GTEXT(_PlatformInit) +SECTION_FUNC(TEXT,_PlatformInit) + +/* Both the M0+ and M4 core come via this shared startup code, + * but the M0+ and M4 core have different vector tables. + * Determine if the core executing this code is the master or + * the slave and handle each core state individually. */ + +shared_boot_entry: + ldr r6, =rel_vals + + /* Flag for slave core (0) */ + movs r4, 0 + movs r5, 1 + + /* Determine which core (M0+ or M4) this code is running on */ + /* r2 = (((*cpu_id) >> 4) & 0xFFF); (M4 core == 0xC24) */ +get_current_core_id: + ldr r0, [r6, #0] + ldr r1, [r0] /* r1 = CPU ID status */ + lsrs r1, r1, #4 /* Right justify 12 CPU ID bits */ + ldrh r2, [r6, #16] /* Mask for CPU ID bits */ + ands r2, r1, r2 /* r2 = ARM COrtex CPU ID */ + ldrh r3, [r6, #18] /* Mask for CPU ID bits */ + cmp r3, r2 /* Core ID matches M4 identifier */ + bne get_master_status + mov r4, r5 /* Set flag for master core (1) */ + + /* Determine if M4 core is the master or slave */ + /* r3 = ((*cpu_ctrl) & 1); (0 == m0+, 1 == M4) */ +get_master_status: + ldr r0, [r6, #4] + ldr r3, [r0] /* r3 = SYSCON co-processor CPU control status */ + + ands r3, r3, r5 /* r3 = (Bit 0: 1 = M4 is master, 0 = M4 is slave) */ + + /* Select boot based on selected master core and core ID */ + +select_boot: + eors r3, r3, r4 /* r4 = (Bit 0: 0 = master, 1 = slave) */ + + bne slave_boot + b normal_boot + + /* Slave boot */ +slave_boot: + ldr r0, [r6, #8] + ldr r2, [r0] /* r1 = SYSCON co-processor boot address */ + + cmp r2, #0 /* Slave boot address = 0 (not set up)? */ + + beq cpu_sleep + ldr r0, [r6, #12] + ldr r1, [r0] /* r5 = SYSCON co-processor stack address */ + + mov sp, r1 /* Update slave CPU stack pointer */ + + /* Be sure to update VTOR for the slave MCU to point to the */ + /* slave vector table in boot memory */ + bx r2 /* Jump to slave boot address */ + + /* Slave isn't yet setup for system boot from the master */ + /* so sleep until the master sets it up and then reboots it */ +cpu_sleep: + mov sp, r5 /* Will force exception if something happens */ +cpu_sleep_wfi: + wfi /* Sleep forever until master reboots */ + b cpu_sleep_wfi +normal_boot: + bx lr + +#endif diff --git a/ext/hal/nxp/mcux/devices/LPC54114/incbin.S b/ext/hal/nxp/mcux/devices/LPC54114/incbin.S new file mode 100644 index 000000000000..c135f4b8fa22 --- /dev/null +++ b/ext/hal/nxp/mcux/devices/LPC54114/incbin.S @@ -0,0 +1,44 @@ +;/* +; * Copyright 2016 Freescale Semiconductor, Inc. +; * Copyright 2016 - 2017 NXP +; * +; * Redistribution and use in source and binary forms, with or without modification, +; * are permitted provided that the following conditions are met: +; * +; * o Redistributions of source code must retain the above copyright notice, this list +; * of conditions and the following disclaimer. +; * +; * o Redistributions in binary form must reproduce the above copyright notice, this +; * list of conditions and the following disclaimer in the documentation and/or +; * other materials provided with the distribution. +; * +; * o Neither the name of the copyright holder nor the names of its +; * contributors may be used to endorse or promote products derived from this +; * software without specific prior written permission. +; * +; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +; * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +; * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +; * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +; * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +; * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +; * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +; */ + .section .m0code , "ax" @progbits @preinit_array + .global m0_image_start + .type m0_image_start, %object + .align 4 +m0_image_start: + .incbin "core1_image.bin" + .global m0_image_end + .type m0_image_end, %object +m0_image_end: + .global m0_image_size + .type m0_image_size, %object + .align 4 +m0_image_size: + .int m0_image_end - m0_image_start + .end diff --git a/ext/multicore/CMakeLists.txt b/ext/multicore/CMakeLists.txt new file mode 100644 index 000000000000..229c0316135a --- /dev/null +++ b/ext/multicore/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory_ifdef(MULTICORE_RPMSG_LITE rpmsg_lite) diff --git a/ext/multicore/rpmsg_lite/Kconfig b/ext/multicore/rpmsg_lite/Kconfig new file mode 100644 index 000000000000..602bff1de26e --- /dev/null +++ b/ext/multicore/rpmsg_lite/Kconfig @@ -0,0 +1,17 @@ +# Kconfig - Shell configuration options + +# +# Copyright 2018 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config MULTICORE_RPMSG_LITE + bool + prompt "Enable Remote Processor Messaging Lite library" + default n + help + Remote Processor Messaging Lite library implementation. + + + diff --git a/ext/multicore/rpmsg_lite/LICENSE b/ext/multicore/rpmsg_lite/LICENSE new file mode 100644 index 000000000000..824efe584444 --- /dev/null +++ b/ext/multicore/rpmsg_lite/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2014-2016 Freescale Semiconductor, Inc. +Copyright (c) 2014, Mentor Graphics Corporation +Copyright (c) 2015 Xilinx, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +o Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + +o Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +o Neither the name of Freescale Semiconductor, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/multicore/rpmsg_lite/README.md b/ext/multicore/rpmsg_lite/README.md new file mode 100644 index 000000000000..fdac80ae4339 --- /dev/null +++ b/ext/multicore/rpmsg_lite/README.md @@ -0,0 +1,84 @@ +RPMsg Component +=============== + +This documentation describes the RPMsg-Lite component which is a lightweight implementation of the Remote Processor Messaging (RPMsg) protocol. The RPMsg protocol defines a standardized binary interface used to communicate between multiple cores in a heterogeneous multicore system. + +Compared to the RPMsg implementation of the Open Asymmetric Multi Processing (OpenAMP) framework (https://github.com/OpenAMP/open-amp), the RPMsg-Lite offers a code size reduction, API simplification and improved modularity. On smaller Cortex-M0+ based systems, it is recommended to use RPMsg-Lite. + +The RPMsg-Lite is an open-source component developed by NXP Semiconductor and released under the BSD compatible license. + +For Further documentation, please look at doxygen documentation at: https://nxpmicro.github.io/rpmsg-lite/ + +# Motivation to create RPMsg-Lite + +There are multiple reasons why RPMsg-Lite was developed. One of them is the need for small footprint RPMsg protocol compatible communication component, another is a simplification of extensive API of OpenAMP RPMsg implementation. + +Until recently, RPMsg protocol was not documented and its only definition was given by the Linux Kernel and legacy OpenAMP implementations. This changed with [1] which is a standardization protocol, allowing multiple different implementations to coexist and still be compatible mutually. + +Small MCU-based systems often do not implement dynamic memory allocation. The creation of static API in RPMsg-Lite enables another reduction of resource usage. Not only the dynamic allocation adds another 5kB of code size, but also the communication is slower and less deterministic, which is a property introduced by dynamic memory. Following table shows some rough comparison data between the OpenAMP RPMsg implementation and new RPMsg-Lite implementation: + +|Component / Configuration | Flash [B] |RAM [B] | +|---------------------------------------------|-----------|---------------| +|OpenAMP RPMSG / Release (reference) | 5547 | 456 + dynamic | +|RPMSG-Lite / Dynamic API, Release | 3462 | 56 + dynamic | +|Relative Difference [%] | ~62.4% | ~12.3% | +|RPMSG-Lite / Static API (no malloc), Release | 2926 | 352 | +|Relative Difference [%] | ~52.7% | ~77.2% | + +# Implementation + +The implementation of RPMsg-Lite can be divided into three sub-components, from which two are optional. The core component is situated in rpmsg_lite.c. Two optional components are used to implement a blocking receive API (in rpmsg_queue.c) and dynamic "named" endpoint creation and deletion announcement service (in rpmsg_ns.c). + +The actual "media access" layer is implemented in virtqueue.c, which is one of few files shared with the OpenAMP implementation. This layer mainly defines the shared memory model and defines internally used components such as vring or virtqueue. + +The porting layer is split into two sub-layers: the environment layer and the platform layer. The first one is to be implemented separately for each environment. (There already exist the bare-metal environment implemented in env_bm.c and the FreeRTOS environment implemented in env_freertos.c etc.) Only the source file which matches the used environment is included in the target application project. The second sublayer is implemented in platform.c and it defines low-level functions for interrupt enabling, disabling and triggering mainly. The situation is described in the following figure: + +![RPMsg-Lite Architecture](./doxygen/images/rpmsg_lite_arch.png) + +## RPMsg-Lite core sub-component + +This sub-component implements a blocking send API and callback-based receive API. RPMsg protocol is part of the transport layer. This is realized by using so-called endpoints. Each endpoint can be assigned a different receive callback function. It is however important to notice, that the callback is executed in an interrupt environment in current design. Certain actions like memory allocation is therefore discouraged to execute in the callback. Following figure shows the role of RPMsg in an ISO/OSI-like layered model: + +![RPMsg ISO/OSI Layered Model](./doxygen/images/rpmsg_isoosi.png) + +## Queue sub-component (optional) + +This sub-component is optional and it requires to implement env_*_queue() functions in the environment porting layer. It brings a blocking receive API which is common in RTOS-environments. It supports both copy and no-copy blocking receive functions. + +## Name Service sub-component (optional) + +This sub-component is a minimum implementation of the name service which is present in the Linux Kernel implementation of RPMsg. It allows the communicating node both to send announcements about "named" endpoint (a.k.a channel) creation or deletion and to receive these announcement taking any user-defined action in an application callback. The endpoint address used to receive name service announcements is arbitrarily fixed to be 53 (0x35). + +# Usage + +Your application should put the /rpmsg_lite/lib/include directory to the include path and then, in the application include either just rpmsg_lite.h header file, or optionally also rpmsg_queue.h and/or rpmsg_ns.h. Both porting sub-layers should be provided for you by NXP, but if you plan to use your own RTOS, all you need to do is to implement your own environment layer (i.e. env_myrtos.c) and to include it in the project build. + +The initialization of the stack is done by calling the rpmsg_lite_master_init() on the master side and the rpmsg_lite_remote_init() on the remote side. This initialization function must be called prior to any RPMsg-Lite API call. After the init, it is wise to create a communication endpoint, otherwise the communication is not possible. This can be done by calling rpmsg_lite_create_ept() function. It accepts optionally a last argument, where an internal context of the endpoint is created – just in case the RL_USE_STATIC_API option is set to 1. If not, the stack calls internally env_alloc() to allocate dynamic memory for it. In case a callback-based receiving is to be used, an ISR-callback is registered to each new endpoint with user-defined callback data pointer. If a blocking receive is desired (in case of RTOS environment), rpmsg_queue_create() function must be called before calling rpmsg_lite_create_ept(). The queue handle is passed to the endpoint creation function as a callback data argument and the callback function is set to rpmsg_queue_rx_cb(). Then, it is possible to use rpmsg_queue_receive() function to listen on a queue object for incoming messages. rpmsg_lite_send() function is used to send messages to the other side. + +The RPMsg-Lite also implements no-copy mechanisms for both sending and receiving operations. These methods require +specifics that have to be considered when used in an application. + +no-copy-send mechanism: This mechanism allows sending messages without the cost for copying data from the application +buffer to the RPMsg/virtio buffer in the shared memory. The sequence of no-copy sending steps to be performed is as follows: +- Call the rpmsg_lite_alloc_tx_buffer() function to get the virtio buffer and provide the buffer pointer to the application. +- Fill the data to be sent into the pre-allocated virtio buffer. Ensure that the filled data does not exceed the buffer size +(provided as the rpmsg_lite_alloc_tx_buffer() size output parameter). +- Call the rpmsg_lite_send_nocopy() function to send the message to the destination endpoint. Consider the cache +functionality and the virtio buffer alignment. See the rpmsg_lite_send_nocopy() function description below. + +no-copy-receive mechanism: This mechanism allows reading messages without the cost for copying data from the virtio +buffer in the shared memory to the application buffer. The sequence of no-copy receiving steps to be performed is as follows: +- Call the rpmsg_queue_recv_nocopy() function to get the virtio buffer pointer to the received data. +- Read received data directly from the shared memory. +- Call the rpmsg_queue_nocopy_free() function to release the virtio buffer and to make it available for the next data transfer. + +The user is responsible for destroying any RPMsg-Lite objects he has created in case of deinitialization. For this, the function rpmsg_queue_destroy() is used to destroy a queue, rpmsg_lite_destroy_ept() is used to destroy an endpoint and finally, rpmsg_lite_deinit() is used to deinitialize the RPMsg-Lite intercore communication stack. Please take care to deinitialize all endpoints using a queue before deinitializing the queue, otherwise you are invalidating actively used queue handle, which is not allowed. RPMsg-Lite does not check this internally, since its main aim is to be lightweight. + +![RPMsg Lite copy and no-copy interface, multiple scenarios](./doxygen/images/rpmsg_lite_send_receive.png) + + +# References +[1] M. Novak, M. Cingel, Lockless Shared Memory Based Multicore Communication Protocol + +--- +Copyright © 2016 Freescale Semiconductor, Inc. diff --git a/ext/multicore/rpmsg_lite/lib/common/llist.c b/ext/multicore/rpmsg_lite/lib/common/llist.c new file mode 100644 index 000000000000..618403e68f2e --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/common/llist.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * llist.c + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * Source file for basic linked list service. + * + **************************************************************************/ +#include "llist.h" + +#define LIST_NULL ((void *)0) +/*! + * add_to_list + * + * Places new element at the start of the list. + * + * @param head - list head + * @param node - new element to add + * + */ +void add_to_list(struct llist **head, struct llist *node) +{ + if (!node) + return; + + if (*head) + { + /* Place the new element at the start of list. */ + node->next = *head; + node->prev = LIST_NULL; + (*head)->prev = node; + *head = node; + } + else + { + /* List is empty - assign new element to list head. */ + *head = node; + (*head)->next = LIST_NULL; + (*head)->prev = LIST_NULL; + } +} + +/*! + * remove_from_list + * + * Removes the given element from the list. + * + * @param head - list head + * @param element - element to remove from list + * + */ +void remove_from_list(struct llist **head, struct llist *node) +{ + if (!(*head) || !(node)) + return; + + if (node == *head) + { + /* First element has to be removed. */ + *head = (*head)->next; + } + else if (node->next == LIST_NULL) + { + /* Last element has to be removed. */ + node->prev->next = node->next; + } + else + { + /* Intermediate element has to be removed. */ + node->prev->next = node->next; + node->next->prev = node->prev; + } +} diff --git a/ext/multicore/rpmsg_lite/lib/include/llist.h b/ext/multicore/rpmsg_lite/lib/include/llist.h new file mode 100644 index 000000000000..ae744916f7b1 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/llist.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * llist.h + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * Header file for linked list service. + * + **************************************************************************/ + +#ifndef LLIST_H_ +#define LLIST_H_ + +struct llist +{ + void *data; + unsigned int attr; + struct llist *next; + struct llist *prev; +}; + +void add_to_list(struct llist **head, struct llist *node); +void remove_from_list(struct llist **head, struct llist *node); + +#endif /* LLIST_H_ */ diff --git a/ext/multicore/rpmsg_lite/lib/include/platform/imx6sx_m4/rpmsg_platform.h b/ext/multicore/rpmsg_lite/lib/include/platform/imx6sx_m4/rpmsg_platform.h new file mode 100644 index 000000000000..501b00b24f69 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/platform/imx6sx_m4/rpmsg_platform.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_SYSTEM_H +#define _MACHINE_SYSTEM_H + +/* RPMSG MU channel index */ +#define RPMSG_MU_CHANNEL (1) + +/* + * Linux requires the ALIGN to 0x1000(4KB) instead of 0x80 + */ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x1000) +#endif + +/* contains pool of descriptors and two circular buffers */ +#ifndef VRING_SIZE +#define VRING_SIZE (0x8000) +#endif + +/* size of shared memory + 2*VRING size */ +#define RL_VRING_OVERHEAD (2 * VRING_SIZE) + +#define RL_GET_VQ_ID(core_id, queue_id) (((queue_id)&0x1) | (((core_id) << 1) & 0xFFFFFFFE)) +#define RL_GET_LINK_ID(id) (((id)&0xFFFFFFFE) >> 1) +#define RL_GET_Q_ID(id) ((id)&0x1) + +#define RL_PLATFORM_IMX6SX_M4_LINK_ID (0) +#define RL_PLATFORM_HIGHEST_LINK_ID (0) + +/* platform interrupt related functions */ +int platform_init_interrupt(int vector_id, void *isr_data); +int platform_deinit_interrupt(int vector_id); +int platform_interrupt_enable(unsigned int vector_id); +int platform_interrupt_disable(unsigned int vector_id); +int platform_in_isr(void); +void platform_notify(int vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(int num_msec); + +/* platform memory functions */ +void platform_map_mem_region(unsigned int va, unsigned int pa, unsigned int size, unsigned int flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +unsigned long platform_vatopa(void *addr); +void *platform_patova(unsigned long addr); + +/* platform init/deinit */ +int platform_init(void); +int platform_deinit(void); +void rpmsg_handler(void); + +#endif /* _MACHINE_SYSTEM_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/platform/imx7d_m4/rpmsg_platform.h b/ext/multicore/rpmsg_lite/lib/include/platform/imx7d_m4/rpmsg_platform.h new file mode 100644 index 000000000000..501b00b24f69 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/platform/imx7d_m4/rpmsg_platform.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_SYSTEM_H +#define _MACHINE_SYSTEM_H + +/* RPMSG MU channel index */ +#define RPMSG_MU_CHANNEL (1) + +/* + * Linux requires the ALIGN to 0x1000(4KB) instead of 0x80 + */ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x1000) +#endif + +/* contains pool of descriptors and two circular buffers */ +#ifndef VRING_SIZE +#define VRING_SIZE (0x8000) +#endif + +/* size of shared memory + 2*VRING size */ +#define RL_VRING_OVERHEAD (2 * VRING_SIZE) + +#define RL_GET_VQ_ID(core_id, queue_id) (((queue_id)&0x1) | (((core_id) << 1) & 0xFFFFFFFE)) +#define RL_GET_LINK_ID(id) (((id)&0xFFFFFFFE) >> 1) +#define RL_GET_Q_ID(id) ((id)&0x1) + +#define RL_PLATFORM_IMX6SX_M4_LINK_ID (0) +#define RL_PLATFORM_HIGHEST_LINK_ID (0) + +/* platform interrupt related functions */ +int platform_init_interrupt(int vector_id, void *isr_data); +int platform_deinit_interrupt(int vector_id); +int platform_interrupt_enable(unsigned int vector_id); +int platform_interrupt_disable(unsigned int vector_id); +int platform_in_isr(void); +void platform_notify(int vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(int num_msec); + +/* platform memory functions */ +void platform_map_mem_region(unsigned int va, unsigned int pa, unsigned int size, unsigned int flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +unsigned long platform_vatopa(void *addr); +void *platform_patova(unsigned long addr); + +/* platform init/deinit */ +int platform_init(void); +int platform_deinit(void); +void rpmsg_handler(void); + +#endif /* _MACHINE_SYSTEM_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/platform/lpc5410x/rpmsg_platform.h b/ext/multicore/rpmsg_lite/lib/include/platform/lpc5410x/rpmsg_platform.h new file mode 100644 index 000000000000..c7addb29cfca --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/platform/lpc5410x/rpmsg_platform.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_SYSTEM_H +#define _MACHINE_SYSTEM_H + +/* +* No need to align the VRING as defined in Linux because LPC54102 is not intended +* to run the Linux +*/ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x10) +#endif + +/* contains pool of descriptos and two circular buffers */ +#ifndef VRING_SIZE +#define VRING_SIZE (0x400) +#endif + +/* size of shared memory + 2*VRING size */ +#define RL_VRING_OVERHEAD (2 * VRING_SIZE) + +#define RL_GET_VQ_ID(core_id, queue_id) (((queue_id)&0x1) | (((core_id) << 1) & 0xFFFFFFFE)) +#define RL_GET_LINK_ID(id) (((id)&0xFFFFFFFE) >> 1) +#define RL_GET_Q_ID(id) ((id)&0x1) + +#define RL_PLATFORM_LPC5410x_M4_M0_LINK_ID (0) +#define RL_PLATFORM_HIGHEST_LINK_ID (0) + +/* platform interrupt related functions */ +int platform_init_interrupt(int vector_id, void *isr_data); +int platform_deinit_interrupt(int vector_id); +int platform_interrupt_enable(unsigned int vector_id); +int platform_interrupt_disable(unsigned int vector_id); +int platform_in_isr(void); +void platform_notify(int vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(int num_msec); + +/* platform memory functions */ +void platform_map_mem_region(unsigned int va, unsigned int pa, unsigned int size, unsigned int flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +unsigned long platform_vatopa(void *addr); +void *platform_patova(unsigned long addr); + +/* platform init/deinit */ +int platform_init(void); +int platform_deinit(void); + +#endif /* _MACHINE_SYSTEM_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/platform/lpc5411x/rpmsg_platform.h b/ext/multicore/rpmsg_lite/lib/include/platform/lpc5411x/rpmsg_platform.h new file mode 100644 index 000000000000..1413b7db8346 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/platform/lpc5411x/rpmsg_platform.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_SYSTEM_H +#define _MACHINE_SYSTEM_H + +/* +* No need to align the VRING as defined in Linux because LPC5411x is not intended +* to run the Linux +*/ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x10) +#endif + +/* contains pool of descriptos and two circular buffers */ +#ifndef VRING_SIZE +#define VRING_SIZE (0x400) +#endif + +/* size of shared memory + 2*VRING size */ +#define RL_VRING_OVERHEAD (2 * VRING_SIZE) + +#define RL_GET_VQ_ID(core_id, queue_id) (((queue_id)&0x1) | (((core_id) << 1) & 0xFFFFFFFE)) +#define RL_GET_LINK_ID(id) (((id)&0xFFFFFFFE) >> 1) +#define RL_GET_Q_ID(id) ((id)&0x1) + +#define RL_PLATFORM_LPC5411x_M4_M0_LINK_ID (0) +#define RL_PLATFORM_HIGHEST_LINK_ID (0) + +/* platform interrupt related functions */ +int platform_init_interrupt(int vector_id, void *isr_data); +int platform_deinit_interrupt(int vector_id); +int platform_interrupt_enable(unsigned int vector_id); +int platform_interrupt_disable(unsigned int vector_id); +int platform_in_isr(void); +void platform_notify(int vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(int num_msec); + +/* platform memory functions */ +void platform_map_mem_region(unsigned int va, unsigned int pa, unsigned int size, unsigned int flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +unsigned long platform_vatopa(void *addr); +void *platform_patova(unsigned long addr); + +/* platform init/deinit */ +int platform_init(void); +int platform_deinit(void); + +#endif /* _MACHINE_SYSTEM_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_compiler.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_compiler.h new file mode 100644 index 000000000000..91f063e8f3bc --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_compiler.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * rpmsg_compiler.h + * + * DESCRIPTION + * + * This file defines compiler-specific macros. + * + ***************************************************************************/ +#ifndef _RPMSG_COMPILER_H_ +#define _RPMSG_COMPILER_H_ + +/* IAR ARM build tools */ +#if defined(__ICCARM__) + +#include + +#define MEM_BARRIER() __DSB() + +#ifndef RL_PACKED_BEGIN +#define RL_PACKED_BEGIN __packed +#endif + +#ifndef RL_PACKED_END +#define RL_PACKED_END +#endif + +/* GNUC */ +#elif defined(__GNUC__) + +#define MEM_BARRIER() __asm volatile("dsb" : : : "memory") + +#ifndef RL_PACKED_BEGIN +#define RL_PACKED_BEGIN +#endif + +#ifndef RL_PACKED_END +#define RL_PACKED_END __attribute__((__packed__)) +#endif + +/* ARM GCC */ +#elif defined(__CC_ARM) + +#define MEM_BARRIER() __schedule_barrier() + +#ifndef RL_PACKED_BEGIN +#define RL_PACKED_BEGIN _Pragma("pack(1U)") +#endif + +#ifndef RL_PACKED_END +#define RL_PACKED_END _Pragma("pack()") +#endif + +#else +/* There is no default definition here to avoid wrong structures packing in case of not supported compiler */ +#error Please implement the structure packing macros for your compiler here! +#endif + +#endif /* _RPMSG_COMPILER_H_ */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_default_config.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_default_config.h new file mode 100644 index 000000000000..a2daa5757c83 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_default_config.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RPMSG_DEFAULT_CONFIG_H +#define _RPMSG_DEFAULT_CONFIG_H + +#define RL_USE_CUSTOM_CONFIG (1) + +#if RL_USE_CUSTOM_CONFIG +#include "rpmsg_config.h" +#endif + +/* default values */ +/* START { */ +#ifndef RL_MS_PER_INTERVAL +#define RL_MS_PER_INTERVAL (1) +#endif + +#ifndef RL_BUFFER_PAYLOAD_SIZE +#define RL_BUFFER_PAYLOAD_SIZE (496) +#endif + +#ifndef RL_BUFFER_COUNT +#define RL_BUFFER_COUNT (2) +#endif + +#ifndef RL_API_HAS_ZEROCOPY +#define RL_API_HAS_ZEROCOPY (1) +#endif + +#ifndef RL_USE_STATIC_API +#define RL_USE_STATIC_API (0) +#endif + +#ifndef RL_CLEAR_USED_BUFFERS +#define RL_CLEAR_USED_BUFFERS (0) +#endif + +#ifndef RL_USE_MCMGR_IPC_ISR_HANDLER +#define RL_USE_MCMGR_IPC_ISR_HANDLER (0) +#endif + +#ifndef RL_ASSERT +#define RL_ASSERT_BOOL(b) \ + do \ + { \ + if (!(b)) \ + while (1) \ + ; \ + } while (0); +#define RL_ASSERT(x) RL_ASSERT_BOOL((x)!=0) +#endif +/* } END */ + +#endif /* _RPMSG_DEFAULT_CONFIG_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_env.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_env.h new file mode 100644 index 000000000000..009e01f5b430 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_env.h @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** +* FILE NAME +* +* rpmsg_env.h +* +* COMPONENT +* +* OpenAMP stack. +* +* DESCRIPTION +* +* This file defines abstraction layer for OpenAMP stack. The implementor +* must provide definition of all the functions. +* +* DATA STRUCTURES +* +* none +* +* FUNCTIONS +* +* env_allocate_memory +* env_free_memory +* env_memset +* env_memcpy +* env_strlen +* env_strcpy +* env_strncpy +* env_print +* env_map_vatopa +* env_map_patova +* env_mb +* env_rmb +* env_wmb +* env_create_mutex +* env_delete_mutex +* env_lock_mutex +* env_unlock_mutex +* env_sleep_msec +* env_disable_interrupt +* env_enable_interrupt +* env_create_queue +* env_delete_queue +* env_put_queue +* env_get_queue +* +**************************************************************************/ +#ifndef _RPMSG_ENV_H_ +#define _RPMSG_ENV_H_ + +#include +#include "rpmsg_default_config.h" +#include "rpmsg_platform.h" + +/*! + * env_init + * + * Initializes OS/BM environment. + * + * @returns - execution status + */ + +int env_init(void); + +/*! + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns - execution status + */ + +int env_deinit(void); +/*! + * ------------------------------------------------------------------------- + * + * Dynamic memory management functions. The parameters + * are similar to standard c functions. + * + *------------------------------------------------------------------------- + **/ + +/*! + * env_allocate_memory + * + * Allocates memory with the given size. + * + * @param size - size of memory to allocate + * + * @return - pointer to allocated memory + */ +void *env_allocate_memory(unsigned int size); + +/*! + * env_free_memory + * + * Frees memory pointed by the given parameter. + * + * @param ptr - pointer to memory to free + */ +void env_free_memory(void *ptr); + +/*! + * ------------------------------------------------------------------------- + * + * RTL Functions + * + *------------------------------------------------------------------------- + */ + +void env_memset(void *ptr, int value, unsigned long size); +void env_memcpy(void *dst, void const *src, unsigned long len); +size_t env_strlen(const char *str); +void env_strcpy(char *dest, const char *src); +int env_strcmp(const char *dst, const char *src); +void env_strncpy(char *dest, const char *src, unsigned long len); +int env_strncmp(char *dest, const char *src, unsigned long len); +#define env_print(...) printf(__VA_ARGS__) + +/*! + *----------------------------------------------------------------------------- + * + * Functions to convert physical address to virtual address and vice versa. + * + *----------------------------------------------------------------------------- + */ + +/*! + * env_map_vatopa + * + * Converts logical address to physical address + * + * @param address - pointer to logical address + * + * @return - physical address + */ +unsigned long env_map_vatopa(void *address); + +/*! + * env_map_patova + * + * Converts physical address to logical address + * + * @param address - pointer to physical address + * + * @return - logical address + * + */ +void *env_map_patova(unsigned long address); + +/*! + *----------------------------------------------------------------------------- + * + * Abstractions for memory barrier instructions. + * + *----------------------------------------------------------------------------- + */ + +/*! + * env_mb + * + * Inserts memory barrier. + */ + +void env_mb(void); + +/*! + * env_rmb + * + * Inserts read memory barrier + */ + +void env_rmb(void); + +/*! + * env_wmb + * + * Inserts write memory barrier + */ + +void env_wmb(void); + +/*! + *----------------------------------------------------------------------------- + * + * Abstractions for OS lock primitives. + * + *----------------------------------------------------------------------------- + */ + +/*! + * env_create_mutex + * + * Creates a mutex with given initial count. + * + * @param lock - pointer to created mutex + * @param count - initial count 0 or 1 + * + * @return - status of function execution + */ +int env_create_mutex(void **lock, int count); + +/*! + * env_delete_mutex + * + * Deletes the given lock. + * + * @param lock - mutex to delete + */ + +void env_delete_mutex(void *lock); + +/*! + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + * + * @param lock - mutex to lock + * + */ + +void env_lock_mutex(void *lock); + +/*! + * env_unlock_mutex + * + * Releases the given lock. + * + * @param lock - mutex to unlock + */ + +void env_unlock_mutex(void *lock); + +/*! + * env_create_sync_lock + * + * Creates a synchronization lock primitive. It is used + * when signal has to be sent from the interrupt context to main + * thread context. + * + * @param lock - pointer to created sync lock object + * @param state - initial state , lock or unlocked + * + * @returns - status of function execution + */ +#define LOCKED 0 +#define UNLOCKED 1 + +int env_create_sync_lock(void **lock, int state); + +/*! + * env_create_sync_lock + * + * Deletes given sync lock object. + * + * @param lock - sync lock to delete. + * + */ + +void env_delete_sync_lock(void *lock); + +/*! + * env_acquire_sync_lock + * + * Tries to acquire the sync lock. + * + * @param lock - sync lock to acquire. + */ +void env_acquire_sync_lock(void *lock); + +/*! + * env_release_sync_lock + * + * Releases synchronization lock. + * + * @param lock - sync lock to release. + */ +void env_release_sync_lock(void *lock); + +/*! + * env_sleep_msec + * + * Suspends the calling thread for given time in msecs. + * + * @param num_msec - delay in msecs + */ +void env_sleep_msec(int num_msec); + +/*! + * env_register_isr + * + * Registers interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + * @param data - interrupt handler data (virtqueue) + */ +void env_register_isr(int vector_id, void *data); + +/*! + * env_unregister_isr + * + * Unregisters interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + */ +void env_unregister_isr(int vector_id); + +/*! + * env_enable_interrupt + * + * Enables the given interrupt + * + * @param vector_id - interrupt vector number + */ + +void env_enable_interrupt(unsigned int vector_id); + +/*! + * env_disable_interrupt + * + * Disables the given interrupt. + * + * @param vector_id - interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector_id); + +/*! + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + * + * Currently only first byte of flag parameter is used and bits mapping is defined as follow; + * + * Cache bits + * 0x0000_0001 = No cache + * 0x0000_0010 = Write back + * 0x0000_0100 = Write through + * 0x0000_x000 = Not used + * + * Memory types + * + * 0x0001_xxxx = Memory Mapped + * 0x0010_xxxx = IO Mapped + * 0x0100_xxxx = Shared + * 0x1000_xxxx = TLB + */ + +/* Macros for caching scheme used by the shared memory */ +#define UNCACHED (1 << 0) +#define WB_CACHE (1 << 1) +#define WT_CACHE (1 << 2) + +/* Memory Types */ +#define MEM_MAPPED (1 << 4) +#define IO_MAPPED (1 << 5) +#define SHARED_MEM (1 << 6) +#define TLB_MEM (1 << 7) + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, unsigned int flags); + +/*! + * env_get_timestamp + * + * Returns a 64 bit time stamp. + * + * + */ +unsigned long long env_get_timestamp(void); + +/*! + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache(void); + +typedef void LOCK; + +/*! + * env_create_queue + * + * Creates a message queue. + * + * @param queue - pointer to created queue + * @param length - maximum number of elements in the queue + * @param item_size - queue element size in bytes + * + * @return - status of function execution + */ +int env_create_queue(void **queue, int length, int element_size); + +/*! + * env_delete_queue + * + * Deletes the message queue. + * + * @param queue - queue to delete + */ + +void env_delete_queue(void *queue); + +/*! + * env_put_queue + * + * Put an element in a queue. + * + * @param queue - queue to put element in + * @param msg - pointer to the message to be put into the queue + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_put_queue(void *queue, void *msg, int timeout_ms); + +/*! + * env_get_queue + * + * Get an element out of a queue. + * + * @param queue - queue to get element from + * @param msg - pointer to a memory to save the message + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_get_queue(void *queue, void *msg, int timeout_ms); + +/*! + * env_isr + * + * Invoke RPMSG/IRQ callback + * + * @param vector - RPMSG IRQ vector ID. + */ + +void env_isr(int vector); + +#endif /* _RPMSG_ENV_H_ */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_lite.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_lite.h new file mode 100644 index 000000000000..7ef9173d790f --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_lite.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RPMSG_LITE_H +#define _RPMSG_LITE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include "virtqueue.h" +#include "rpmsg_env.h" +#include "llist.h" +#include "rpmsg_compiler.h" + +//! @addtogroup rpmsg_lite +//! @{ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define RL_VERSION "1.2.0" /*!< Current RPMsg Lite version */ + +/* Shared memory "allocator" parameters */ +#define RL_WORD_SIZE (sizeof(unsigned long)) +#define RL_WORD_ALIGN_UP(a) \ + (((((unsigned long)a) & (RL_WORD_SIZE - 1)) != 0) ? ((((unsigned long)a) & (~(RL_WORD_SIZE - 1))) + 4) : \ + ((unsigned long)a)) +#define RL_WORD_ALIGN_DOWN(a) \ + (((((unsigned long)a) & (RL_WORD_SIZE - 1)) != 0) ? (((unsigned long)a) & (~(RL_WORD_SIZE - 1))) : \ + ((unsigned long)a)) + +/* Definitions for device types , null pointer, etc.*/ +#define RL_SUCCESS (0) +#define RL_NULL ((void *)0) +#define RL_REMOTE (0) +#define RL_MASTER (1) +#define RL_TRUE (1) +#define RL_FALSE (0) +#define RL_ADDR_ANY (0xFFFFFFFF) +#define RL_RELEASE (0) +#define RL_HOLD (1) +#define RL_DONT_BLOCK (0) +#define RL_BLOCK (0xFFFFFFFF) + +/* Error macros. */ +#define RL_ERRORS_BASE (-5000) +#define RL_ERR_NO_MEM (RL_ERRORS_BASE - 1) +#define RL_ERR_BUFF_SIZE (RL_ERRORS_BASE - 2) +#define RL_ERR_PARAM (RL_ERRORS_BASE - 3) +#define RL_ERR_DEV_ID (RL_ERRORS_BASE - 4) +#define RL_ERR_MAX_VQ (RL_ERRORS_BASE - 5) +#define RL_ERR_NO_BUFF (RL_ERRORS_BASE - 6) +#define RL_NOT_READY (RL_ERRORS_BASE - 7) +#define RL_ALREADY_DONE (RL_ERRORS_BASE - 8) + +/* Init flags */ +#define RL_NO_FLAGS (0) + +/*! \typedef rl_ept_rx_cb_t + \brief Receive callback function type. +*/ +typedef int (*rl_ept_rx_cb_t)(void *payload, int payload_len, unsigned long src, void *priv); + +/*! + * RPMsg Lite Endpoint structure + */ +struct rpmsg_lite_endpoint +{ + unsigned long addr; /*!< endpoint address */ + rl_ept_rx_cb_t rx_cb; /*!< ISR callback function */ + void *rx_cb_data; /*!< ISR callback data */ + void *rfu; /*!< reserved for future usage */ + /* 16 bytes aligned on 32bit architecture */ +}; + +/*! + * RPMsg Lite Endpoint static context + */ +struct rpmsg_lite_ept_static_context +{ + struct rpmsg_lite_endpoint ept; /*!< memory for endpoint structure */ + struct llist node; /*!< memory for linked list node structure */ +}; + +/*! + * Structure describing the local instance + * of RPMSG lite communication stack and + * holds all runtime variables needed internally + * by the stack. + */ +struct rpmsg_lite_instance +{ + struct virtqueue *rvq; /*!< receive virtqueue */ + struct virtqueue *tvq; /*!< transmit virtqueue */ + struct llist *rl_endpoints; /*!< linked list of endpoints */ + LOCK *lock; /*!< local RPMsg Lite mutex lock */ + unsigned int link_state; /*!< state of the link, up/down*/ + char *sh_mem_base; /*!< base address of the shared memory */ + unsigned int sh_mem_remaining; /*!< remaining free bytes of shared memory */ + unsigned int sh_mem_total; /*!< total size of shared memory */ + struct virtqueue_ops const *vq_ops; /*!< ops functions table pointer */ + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + struct vq_static_context vq_ctxt[2]; +#endif +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +/* Exported API functions */ + +/*! + * @brief Initializes the RPMsg-Lite communication stack. + * Must be called prior to any other RPMSG lite API. + * To be called by the master side. + * + * @param shmem_addr Shared memory base used for this instance of RPMsg-Lite + * @param shmem_length Length of memory area given by previous parameter + * @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h + * @param init_flags Initialization flags + * @param static_context RPMsg-Lite preallocated context pointer, used in case of static api (RL_USE_STATIC_API) +* + * @return New RPMsg-Lite instance pointer or NULL. + * + */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr, + size_t shmem_length, + int link_id, + uint32_t init_flags, + struct rpmsg_lite_instance *static_context); +#else +struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr, + size_t shmem_length, + int link_id, + uint32_t init_flags); +#endif + +/** + * @brief Initializes the RPMsg-Lite communication stack. + * Must be called prior to any other RPMsg-Lite API. + * To be called by the remote side. + * + * @param shmem_addr Shared memory base used for this instance of RPMsg-Lite + * @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h + * @param init_flags Initialization flags + * + * @return New RPMsg-Lite instance pointer or NULL. + * + */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, + int link_id, + uint32_t init_flags, + struct rpmsg_lite_instance *static_context); +#else +struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, int link_id, uint32_t init_flags); +#endif + +/*! + * + * @brief Deinitialized the RPMsg-Lite communication stack + * This function always succeeds. + * rpmsg_lite_init() can be called again after this + * function has been called. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * + * @return Status of function execution, RL_SUCCESS on success. + */ +int rpmsg_lite_deinit(struct rpmsg_lite_instance *rpmsg_lite_dev); + +/*! + * @brief Create a new rpmsg endpoint, which can be used + * for communication. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param addr Desired address, RL_ADDR_ANY for automatic selection + * @param rx_cb Callback function called on receive + * @param rx_cb_data Callback data pointer, passed to rx_cb + * @param ept_context Endpoint preallocated context pointer, used in case of static api (RL_USE_STATIC_API) + * + * @return RL_NULL on error, new endpoint pointer on success. + * + */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long addr, + rl_ept_rx_cb_t rx_cb, + void *rx_cb_data, + struct rpmsg_lite_ept_static_context *ept_context); +#else +struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long addr, + rl_ept_rx_cb_t rx_cb, + void *rx_cb_data); +#endif + +/*! + * @brief This function deletes rpmsg endpoint and performs cleanup. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param rl_ept Pointer to endpoint to destroy + * + */ +int rpmsg_lite_destroy_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, struct rpmsg_lite_endpoint *rl_ept); + +/*! + * + * @brief Sends a message contained in data field of length size + * to the remote endpoint with address dst. + * ept->addr is used as source address in the rpmsg header + * of the message being sent. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param ept Sender endpoint + * @param dst Remote endpoint address + * @param data Payload buffer + * @param size Size of payload, in bytes + * @param timeout Timeout in ms, 0 if nonblocking + * + * @return Status of function execution, RL_SUCCESS on success. + * + */ +int rpmsg_lite_send(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *ept, + unsigned long dst, + char *data, + unsigned long size, + unsigned long timeout); + +/*! + * @brief Function to get the link state + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * + * @return True when link up, false when down. + * + */ +int rpmsg_lite_is_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev); + +#if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1) + +/*! + * @brief Releases the rx buffer for future reuse in vring. + * This API can be called at process context when the + * message in rx buffer is processed. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param rxbuf Rx buffer with message payload + * + * @return Status of function execution, RL_SUCCESS on success. + */ +int rpmsg_lite_release_rx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, void *rxbuf); + +/*! + * @brief Allocates the tx buffer for message payload. + * + * This API can only be called at process context to get the tx buffer in vring. By this way, the + * application can directly put its message into the vring tx buffer without copy from an application buffer. + * It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct + * parameters to the rpmsg_lite_send_nocopy() function to perform data no-copy-send mechanism. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param[in] size Pointer to store maximum payload size available + * @param[in] timeout Integer, wait upto timeout ms or not for buffer to become available + * + * @return The tx buffer address on success and NULL on failure. + * + * @see rpmsg_lite_send_nocopy + */ +void *rpmsg_lite_alloc_tx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long *size, + unsigned long timeout); + +/*! + * @brief Sends a message in tx buffer allocated by rpmsg_lite_alloc_tx_buffer() + * + * This function sends txbuf of length len to the remote dst address, + * and uses ept->addr as the source address. + * The application has to take the responsibility for: + * 1. tx buffer allocation (rpmsg_lite_alloc_tx_buffer()) + * 2. filling the data to be sent into the pre-allocated tx buffer + * 3. not exceeding the buffer size when filling the data + * 4. data cache coherency + * + * After the rpmsg_lite_send_nocopy() function is issued the tx buffer is no more owned + * by the sending task and must not be touched anymore unless the rpmsg_lite_send_nocopy() + * function fails and returns an error. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param[in] ept Sender endpoint pointer + * @param[in] dst Destination address + * @param[in] data TX buffer with message filled + * @param[in] size Length of payload + * + * @return 0 on success and an appropriate error value on failure. + * + * @see rpmsg_lite_alloc_tx_buffer + */ +int rpmsg_lite_send_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *ept, + unsigned long dst, + void *data, + unsigned long size); +#endif /* RL_API_HAS_ZEROCOPY */ + +//! @} + +#if defined(__cplusplus) +} +#endif + +#endif /* _RPMSG_LITE_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_ns.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_ns.h new file mode 100644 index 000000000000..0eb269c99e6e --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_ns.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RPMSG_NS_H +#define _RPMSG_NS_H + +#include "rpmsg_lite.h" + +//! @addtogroup rpmsg_ns +//! @{ + +#define RL_NS_EPT_ADDR (0x35) + +/* Up to 32 flags available */ +enum rpmsg_ns_flags +{ + RL_NS_CREATE = 0, + RL_NS_DESTROY = 1, +}; + +/*! \typedef rpmsg_ns_new_ept_cb + \brief New endpoint NS callback function type. +*/ +typedef void (*rpmsg_ns_new_ept_cb)(unsigned int new_ept, + const char *new_ept_name, + unsigned long flags, + void *user_data); + +struct rpmsg_ns_callback_data +{ + rpmsg_ns_new_ept_cb cb; + void *user_data; +}; + +struct rpmsg_ns_context +{ + struct rpmsg_lite_endpoint *ept; + struct rpmsg_ns_callback_data *cb_ctxt; +}; + +typedef struct rpmsg_ns_context *rpmsg_ns_handle; + +struct rpmsg_ns_static_context_container +{ + struct rpmsg_lite_ept_static_context ept_ctxt; + struct rpmsg_ns_callback_data cb_ctxt; + struct rpmsg_ns_context ns_ctxt; +}; + +typedef struct rpmsg_ns_static_context_container rpmsg_ns_static_context; + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/* Exported API functions */ + +/*! + * @brief Registers application nameservice callback + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param app_cb Application nameservice callback + * @param user_data Application nameservice callback data + * + * @return NameService handle, to be kept for unbinding. + * + */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_ns_new_ept_cb app_cb, + void *user_data, + rpmsg_ns_static_context *ns_ept_ctxt); +#else +rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_new_ept_cb app_cb, void *user_data); +#endif /* RL_USE_STATIC_API */ + +/*! + * @brief Unregisters application nameservice callback and cleans up + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param handle NameService handle + * + * @return Status of function execution, RL_SUCCESS on success. + * + */ +int rpmsg_ns_unbind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_handle handle); + +/*! + * @brief Sends name service announcement to remote device + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param new_ept New endpoint to announce + * @param ept_name Name for the announced endpoint + * @param flags Channel creation/deletion flags + * + * @return Status of function execution, RL_SUCCESS on success + * + */ +int rpmsg_ns_announce(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *new_ept, + char *ept_name, + unsigned long flags); + +//! @} + +#if defined(__cplusplus) +} +#endif + +#endif /* _RPMSG_NS_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/rpmsg_queue.h b/ext/multicore/rpmsg_lite/lib/include/rpmsg_queue.h new file mode 100644 index 000000000000..dd614fca5524 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/rpmsg_queue.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RPMSG_QUEUE_H +#define _RPMSG_QUEUE_H + +#include "rpmsg_lite.h" + +//! @addtogroup rpmsg_queue +//! @{ + +/*! \typedef rpmsg_queue_handle + \brief Rpmsg queue handle type. +*/ +typedef void *rpmsg_queue_handle; + +/* RL_API_HAS_ZEROCOPY has to be enabled for RPMsg Queue to work */ +#if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1) + +/******************************************************************************* + * API + ******************************************************************************/ + +/* Exported API functions */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! +* @brief +* This callback needs to be registered with an endpoint +* +* @param payload Pointer to the buffer containing received data +* @param payload_len Size of data received, in bytes +* @param src Pointer to address of the endpoint from which data is received +* @param priv Private data provided during endpoint creation +* +* @return RL_HOLD or RL_RELEASE to release or hold the buffer in payload +*/ +int rpmsg_queue_rx_cb(void *payload, int payload_len, unsigned long src, void *priv); + +/*! +* @brief +* Create a RPMsg queue which can be used +* for blocking reception. +* +* @param rpmsg_lite_dev RPMsg Lite instance +* +* @return RPMsg queue handle or RL_NULL +* +*/ +rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev); + +/*! +* @brief +* Destroy a queue and clean up. +* Do not destroy a queue which is registered with an active endpoint! +* +* @param rpmsg_lite_dev RPMsg-Lite instance +* @param[in] q RPMsg queue handle to destroy +* +* @return Status of function execution +* +*/ +int rpmsg_queue_destroy(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q); + +/*! + * @brief + * blocking receive function - blocking version of the received function that can be called from an RTOS task. + * The data is copied from the receive buffer into the user supplied buffer. + * + * This is the "receive with copy" version of the RPMsg receive function. This version is simple + * to use but it requires copying data from shared memory into the user space buffer. + * The user has no obligation or burden to manage the shared memory buffers. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param[in] q RPMsg queue handle to listen on + * @param[in] data Pointer to the user buffer the received data are copied to + * @param[out] len Pointer to an int variable that will contain the number of bytes actually copied into the + * buffer + * @param[in] maxlen Maximum number of bytes to copy (received buffer size) + * @param[out] src Pointer to address of the endpoint from which data is received + * @param[in] timeout Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking + * call). + * A value of 0xffffffff means wait forever (blocking call). + * + * @return Status of function execution + * + * @see rpmsg_queue_recv_nocopy + */ +int rpmsg_queue_recv(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_queue_handle q, + unsigned long *src, + char *data, + int maxlen, + int *len, + unsigned long timeout); + +/*! + * @brief + * blocking receive function - blocking version of the received function that can be called from an RTOS task. + * The data is NOT copied into the user-app. buffer. + * + * This is the "zero-copy receive" version of the RPMsg receive function. No data is copied. + * Only the pointer to the data is returned. This version is fast, but it requires the user to manage + * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and + * make the appropriate API call to free it, see rpmsg_queue_nocopy_free(). + * + * @param rpmsg_lite_dev RPMsg Lite instance + * @param[in] q RPMsg queue handle to listen on + * @param[out] data Pointer to the RPMsg buffer of the shared memory where the received data is stored + * @param[out] len Pointer to an int variable that that will contain the number of valid bytes in the RPMsg + * buffer + * @param[out] src Pointer to address of the endpoint from which data is received + * @param[in] timeout Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking + * call). + * A value of 0xffffffff means wait forever (blocking call). + * + * @return Status of function execution. + * + * @see rpmsg_queue_nocopy_free + * @see rpmsg_queue_recv + */ +int rpmsg_queue_recv_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_queue_handle q, + unsigned long *src, + char **data, + int *len, + unsigned long timeout); + +/*! + * @brief This function frees a buffer previously returned by rpmsg_queue_recv_nocopy(). + * + * Once the zero-copy mechanism of receiving data is used, this function + * has to be called to free a buffer and to make it available for the next data + * transfer. + * + * @param rpmsg_lite_dev RPMsg-Lite instance + * @param[in] data Pointer to the RPMsg buffer of the shared memory that has to be freed + * + * @return Status of function execution. + * + * @see rpmsg_queue_recv_nocopy + */ +int rpmsg_queue_nocopy_free(struct rpmsg_lite_instance *rpmsg_lite_dev, void *data); + +//! @} + +#if defined(__cplusplus) +} +#endif + +#endif /* RL_API_HAS_ZEROCOPY */ + +#endif /* _RPMSG_QUEUE_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/virtio_ring.h b/ext/multicore/rpmsg_lite/lib/include/virtio_ring.h new file mode 100644 index 000000000000..f27405ca01f7 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/virtio_ring.h @@ -0,0 +1,161 @@ +/*- + * Copyright Rusty Russell IBM Corporation 2007. + * + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef VIRTIO_RING_H +#define VIRTIO_RING_H + +/* This marks a buffer as continuing via the next field. */ +#define VRING_DESC_F_NEXT 1 +/* This marks a buffer as write-only (otherwise read-only). */ +#define VRING_DESC_F_WRITE 2 +/* This means the buffer contains a list of buffer descriptors. */ +#define VRING_DESC_F_INDIRECT 4 + +/* The Host uses this in used->flags to advise the Guest: don't kick me + * when you add a buffer. It's unreliable, so it's simply an + * optimization. Guest will still kick if it's out of buffers. */ +#define VRING_USED_F_NO_NOTIFY 1 +/* The Guest uses this in avail->flags to advise the Host: don't + * interrupt me when you consume a buffer. It's unreliable, so it's + * simply an optimization. */ +#define VRING_AVAIL_F_NO_INTERRUPT 1 + +/* VirtIO ring descriptors: 16 bytes. + * These can chain together via "next". */ +struct vring_desc +{ + /* Address (guest-physical). */ + uint64_t addr; + /* Length. */ + uint32_t len; + /* The flags as indicated above. */ + uint16_t flags; + /* We chain unused descriptors via this, too. */ + uint16_t next; +}; + +struct vring_avail +{ + uint16_t flags; + uint16_t idx; + uint16_t ring[1]; +}; + +/* uint32_t is used here for ids for padding reasons. */ +struct vring_used_elem +{ + /* Index of start of used descriptor chain. */ + uint32_t id; + /* Total length of the descriptor chain which was written to. */ + uint32_t len; +}; + +struct vring_used +{ + uint16_t flags; + uint16_t idx; + struct vring_used_elem ring[1]; +}; + +struct vring +{ + unsigned int num; + + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +}; + +/* The standard layout for the ring is a continuous chunk of memory which + * looks like this. We assume num is a power of 2. + * + * struct vring { + * // The actual descriptors (16 bytes each) + * struct vring_desc desc[num]; + * + * // A ring of available descriptor heads with free-running index. + * __u16 avail_flags; + * __u16 avail_idx; + * __u16 available[num]; + * __u16 used_event_idx; + * + * // Padding to the next align boundary. + * char pad[]; + * + * // A ring of used descriptor heads with free-running index. + * __u16 used_flags; + * __u16 used_idx; + * struct vring_used_elem used[num]; + * __u16 avail_event_idx; + * }; + * + * NOTE: for VirtIO PCI, align is 4096. + */ + +/* + * We publish the used event index at the end of the available ring, and vice + * versa. They are at the end for backwards compatibility. + */ +#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) +#define vring_avail_event(vr) ((uint16_t *)&(vr)->used->ring[(vr)->num]) + +static inline int vring_size(unsigned int num, unsigned long align) +{ + int size; + + size = num * sizeof(struct vring_desc); + size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) + sizeof(uint16_t); + size = (size + align - 1) & ~(align - 1); + size += sizeof(struct vring_used) + (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t); + return (size); +} + +static inline void vring_init(struct vring *vr, unsigned int num, uint8_t *p, unsigned long align) +{ + vr->num = num; + vr->desc = (struct vring_desc *)p; + vr->avail = (struct vring_avail *)(p + num * sizeof(struct vring_desc)); + vr->used = (struct vring_used *)(((unsigned long)&vr->avail->ring[num] + align - 1) & ~(align - 1)); +} + +/* + * The following is used with VIRTIO_RING_F_EVENT_IDX. + * + * Assuming a given event_idx value from the other size, if we have + * just incremented index from old to new_idx, should we trigger an + * event? + */ +static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) +{ + return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); +} +#endif /* VIRTIO_RING_H */ diff --git a/ext/multicore/rpmsg_lite/lib/include/virtqueue.h b/ext/multicore/rpmsg_lite/lib/include/virtqueue.h new file mode 100644 index 000000000000..ac739164ad9c --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/include/virtqueue.h @@ -0,0 +1,247 @@ +#ifndef VIRTQUEUE_H_ +#define VIRTQUEUE_H_ + +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +typedef uint8_t boolean; + +#include "virtio_ring.h" +#include "rpmsg_env.h" +#include "llist.h" + +/*Error Codes*/ +#define VQ_ERROR_BASE (-3000) +#define ERROR_VRING_FULL (VQ_ERROR_BASE - 1) +#define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2) +#define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3) +#define ERROR_NO_MEM (VQ_ERROR_BASE - 4) +#define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5) +#define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6) +#define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7) +#define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8) + +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif +#define VQUEUE_SUCCESS (0) +#define VQUEUE_DEBUG (false) + +/* This is temporary macro to replace C NULL support. + * At the moment all the RTL specific functions are present in env. + * */ +#define VQ_NULL ((void *)0) + +/* The maximum virtqueue size is 2^15. Use that value as the end of + * descriptor chain terminator since it will never be a valid index + * in the descriptor table. This is used to verify we are correctly + * handling vq_free_cnt. + */ +#define VQ_RING_DESC_CHAIN_END (32768) +#define VIRTQUEUE_FLAG_INDIRECT (0x0001) +#define VIRTQUEUE_FLAG_EVENT_IDX (0x0002) +#define VIRTQUEUE_MAX_NAME_SZ (32) /* mind the alignment */ + +/* Support for indirect buffer descriptors. */ +#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28) + +/* Support to suppress interrupt until specific index is reached. */ +#define VIRTIO_RING_F_EVENT_IDX (1 << 29) + +/* + * Hint on how long the next interrupt should be postponed. This is + * only used when the EVENT_IDX feature is negotiated. + */ +typedef enum +{ + VQ_POSTPONE_SHORT, + VQ_POSTPONE_LONG, + VQ_POSTPONE_EMPTIED /* Until all available desc are used. */ +} vq_postpone_t; + +/* local virtqueue representation, not in shared memory */ +struct virtqueue +{ + /* 32bit aligned { */ + char vq_name[VIRTQUEUE_MAX_NAME_SZ]; + uint32_t vq_flags; + int vq_alignment; + int vq_ring_size; + void *vq_ring_mem; + void (*callback)(struct virtqueue *vq); + void (*notify)(struct virtqueue *vq); + int vq_max_indirect_size; + int vq_indirect_mem_size; + struct vring vq_ring; + /* } 32bit aligned */ + + /* 16bit aligned { */ + uint16_t vq_queue_index; + uint16_t vq_nentries; + uint16_t vq_free_cnt; + uint16_t vq_queued_cnt; + + /* + * Head of the free chain in the descriptor table. If + * there are no free descriptors, this will be set to + * VQ_RING_DESC_CHAIN_END. + */ + uint16_t vq_desc_head_idx; + + /* + * Last consumed descriptor in the used table, + * trails vq_ring.used->idx. + */ + uint16_t vq_used_cons_idx; + + /* + * Last consumed descriptor in the available table - + * used by the consumer side. + */ + uint16_t vq_available_idx; + /* } 16bit aligned */ + + boolean avail_read; /* 8bit wide */ + boolean avail_write; /* 8bit wide */ + boolean used_read; /* 8bit wide */ + boolean used_write; /* 8bit wide */ + + uint16_t padd; /* aligned to 32bits after this: */ + + void *priv; /* private pointer, upper layer instance pointer */ +}; + +/* struct to hold vring specific information */ +struct vring_alloc_info +{ + void *phy_addr; + uint32_t align; + uint16_t num_descs; + uint16_t pad; +}; + +struct vq_static_context +{ + struct virtqueue vq; +}; + +typedef void vq_callback(struct virtqueue *); +typedef void vq_notify(struct virtqueue *); + +#if (VQUEUE_DEBUG == true) +#define VQASSERT_BOOL(_vq, _exp, _msg) \ + do \ + { \ + if (!(_exp)) \ + { \ + env_print("%s: %s - " _msg, __func__, (_vq)->vq_name); \ + while (1) \ + ; \ + } \ + } while (0) +#define VQASSERT(_vq, _exp, _msg) VQASSERT_BOOL(_vq, (_exp) != 0, _msg) + +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index") + +#define VQ_PARAM_CHK(condition, status_var, status_err) \ + if ((status_var == 0) && (condition)) \ + { \ + status_var = status_err; \ + } + +#define VQUEUE_BUSY(vq, dir) \ + if ((vq)->dir == false) \ + (vq)->dir = true; \ + else \ + VQASSERT(vq, (vq)->dir == false, "VirtQueue already in use") + +#define VQUEUE_IDLE(vq, dir) ((vq)->dir = false) + +#else + +#define KASSERT(cond, str) +#define VQASSERT(_vq, _exp, _msg) +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) +#define VQ_PARAM_CHK(condition, status_var, status_err) +#define VQUEUE_BUSY(vq, dir) +#define VQUEUE_IDLE(vq, dir) + +#endif + +int virtqueue_create(unsigned short id, + char *name, + struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue **v_queue); + +int virtqueue_create_static(unsigned short id, + char *name, + struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue **v_queue, + struct vq_static_context *vq_ctxt); + +int virtqueue_add_buffer(struct virtqueue *vq, uint16_t head_idx); + +int virtqueue_fill_used_buffers(struct virtqueue *vq, void *buffer, uint32_t len); + +int virtqueue_fill_avail_buffers(struct virtqueue *vq, void *buffer, uint32_t len); + +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx); + +void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len); + +int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len); + +void virtqueue_disable_cb(struct virtqueue *vq); + +int virtqueue_enable_cb(struct virtqueue *vq); + +void virtqueue_kick(struct virtqueue *vq); + +void virtqueue_free(struct virtqueue *vq); + +void virtqueue_free_static(struct virtqueue *vq); + +void virtqueue_dump(struct virtqueue *vq); + +void virtqueue_notification(struct virtqueue *vq); + +uint32_t virtqueue_get_desc_size(struct virtqueue *vq); + +uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx); + +void vq_ring_init(struct virtqueue *vq); + +#endif /* VIRTQUEUE_H_ */ diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c new file mode 100644 index 000000000000..18fb526aba21 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * bm_env.c + * + * + * DESCRIPTION + * + * This file is Bare Metal Implementation of env layer for OpenAMP. + * + * + **************************************************************************/ + +#include "rpmsg_env.h" +#include "rpmsg_platform.h" +#include "virtqueue.h" +#include "rpmsg_compiler.h" + +#include +#include +#include + +static int env_init_counter = 0; + +/* Max supported ISR counts */ +#define ISR_COUNT (12) /* Change for multiple remote cores */ + /*! + * Structure to keep track of registered ISR's. + */ +struct isr_info +{ + void *data; +}; +static struct isr_info isr_table[ISR_COUNT]; + +/*! + * env_in_isr + * + * @returns True, if currently in ISR + * + */ +inline int env_in_isr(void) +{ + return platform_in_isr(); +} + +/*! + * env_init + * + * Initializes OS/BM environment. + * + */ +int env_init(void) +{ + // verify 'env_init_counter' + assert(env_init_counter >= 0); + if (env_init_counter < 0) + return -1; + env_init_counter++; + // multiple call of 'env_init' - return ok + if (1 < env_init_counter) + return 0; + // first call + memset(isr_table, 0, sizeof(isr_table)); + return platform_init(); +} + +/*! + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns Execution status + */ +int env_deinit(void) +{ + // verify 'env_init_counter' + assert(env_init_counter > 0); + if (env_init_counter <= 0) + return -1; + // counter on zero - call platform deinit + env_init_counter--; + // multiple call of 'env_deinit' - return ok + if (0 < env_init_counter) + return 0; + // last call + return platform_deinit(); +} + +/*! + * env_allocate_memory - implementation + * + * @param size + */ +void *env_allocate_memory(unsigned int size) +{ + return (malloc(size)); +} + +/*! + * env_free_memory - implementation + * + * @param ptr + */ +void env_free_memory(void *ptr) +{ + if (ptr != NULL) + { + free(ptr); + } +} + +/*! + * + * env_memset - implementation + * + * @param ptr + * @param value + * @param size + */ +void env_memset(void *ptr, int value, unsigned long size) +{ + memset(ptr, value, size); +} + +/*! + * + * env_memcpy - implementation + * + * @param dst + * @param src + * @param len + */ +void env_memcpy(void *dst, void const *src, unsigned long len) +{ + memcpy(dst, src, len); +} + +/*! + * + * env_strcmp - implementation + * + * @param dst + * @param src + */ + +int env_strcmp(const char *dst, const char *src) +{ + return (strcmp(dst, src)); +} + +/*! + * + * env_strncpy - implementation + * + * @param dest + * @param src + * @param len + */ +void env_strncpy(char *dest, const char *src, unsigned long len) +{ + strncpy(dest, src, len); +} + +/*! + * + * env_strncmp - implementation + * + * @param dest + * @param src + * @param len + */ +int env_strncmp(char *dest, const char *src, unsigned long len) +{ + return (strncmp(dest, src, len)); +} + +/*! + * + * env_mb - implementation + * + */ +void env_mb(void) +{ + MEM_BARRIER(); +} + +/*! + * osalr_mb - implementation + */ +void env_rmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_wmb - implementation + */ +void env_wmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_map_vatopa - implementation + * + * @param address + */ +unsigned long env_map_vatopa(void *address) +{ + return platform_vatopa(address); +} + +/*! + * env_map_patova - implementation + * + * @param address + */ +void *env_map_patova(unsigned long address) +{ + return platform_patova(address); +} + +/*! + * env_create_mutex + * + * Creates a mutex with the given initial count. + * + */ +int env_create_mutex(void **lock, int count) +{ + /* make the mutex pointer point to itself + * this marks the mutex handle as initialized. + */ + *lock = lock; + return 0; +} + +/*! + * env_delete_mutex + * + * Deletes the given lock + * + */ +void env_delete_mutex(void *lock) +{ +} + +/*! + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + */ +void env_lock_mutex(void *lock) +{ + /* No mutex needed for RPMsg-Lite in BM environment, + * since the API is not shared with ISR context. */ +} + +/*! + * env_unlock_mutex + * + * Releases the given lock. + */ +void env_unlock_mutex(void *lock) +{ + /* No mutex needed for RPMsg-Lite in BM environment, + * since the API is not shared with ISR context. */ +} + +/*! + * env_sleep_msec + * + * Suspends the calling thread for given time , in msecs. + */ +void env_sleep_msec(int num_msec) +{ + platform_time_delay(num_msec); +} + +/*! + * env_register_isr + * + * Registers interrupt handler data for the given interrupt vector. + * + * @param vector_id Virtual interrupt vector number + * @param data Interrupt handler data (virtqueue) + */ +void env_register_isr(int vector_id, void *data) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = data; + } +} + +/*! + * env_unregister_isr + * + * Unregisters interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + */ +void env_unregister_isr(int vector_id) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = NULL; + } +} + +/*! + * env_enable_interrupt + * + * Enables the given interrupt + * + * @param vector_id Interrupt vector number + */ + +void env_enable_interrupt(unsigned int vector_id) +{ + platform_interrupt_enable(vector_id); +} + +/*! + * env_disable_interrupt + * + * Disables the given interrupt + * + * @param vector_id Interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector_id) +{ + platform_interrupt_disable(vector_id); +} + +/*! + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + */ + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, unsigned int flags) +{ + platform_map_mem_region(va, pa, size, flags); +} + +/*! + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache() +{ + platform_cache_all_flush_invalidate(); + platform_cache_disable(); +} + +/*========================================================= */ +/* Util data / functions for BM */ + +void env_isr(int vector) +{ + struct isr_info *info; + assert(vector < ISR_COUNT); + if (vector < ISR_COUNT) + { + info = &isr_table[vector]; + virtqueue_notification((struct virtqueue *)info->data); + } +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c new file mode 100644 index 000000000000..07266d64068b --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * freertos_env.c + * + * + * DESCRIPTION + * + * This file is FreeRTOS Implementation of env layer for OpenAMP. + * + * + **************************************************************************/ + +#include "rpmsg_env.h" +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "rpmsg_platform.h" +#include "virtqueue.h" +#include "rpmsg_compiler.h" + +#include +#include +#include + +static int env_init_counter = 0; +SemaphoreHandle_t env_sema = NULL; + +/* Max supported ISR counts */ +#define ISR_COUNT (32) +/*! + * Structure to keep track of registered ISR's. + */ +struct isr_info +{ + void *data; +}; +static struct isr_info isr_table[ISR_COUNT]; + +/*! + * env_in_isr + * + * @returns - true, if currently in ISR + * + */ +int env_in_isr(void) +{ + return platform_in_isr(); +} + +/*! + * env_init + * + * Initializes OS/BM environment. + * + */ +int env_init(void) +{ + int retval; + vTaskSuspendAll(); /* stop scheduler */ + // verify 'env_init_counter' + assert(env_init_counter >= 0); + if (env_init_counter < 0) + { + xTaskResumeAll(); /* re-enable scheduler */ + return -1; + } + env_init_counter++; + // multiple call of 'env_init' - return ok + if (env_init_counter <= 1) + { + // first call + env_sema = xSemaphoreCreateBinary(); + memset(isr_table, 0, sizeof(isr_table)); + xTaskResumeAll(); + retval = platform_init(); + xSemaphoreGive(env_sema); + + return retval; + } + else + { + xTaskResumeAll(); + /* Get the semaphore and then return it, + * this allows for platform_init() to block + * if needed and other tasks to wait for the + * blocking to be done. + * This is in ENV layer as this is ENV specific.*/ + xSemaphoreTake(env_sema, portMAX_DELAY); + xSemaphoreGive(env_sema); + return 0; + } +} + +/*! + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns - execution status + */ +int env_deinit(void) +{ + int retval; + + vTaskSuspendAll(); /* stop scheduler */ + // verify 'env_init_counter' + assert(env_init_counter > 0); + if (env_init_counter <= 0) + { + xTaskResumeAll(); /* re-enable scheduler */ + return -1; + } + + // counter on zero - call platform deinit + env_init_counter--; + // multiple call of 'env_deinit' - return ok + if (env_init_counter <= 0) + { + // last call + memset(isr_table, 0, sizeof(isr_table)); + retval = platform_deinit(); + vSemaphoreDelete(env_sema); + env_sema = NULL; + xTaskResumeAll(); + + return retval; + } + else + { + xTaskResumeAll(); + return 0; + } +} + +/*! + * env_allocate_memory - implementation + * + * @param size + */ +void *env_allocate_memory(unsigned int size) +{ + return (pvPortMalloc(size)); +} + +/*! + * env_free_memory - implementation + * + * @param ptr + */ +void env_free_memory(void *ptr) +{ + vPortFree(ptr); +} + +/*! + * + * env_memset - implementation + * + * @param ptr + * @param value + * @param size + */ +void env_memset(void *ptr, int value, unsigned long size) +{ + memset(ptr, value, size); +} + +/*! + * + * env_memcpy - implementation + * + * @param dst + * @param src + * @param len + */ +void env_memcpy(void *dst, void const *src, unsigned long len) +{ + memcpy(dst, src, len); +} + +/*! + * + * env_strcmp - implementation + * + * @param dst + * @param src + */ + +int env_strcmp(const char *dst, const char *src) +{ + return (strcmp(dst, src)); +} + +/*! + * + * env_strncpy - implementation + * + * @param dest + * @param src + * @param len + */ +void env_strncpy(char *dest, const char *src, unsigned long len) +{ + strncpy(dest, src, len); +} + +/*! + * + * env_strncmp - implementation + * + * @param dest + * @param src + * @param len + */ +int env_strncmp(char *dest, const char *src, unsigned long len) +{ + return (strncmp(dest, src, len)); +} + +/*! + * + * env_mb - implementation + * + */ +void env_mb(void) +{ + MEM_BARRIER(); +} + +/*! + * osalr_mb - implementation + */ +void env_rmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_wmb - implementation + */ +void env_wmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_map_vatopa - implementation + * + * @param address + */ +unsigned long env_map_vatopa(void *address) +{ + return platform_vatopa(address); +} + +/*! + * env_map_patova - implementation + * + * @param address + */ +void *env_map_patova(unsigned long address) +{ + return platform_patova(address); +} + +/*! + * env_create_mutex + * + * Creates a mutex with the given initial count. + * + */ +int env_create_mutex(void **lock, int count) +{ + *lock = xSemaphoreCreateCounting(10, count); + if (*lock) + { + return 0; + } + else + { + return -1; + } +} + +/*! + * env_delete_mutex + * + * Deletes the given lock + * + */ +void env_delete_mutex(void *lock) +{ + vSemaphoreDelete(lock); +} + +/*! + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + */ +void env_lock_mutex(void *lock) +{ + SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock; + if (!env_in_isr()) + { + xSemaphoreTake(xSemaphore, portMAX_DELAY); + } +} + +/*! + * env_unlock_mutex + * + * Releases the given lock. + */ +void env_unlock_mutex(void *lock) +{ + SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock; + if (!env_in_isr()) + { + xSemaphoreGive(xSemaphore); + } +} + +/*! + * env_create_sync_lock + * + * Creates a synchronization lock primitive. It is used + * when signal has to be sent from the interrupt context to main + * thread context. + */ +int env_create_sync_lock(void **lock, int state) +{ + return env_create_mutex(lock, state); /* state=1 .. initially free */ +} + +/*! + * env_delete_sync_lock + * + * Deletes the given lock + * + */ +void env_delete_sync_lock(void *lock) +{ + if (lock) + env_delete_mutex(lock); +} + +/*! + * env_acquire_sync_lock + * + * Tries to acquire the lock, if lock is not available then call to + * this function waits for lock to become available. + */ +void env_acquire_sync_lock(void *lock) +{ + BaseType_t xTaskWokenByReceive = pdFALSE; + SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock; + if (env_in_isr()) + { + xSemaphoreTakeFromISR(xSemaphore, &xTaskWokenByReceive); + portEND_SWITCHING_ISR(xTaskWokenByReceive); + } + else + { + xSemaphoreTake(xSemaphore, portMAX_DELAY); + } +} + +/*! + * env_release_sync_lock + * + * Releases the given lock. + */ +void env_release_sync_lock(void *lock) +{ + BaseType_t xTaskWokenByReceive = pdFALSE; + SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock; + if (env_in_isr()) + { + xSemaphoreGiveFromISR(xSemaphore, &xTaskWokenByReceive); + portEND_SWITCHING_ISR(xTaskWokenByReceive); + } + else + { + xSemaphoreGive(xSemaphore); + } +} + +/*! + * env_sleep_msec + * + * Suspends the calling thread for given time , in msecs. + */ +void env_sleep_msec(int num_msec) +{ + vTaskDelay(num_msec / portTICK_PERIOD_MS); +} + +/*! + * env_register_isr + * + * Registers interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + * @param data - interrupt handler data (virtqueue) + */ +void env_register_isr(int vector_id, void *data) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = data; + } +} + +/*! + * env_unregister_isr + * + * Unregisters interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + */ +void env_unregister_isr(int vector_id) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = NULL; + } +} + +/*! + * env_enable_interrupt + * + * Enables the given interrupt + * + * @param vector_id - interrupt vector number + */ + +void env_enable_interrupt(unsigned int vector_id) +{ + platform_interrupt_enable(vector_id); +} + +/*! + * env_disable_interrupt + * + * Disables the given interrupt + * + * @param vector_id - interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector_id) +{ + platform_interrupt_disable(vector_id); +} + +/*! + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + */ + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, unsigned int flags) +{ + platform_map_mem_region(va, pa, size, flags); +} + +/*! + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache(void) +{ + platform_cache_all_flush_invalidate(); + platform_cache_disable(); +} + +/*! + * + * env_get_timestamp + * + * Returns a 64 bit time stamp. + * + * + */ +unsigned long long env_get_timestamp(void) +{ + if (env_in_isr()) + { + return (unsigned long long)xTaskGetTickCountFromISR(); + } + else + { + return (unsigned long long)xTaskGetTickCount(); + } +} + +/*========================================================= */ +/* Util data / functions */ + +void env_isr(int vector) +{ + struct isr_info *info; + assert(vector < ISR_COUNT); + if (vector < ISR_COUNT) + { + info = &isr_table[vector]; + virtqueue_notification((struct virtqueue *)info->data); + } +} + +/* + * env_create_queue + * + * Creates a message queue. + * + * @param queue - pointer to created queue + * @param length - maximum number of elements in the queue + * @param item_size - queue element size in bytes + * + * @return - status of function execution + */ +int env_create_queue(void **queue, int length, int element_size) +{ + *queue = xQueueCreate(length, element_size); + if (*queue) + { + return 0; + } + else + { + return -1; + } +} + +/*! + * env_delete_queue + * + * Deletes the message queue. + * + * @param queue - queue to delete + */ + +void env_delete_queue(void *queue) +{ + vQueueDelete(queue); +} + +/*! + * env_put_queue + * + * Put an element in a queue. + * + * @param queue - queue to put element in + * @param msg - pointer to the message to be put into the queue + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_put_queue(void *queue, void *msg, int timeout_ms) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (env_in_isr()) + { + if (xQueueSendFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS) + { + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); + return 1; + } + } + else + { + if (xQueueSend(queue, msg, ((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) == + pdPASS) + { + return 1; + } + } + return 0; +} + +/*! + * env_get_queue + * + * Get an element out of a queue. + * + * @param queue - queue to get element from + * @param msg - pointer to a memory to save the message + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_get_queue(void *queue, void *msg, int timeout_ms) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (env_in_isr()) + { + if (xQueueReceiveFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS) + { + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); + return 1; + } + } + else + { + if (xQueueReceive(queue, msg, + ((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) == pdPASS) + { + return 1; + } + } + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c new file mode 100644 index 000000000000..4f672d92112f --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************************** + * FILE NAME + * + * rpmsg_zephyr_env.c + * + * + * DESCRIPTION + * + * This file is Zephyr RTOS Implementation of env layer for OpenAMP. + * + * + **************************************************************************/ + +#include "rpmsg_env.h" +#include +#include "rpmsg_platform.h" +#include "virtqueue.h" +#include "rpmsg_compiler.h" + +#include +#include +#include + +static int env_init_counter = 0; +static struct k_sem env_sema = {0}; + +/* Max supported ISR counts */ +#define ISR_COUNT (32) +/*! + * Structure to keep track of registered ISR's. + */ +struct isr_info +{ + void *data; +}; +static struct isr_info isr_table[ISR_COUNT]; + +/*! + * env_in_isr + * + * @returns - true, if currently in ISR + * + */ +int env_in_isr(void) +{ + return platform_in_isr(); +} + +/*! + * env_init + * + * Initializes OS/BM environment. + * + */ +int env_init(void) +{ + int retval; + k_sched_lock(); /* stop scheduler */ + // verify 'env_init_counter' + assert(env_init_counter >= 0); + if (env_init_counter < 0) + { + k_sched_unlock(); /* re-enable scheduler */ + return -1; + } + env_init_counter++; + // multiple call of 'env_init' - return ok + if (env_init_counter <= 1) + { + // first call + k_sem_init(&env_sema, 0, 1); + memset(isr_table, 0, sizeof(isr_table)); + k_sched_unlock(); + retval = platform_init(); + k_sem_give(&env_sema); + + return retval; + } + else + { + k_sched_unlock(); + /* Get the semaphore and then return it, + * this allows for platform_init() to block + * if needed and other tasks to wait for the + * blocking to be done. + * This is in ENV layer as this is ENV specific.*/ + k_sem_take(&env_sema, K_FOREVER); + k_sem_give(&env_sema); + return 0; + } +} + +/*! + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns - execution status + */ +int env_deinit(void) +{ + int retval; + + k_sched_lock(); /* stop scheduler */ + // verify 'env_init_counter' + assert(env_init_counter > 0); + if (env_init_counter <= 0) + { + k_sched_unlock(); /* re-enable scheduler */ + return -1; + } + + // counter on zero - call platform deinit + env_init_counter--; + // multiple call of 'env_deinit' - return ok + if (env_init_counter <= 0) + { + // last call + memset(isr_table, 0, sizeof(isr_table)); + retval = platform_deinit(); + k_sem_reset(&env_sema); + k_sched_unlock(); + + return retval; + } + else + { + k_sched_unlock(); + return 0; + } +} + +/*! + * env_allocate_memory - implementation + * + * @param size + */ +void *env_allocate_memory(unsigned int size) +{ + return (k_malloc(size)); +} + +/*! + * env_free_memory - implementation + * + * @param ptr + */ +void env_free_memory(void *ptr) +{ + k_free(ptr); +} + +/*! + * + * env_memset - implementation + * + * @param ptr + * @param value + * @param size + */ +void env_memset(void *ptr, int value, unsigned long size) +{ + memset(ptr, value, size); +} + +/*! + * + * env_memcpy - implementation + * + * @param dst + * @param src + * @param len + */ +void env_memcpy(void *dst, void const *src, unsigned long len) +{ + memcpy(dst, src, len); +} + +/*! + * + * env_strcmp - implementation + * + * @param dst + * @param src + */ + +int env_strcmp(const char *dst, const char *src) +{ + return (strcmp(dst, src)); +} + +/*! + * + * env_strncpy - implementation + * + * @param dest + * @param src + * @param len + */ +void env_strncpy(char *dest, const char *src, unsigned long len) +{ + strncpy(dest, src, len); +} + +/*! + * + * env_strncmp - implementation + * + * @param dest + * @param src + * @param len + */ +int env_strncmp(char *dest, const char *src, unsigned long len) +{ + return (strncmp(dest, src, len)); +} + +/*! + * + * env_mb - implementation + * + */ +void env_mb(void) +{ + MEM_BARRIER(); +} + +/*! + * osalr_mb - implementation + */ +void env_rmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_wmb - implementation + */ +void env_wmb(void) +{ + MEM_BARRIER(); +} + +/*! + * env_map_vatopa - implementation + * + * @param address + */ +unsigned long env_map_vatopa(void *address) +{ + return platform_vatopa(address); +} + +/*! + * env_map_patova - implementation + * + * @param address + */ +void *env_map_patova(unsigned long address) +{ + return platform_patova(address); +} + +/*! + * env_create_mutex + * + * Creates a mutex with the given initial count. + * + */ +int env_create_mutex(void **lock, int count) +{ + struct k_sem *semaphore_ptr; + + semaphore_ptr = (struct k_sem *)env_allocate_memory(sizeof(struct k_sem)); + if(semaphore_ptr == NULL) + { + return -1; + } + k_sem_init(semaphore_ptr, count, 10); + *lock = (void*)semaphore_ptr; + return 0; +} + +/*! + * env_delete_mutex + * + * Deletes the given lock + * + */ +void env_delete_mutex(void *lock) +{ + k_sem_reset(lock); + env_free_memory(lock); +} + +/*! + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + */ +void env_lock_mutex(void *lock) +{ + if (!env_in_isr()) + { + k_sem_take((struct k_sem *)lock, K_FOREVER); + } +} + +/*! + * env_unlock_mutex + * + * Releases the given lock. + */ +void env_unlock_mutex(void *lock) +{ + if (!env_in_isr()) + { + k_sem_give((struct k_sem *)lock); + } +} + +/*! + * env_create_sync_lock + * + * Creates a synchronization lock primitive. It is used + * when signal has to be sent from the interrupt context to main + * thread context. + */ +int env_create_sync_lock(void **lock, int state) +{ + return env_create_mutex(lock, state); /* state=1 .. initially free */ +} + +/*! + * env_delete_sync_lock + * + * Deletes the given lock + * + */ +void env_delete_sync_lock(void *lock) +{ + if (lock) + env_delete_mutex(lock); +} + +/*! + * env_acquire_sync_lock + * + * Tries to acquire the lock, if lock is not available then call to + * this function waits for lock to become available. + */ +void env_acquire_sync_lock(void *lock) +{ + if (lock) + env_lock_mutex(lock); +} + +/*! + * env_release_sync_lock + * + * Releases the given lock. + */ +void env_release_sync_lock(void *lock) +{ + if (lock) + env_unlock_mutex(lock); +} + +/*! + * env_sleep_msec + * + * Suspends the calling thread for given time , in msecs. + */ +void env_sleep_msec(int num_msec) +{ + k_sleep(num_msec); +} + +/*! + * env_register_isr + * + * Registers interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + * @param data - interrupt handler data (virtqueue) + */ +void env_register_isr(int vector_id, void *data) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = data; + } +} + +/*! + * env_unregister_isr + * + * Unregisters interrupt handler data for the given interrupt vector. + * + * @param vector_id - virtual interrupt vector number + */ +void env_unregister_isr(int vector_id) +{ + assert(vector_id < ISR_COUNT); + if (vector_id < ISR_COUNT) + { + isr_table[vector_id].data = NULL; + } +} + +/*! + * env_enable_interrupt + * + * Enables the given interrupt + * + * @param vector_id - interrupt vector number + */ + +void env_enable_interrupt(unsigned int vector_id) +{ + platform_interrupt_enable(vector_id); +} + +/*! + * env_disable_interrupt + * + * Disables the given interrupt + * + * @param vector_id - interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector_id) +{ + platform_interrupt_disable(vector_id); +} + +/*! + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + */ + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, unsigned int flags) +{ + platform_map_mem_region(va, pa, size, flags); +} + +/*! + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache(void) +{ + platform_cache_all_flush_invalidate(); + platform_cache_disable(); +} + +/*========================================================= */ +/* Util data / functions */ + +void env_isr(int vector) +{ + struct isr_info *info; + assert(vector < ISR_COUNT); + if (vector < ISR_COUNT) + { + info = &isr_table[vector]; + virtqueue_notification((struct virtqueue *)info->data); + } +} + +/* + * env_create_queue + * + * Creates a message queue. + * + * @param queue - pointer to created queue + * @param length - maximum number of elements in the queue + * @param item_size - queue element size in bytes + * + * @return - status of function execution + */ +int env_create_queue(void **queue, int length, int element_size) +{ + struct k_msgq *queue_ptr = NULL; + char *msgq_buffer_ptr = NULL; + + queue_ptr = (struct k_msgq *)env_allocate_memory(sizeof(struct k_msgq)); + msgq_buffer_ptr = (char *)env_allocate_memory(length * element_size); + if((queue_ptr == NULL) || (msgq_buffer_ptr == NULL)) + { + return -1; + } + k_msgq_init(queue_ptr, msgq_buffer_ptr, element_size, length); + + *queue = (void*)queue_ptr; + return 0; +} + +/*! + * env_delete_queue + * + * Deletes the message queue. + * + * @param queue - queue to delete + */ + +void env_delete_queue(void *queue) +{ + k_msgq_purge((struct k_msgq*)queue); + env_free_memory(((struct k_msgq*)queue)->buffer_start); + env_free_memory(queue); +} + +/*! + * env_put_queue + * + * Put an element in a queue. + * + * @param queue - queue to put element in + * @param msg - pointer to the message to be put into the queue + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_put_queue(void *queue, void *msg, int timeout_ms) +{ +// if (!env_in_isr()) +// { + if (0 == k_msgq_put((struct k_msgq*)queue, msg, timeout_ms)) + { + return 1; + } +// } + return 0; +} + +/*! + * env_get_queue + * + * Get an element out of a queue. + * + * @param queue - queue to get element from + * @param msg - pointer to a memory to save the message + * @param timeout_ms - timeout in ms + * + * @return - status of function execution + */ + +int env_get_queue(void *queue, void *msg, int timeout_ms) +{ +// if (!env_in_isr()) +// { + if (0 == k_msgq_get((struct k_msgq*)queue, msg, timeout_ms)) + { + return 1; + } +// } + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx6sx_m4/rpmsg_platform.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx6sx_m4/rpmsg_platform.c new file mode 100644 index 000000000000..ec884be12f87 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx6sx_m4/rpmsg_platform.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +#include "board.h" +#include "mu_imx.h" + +#define APP_MU_IRQ_PRIORITY (3) + +static int isr_counter = 0; +static int disable_counter = 0; +static void *lock; + +int platform_init_interrupt(int vq_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vq_id, isr_data); + + /* Prepare the MU Hardware, enable channel 1 interrupt */ + env_lock_mutex(lock); + + assert(0 <= isr_counter); + if (!isr_counter) + MU_EnableRxFullInt(MUB, RPMSG_MU_CHANNEL); + isr_counter++; + + env_unlock_mutex(lock); + + return 0; +} + +int platform_deinit_interrupt(int vq_id) +{ + /* Prepare the MU Hardware, enable channel 1 interrupt */ + env_lock_mutex(lock); + + assert(0 < isr_counter); + isr_counter--; + if (!isr_counter) + MU_DisableRxFullInt(MUB, RPMSG_MU_CHANNEL); + + /* Unregister ISR from environment layer */ + env_unregister_isr(vq_id); + + env_unlock_mutex(lock); + + return 0; +} + +void platform_notify(int vq_id) +{ + /* As Linux suggests, use MU->Data Channle 1 as communication channel */ + uint32_t msg = (RL_GET_Q_ID(vq_id)) << 16; + + env_lock_mutex(lock); + MU_SendMsg(MUB, RPMSG_MU_CHANNEL, msg); + env_unlock_mutex(lock); +} + +/* + * MU Interrrupt RPMsg handler + */ +void rpmsg_handler(void) +{ + uint32_t msg, channel; + + if (MU_TryReceiveMsg(MUB, RPMSG_MU_CHANNEL, &msg) == kStatus_MU_Success) + { + channel = msg >> 16; + env_isr(channel); + } + + return; +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(int num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has 3 cycles */ + loop = SystemCoreClock / 3 / 1000 * num_msec; + + /* There's some difference among toolchains, 3 or 4 cycles each loop */ + while (loop) + { + __NOP(); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int platform_in_isr(void) +{ + return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt with passed priority and type. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * @param trigger_type IRQ active level + * @param trigger_type IRQ priority + * + * @return vq_id. Return value is never checked.. + * + */ +int platform_interrupt_enable(unsigned int vq_id) +{ + assert(0 < disable_counter); + + __asm volatile("cpsid i"); + disable_counter--; + + if (!disable_counter) + NVIC_EnableIRQ(MU_M4_IRQn); + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * + * @return vq_id. Return value is never checked. + * + */ +int platform_interrupt_disable(unsigned int vq_id) +{ + assert(0 <= disable_counter); + + __asm volatile("cpsid i"); + // virtqueues use the same NVIC vector + // if counter is set - the interrupts are disabled + if (!disable_counter) + NVIC_DisableIRQ(MU_M4_IRQn); + + disable_counter++; + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr, unsigned int size, unsigned int flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate() +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable() +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +unsigned long platform_vatopa(void *addr) +{ + return ((unsigned long)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(unsigned long addr) +{ + return ((void *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int platform_init(void) +{ + /* + * Prepare for the MU Interrupt + * MU must be initialized before rpmsg init is called + */ + MU_Init(BOARD_MU_BASE_ADDR); + NVIC_SetPriority(BOARD_MU_IRQ_NUM, APP_MU_IRQ_PRIORITY); + NVIC_EnableIRQ(BOARD_MU_IRQ_NUM); + + /* Create lock used in multi-instanced RPMsg */ + env_create_mutex(&lock, 1); + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(lock); + lock = NULL; + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx7d_m4/rpmsg_platform.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx7d_m4/rpmsg_platform.c new file mode 100644 index 000000000000..ec884be12f87 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/imx7d_m4/rpmsg_platform.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +#include "board.h" +#include "mu_imx.h" + +#define APP_MU_IRQ_PRIORITY (3) + +static int isr_counter = 0; +static int disable_counter = 0; +static void *lock; + +int platform_init_interrupt(int vq_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vq_id, isr_data); + + /* Prepare the MU Hardware, enable channel 1 interrupt */ + env_lock_mutex(lock); + + assert(0 <= isr_counter); + if (!isr_counter) + MU_EnableRxFullInt(MUB, RPMSG_MU_CHANNEL); + isr_counter++; + + env_unlock_mutex(lock); + + return 0; +} + +int platform_deinit_interrupt(int vq_id) +{ + /* Prepare the MU Hardware, enable channel 1 interrupt */ + env_lock_mutex(lock); + + assert(0 < isr_counter); + isr_counter--; + if (!isr_counter) + MU_DisableRxFullInt(MUB, RPMSG_MU_CHANNEL); + + /* Unregister ISR from environment layer */ + env_unregister_isr(vq_id); + + env_unlock_mutex(lock); + + return 0; +} + +void platform_notify(int vq_id) +{ + /* As Linux suggests, use MU->Data Channle 1 as communication channel */ + uint32_t msg = (RL_GET_Q_ID(vq_id)) << 16; + + env_lock_mutex(lock); + MU_SendMsg(MUB, RPMSG_MU_CHANNEL, msg); + env_unlock_mutex(lock); +} + +/* + * MU Interrrupt RPMsg handler + */ +void rpmsg_handler(void) +{ + uint32_t msg, channel; + + if (MU_TryReceiveMsg(MUB, RPMSG_MU_CHANNEL, &msg) == kStatus_MU_Success) + { + channel = msg >> 16; + env_isr(channel); + } + + return; +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(int num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has 3 cycles */ + loop = SystemCoreClock / 3 / 1000 * num_msec; + + /* There's some difference among toolchains, 3 or 4 cycles each loop */ + while (loop) + { + __NOP(); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int platform_in_isr(void) +{ + return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt with passed priority and type. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * @param trigger_type IRQ active level + * @param trigger_type IRQ priority + * + * @return vq_id. Return value is never checked.. + * + */ +int platform_interrupt_enable(unsigned int vq_id) +{ + assert(0 < disable_counter); + + __asm volatile("cpsid i"); + disable_counter--; + + if (!disable_counter) + NVIC_EnableIRQ(MU_M4_IRQn); + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * + * @return vq_id. Return value is never checked. + * + */ +int platform_interrupt_disable(unsigned int vq_id) +{ + assert(0 <= disable_counter); + + __asm volatile("cpsid i"); + // virtqueues use the same NVIC vector + // if counter is set - the interrupts are disabled + if (!disable_counter) + NVIC_DisableIRQ(MU_M4_IRQn); + + disable_counter++; + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr, unsigned int size, unsigned int flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate() +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable() +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +unsigned long platform_vatopa(void *addr) +{ + return ((unsigned long)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(unsigned long addr) +{ + return ((void *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int platform_init(void) +{ + /* + * Prepare for the MU Interrupt + * MU must be initialized before rpmsg init is called + */ + MU_Init(BOARD_MU_BASE_ADDR); + NVIC_SetPriority(BOARD_MU_IRQ_NUM, APP_MU_IRQ_PRIORITY); + NVIC_EnableIRQ(BOARD_MU_IRQ_NUM); + + /* Create lock used in multi-instanced RPMsg */ + env_create_mutex(&lock, 1); + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(lock); + lock = NULL; + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5410x/rpmsg_platform.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5410x/rpmsg_platform.c new file mode 100644 index 000000000000..393c847d33ec --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5410x/rpmsg_platform.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +#include "fsl_device_registers.h" +#include "fsl_mailbox.h" + +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) +#include "mcmgr.h" +#endif + +static int isr_counter = 0; +static int disable_counter = 0; +static void *lock; + +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) +static void mcmgr_event_handler(uint16_t vring_idx, void *context) +{ + env_isr(vring_idx); +} +#else +void MAILBOX_IRQHandler(void) +{ + mailbox_cpu_id_t cpu_id; +#if defined(__CM4_CMSIS_VERSION) + cpu_id = kMAILBOX_CM4; +#else + cpu_id = kMAILBOX_CM0Plus; +#endif + + uint32_t value = MAILBOX_GetValue(MAILBOX, cpu_id); + + if (value & 0x01) + { + env_isr(0); + MAILBOX_ClearValueBits(MAILBOX, cpu_id, 0x01); + } + if (value & 0x02) + { + env_isr(1); + MAILBOX_ClearValueBits(MAILBOX, cpu_id, 0x02); + } +} + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +#endif + +int platform_init_interrupt(int vq_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vq_id, isr_data); + + env_lock_mutex(lock); + + assert(0 <= isr_counter); + if (!isr_counter) + +#if defined(__CM4_CMSIS_VERSION) + NVIC_SetPriority(MAILBOX_IRQn, 5); +#else + NVIC_SetPriority(MAILBOX_IRQn, 2); +#endif + isr_counter++; + + env_unlock_mutex(lock); + + return 0; +} + +int platform_deinit_interrupt(int vq_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(lock); + + assert(0 < isr_counter); + isr_counter--; + if (!isr_counter) + NVIC_DisableIRQ(MAILBOX_IRQn); + + /* Unregister ISR from environment layer */ + env_unregister_isr(vq_id); + + env_unlock_mutex(lock); + + return 0; +} + +void platform_notify(int vq_id) +{ +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) + env_lock_mutex(lock); + MCMGR_TriggerEvent(kMCMGR_RemoteRPMsgEvent, RL_GET_Q_ID(vq_id)); + env_unlock_mutex(lock); +#else + switch (RL_GET_LINK_ID(vq_id)) + { + case 0: + env_lock_mutex(lock); +#if defined(__CM4_CMSIS_VERSION) + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM0Plus, (1 << RL_GET_Q_ID(vq_id))); +#else + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM4, (1 << RL_GET_Q_ID(vq_id))); +#endif + env_unlock_mutex(lock); + return; + + default: + return; + } +#endif +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(int num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has 3 cycles */ + loop = SystemCoreClock / 3 / 1000 * num_msec; + + /* There's some difference among toolchains, 3 or 4 cycles each loop */ + while (loop) + { + __NOP(); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int platform_in_isr(void) +{ + return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt with passed priority and type. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * @param trigger_type IRQ active level + * @param trigger_type IRQ priority + * + * @return vq_id. Return value is never checked.. + * + */ +int platform_interrupt_enable(unsigned int vq_id) +{ + assert(0 < disable_counter); + + __asm volatile("cpsid i"); + disable_counter--; + + if (!disable_counter) + NVIC_EnableIRQ(MAILBOX_IRQn); + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * + * @return vq_id. Return value is never checked. + * + */ +int platform_interrupt_disable(unsigned int vq_id) +{ + assert(0 <= disable_counter); + + __asm volatile("cpsid i"); + // virtqueues use the same NVIC vector + // if counter is set - the interrupts are disabled + if (!disable_counter) + NVIC_DisableIRQ(MAILBOX_IRQn); + + disable_counter++; + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr, unsigned int size, unsigned int flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate() +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable() +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +unsigned long platform_vatopa(void *addr) +{ + return ((unsigned long)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(unsigned long addr) +{ + return ((void *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int platform_init(void) +{ +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) + MCMGR_RegisterEvent(kMCMGR_RemoteRPMsgEvent, mcmgr_event_handler, NULL); +#else + MAILBOX_Init(MAILBOX); +#endif + + /* Create lock used in multi-instanced RPMsg */ + env_create_mutex(&lock, 1); + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int platform_deinit(void) +{ +/* Important for LPC54102 - do not deinit mailbox, if there + is a pending ISR on the other core! */ +#if defined(__CM4_CMSIS_VERSION) + while (0 != MAILBOX_GetValue(MAILBOX, kMAILBOX_CM0Plus)) + ; +#else + while (0 != MAILBOX_GetValue(MAILBOX, kMAILBOX_CM4)) + ; +#endif + + MAILBOX_Deinit(MAILBOX); + + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(lock); + lock = NULL; + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform.c new file mode 100644 index 000000000000..b5bd26aa4696 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +#include "fsl_device_registers.h" +#include "fsl_mailbox.h" + +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) +#include "mcmgr.h" +#endif + +static int isr_counter = 0; +static int disable_counter = 0; +static void *lock; + +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) +static void mcmgr_event_handler(uint16_t vring_idx, void *context) +{ + env_isr(vring_idx); +} +#else +void MAILBOX_IRQHandler(void) +{ + mailbox_cpu_id_t cpu_id; +#if defined(__CM4_CMSIS_VERSION) + cpu_id = kMAILBOX_CM4; +#else + cpu_id = kMAILBOX_CM0Plus; +#endif + + uint32_t value = MAILBOX_GetValue(MAILBOX, cpu_id); + + if (value & 0x01) + { + env_isr(0); + MAILBOX_ClearValueBits(MAILBOX, cpu_id, 0x01); + } + if (value & 0x02) + { + env_isr(1); + MAILBOX_ClearValueBits(MAILBOX, cpu_id, 0x02); + } +} + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +#endif + +int platform_init_interrupt(int vq_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vq_id, isr_data); + + env_lock_mutex(lock); + + assert(0 <= isr_counter); + if (!isr_counter) + +#if defined(__CM4_CMSIS_VERSION) + NVIC_SetPriority(MAILBOX_IRQn, 5); +#else + NVIC_SetPriority(MAILBOX_IRQn, 2); +#endif + isr_counter++; + + env_unlock_mutex(lock); + + return 0; +} + +int platform_deinit_interrupt(int vq_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(lock); + + assert(0 < isr_counter); + isr_counter--; + if (!isr_counter) + NVIC_DisableIRQ(MAILBOX_IRQn); + + /* Unregister ISR from environment layer */ + env_unregister_isr(vq_id); + + env_unlock_mutex(lock); + + return 0; +} + +void platform_notify(int vq_id) +{ +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) + env_lock_mutex(lock); + MCMGR_TriggerEvent(kMCMGR_RemoteRPMsgEvent, RL_GET_Q_ID(vq_id)); + env_unlock_mutex(lock); +#else + switch (RL_GET_LINK_ID(vq_id)) + { + case 0: + env_lock_mutex(lock); +#if defined(__CM4_CMSIS_VERSION) + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM0Plus, (1 << RL_GET_Q_ID(vq_id))); +#else + MAILBOX_SetValueBits(MAILBOX, kMAILBOX_CM4, (1 << RL_GET_Q_ID(vq_id))); +#endif + env_unlock_mutex(lock); + return; + + default: + return; + } +#endif +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(int num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has 3 cycles */ + loop = SystemCoreClock / 3 / 1000 * num_msec; + + /* There's some difference among toolchains, 3 or 4 cycles each loop */ + while (loop) + { + __NOP(); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int platform_in_isr(void) +{ + return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt with passed priority and type. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * @param trigger_type IRQ active level + * @param trigger_type IRQ priority + * + * @return vq_id. Return value is never checked.. + * + */ +int platform_interrupt_enable(unsigned int vq_id) +{ + assert(0 < disable_counter); + + __asm volatile("cpsid i"); + disable_counter--; + + if (!disable_counter) + NVIC_EnableIRQ(MAILBOX_IRQn); + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * + * @return vq_id. Return value is never checked. + * + */ +int platform_interrupt_disable(unsigned int vq_id) +{ + assert(0 <= disable_counter); + + __asm volatile("cpsid i"); + // virtqueues use the same NVIC vector + // if counter is set - the interrupts are disabled + if (!disable_counter) + NVIC_DisableIRQ(MAILBOX_IRQn); + + disable_counter++; + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr, unsigned int size, unsigned int flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate() +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable() +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +unsigned long platform_vatopa(void *addr) +{ + return ((unsigned long)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(unsigned long addr) +{ + return ((void *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int platform_init(void) +{ +#if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1) + MCMGR_RegisterEvent(kMCMGR_RemoteRPMsgEvent, mcmgr_event_handler, NULL); +#else + MAILBOX_Init(MAILBOX); +#endif + + /* Create lock used in multi-instanced RPMsg */ + env_create_mutex(&lock, 1); + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int platform_deinit(void) +{ +/* Important for LPC5411x - do not deinit mailbox, if there + is a pending ISR on the other core! */ +#if defined(__CM4_CMSIS_VERSION) + while (0 != MAILBOX_GetValue(MAILBOX, kMAILBOX_CM0Plus)) + ; +#else + while (0 != MAILBOX_GetValue(MAILBOX, kMAILBOX_CM4)) + ; +#endif + + MAILBOX_Deinit(MAILBOX); + + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(lock); + lock = NULL; + return 0; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c new file mode 100644 index 000000000000..85cc501b88a5 --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c @@ -0,0 +1,265 @@ +/* + * The Clear BSD License + * Copyright (c) 2017 NXP + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" +#include + +static int isr_counter = 0; +static int disable_counter = 0; +static void *lock; +static struct device *ipm_handle = NULL; + +void platform_ipm_callback(void *context, u32_t id, volatile void *data) +{ + if ((*(uint32_t*)data) & 0x01) + { + env_isr(0); + } + if ((*(uint32_t*)data) & 0x02) + { + env_isr(1); + } +} + +int platform_init_interrupt(int vq_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vq_id, isr_data); + + env_lock_mutex(lock); + + assert(0 <= isr_counter); + + isr_counter++; + + env_unlock_mutex(lock); + + return 0; +} + +int platform_deinit_interrupt(int vq_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(lock); + + assert(0 < isr_counter); + isr_counter--; + if ((!isr_counter) && (ipm_handle != NULL)) + { + ipm_set_enabled(ipm_handle, 0); + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vq_id); + + env_unlock_mutex(lock); + + return 0; +} + +void platform_notify(int vq_id) +{ + switch (RL_GET_LINK_ID(vq_id)) + { + case 0: + env_lock_mutex(lock); + uint32_t data = (1 << RL_GET_Q_ID(vq_id)); + assert(ipm_handle); + ipm_send(ipm_handle, 0, 0, &data, sizeof(uint32_t)); + env_unlock_mutex(lock); + return; + + default: + return; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int platform_in_isr(void) +{ + return (0 != k_is_in_isr()); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt with passed priority and type. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * @param trigger_type IRQ active level + * @param trigger_type IRQ priority + * + * @return vq_id. Return value is never checked.. + * + */ +int platform_interrupt_enable(unsigned int vq_id) +{ + assert(0 < disable_counter); + + __asm volatile("cpsid i"); + disable_counter--; + + if ((!disable_counter) && (ipm_handle != NULL)) + { + ipm_set_enabled(ipm_handle, 1); + } + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vq_id Vector ID that need to be converted to IRQ number + * + * @return vq_id. Return value is never checked. + * + */ +int platform_interrupt_disable(unsigned int vq_id) +{ + assert(0 <= disable_counter); + + __asm volatile("cpsid i"); + // virtqueues use the same NVIC vector + // if counter is set - the interrupts are disabled + if ((!disable_counter) && (ipm_handle != NULL)) + { + ipm_set_enabled(ipm_handle, 0); + } + + disable_counter++; + __asm volatile("cpsie i"); + return (vq_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr, unsigned int size, unsigned int flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate() +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable() +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +unsigned long platform_vatopa(void *addr) +{ + return ((unsigned long)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(unsigned long addr) +{ + return ((void *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int platform_init(void) +{ + /* Get IPM device handle */ + ipm_handle = device_get_binding("MAILBOX_0"); + if(!ipm_handle) + { + return -1; + } + + /* Register application callback with no context */ + ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); + + /* Create lock used in multi-instanced RPMsg */ + env_create_mutex(&lock, 1); + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(lock); + lock = NULL; + return 0; +} + diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c new file mode 100644 index 000000000000..709d7338bb0f --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rpmsg_lite.h" +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +RL_PACKED_BEGIN +/*! + * Common header for all rpmsg messages. + * Every message sent/received on the rpmsg bus begins with this header. + */ +struct rpmsg_std_hdr +{ + unsigned long src; /*!< source endpoint address */ + unsigned long dst; /*!< destination endpoint address */ + unsigned long reserved; /*!< reserved for future use */ + unsigned short len; /*!< length of payload (in bytes) */ + unsigned short flags; /*!< message flags */ +} RL_PACKED_END; + +RL_PACKED_BEGIN +/*! + * Common message structure. + * Contains the header and the payload. + */ +struct rpmsg_std_msg +{ + struct rpmsg_std_hdr hdr; /*!< RPMsg message header */ + unsigned char data[1]; /*!< bytes of message payload data */ +} RL_PACKED_END; + +/* rpmsg_std_hdr contains a reserved field, + * this implementation of RPMSG uses this reserved + * field to hold the idx and totlen of the buffer + * not being returned to the vring in the receive + * callback function. This way, the no-copy API + * can use this field to return the buffer later. + */ +struct rpmsg_hdr_reserved +{ + unsigned short rfu; /* reserved for future usage */ + unsigned short idx; +}; + +/* Interface which is used to interact with the virtqueue layer, + * a different interface is used, when the local processor is the MASTER + * and when it is the REMOTE. + */ +struct virtqueue_ops +{ + void (*vq_tx)(struct virtqueue *vq, void *buffer, unsigned long len, unsigned short idx); + void *(*vq_tx_alloc)(struct virtqueue *vq, unsigned long *len, unsigned short *idx); + void *(*vq_rx)(struct virtqueue *vq, unsigned long *len, unsigned short *idx); + void (*vq_rx_free)(struct virtqueue *vq, void *buffer, unsigned long len, unsigned short idx); +}; + +/* Zero-Copy extension macros */ +#define RPMSG_STD_MSG_FROM_BUF(buf) (struct rpmsg_std_msg *)((char *)buf - offsetof(struct rpmsg_std_msg, data)) + +#if (!RL_BUFFER_COUNT) || (RL_BUFFER_COUNT & (RL_BUFFER_COUNT - 1)) +#error "RL_BUFFER_COUNT must be power of two (2, 4, ...)" +#endif + +/* Buffer is formed by payload and struct rpmsg_std_hdr */ +#define RL_BUFFER_SIZE (RL_BUFFER_PAYLOAD_SIZE + 16) + +#if (!RL_BUFFER_SIZE) || (RL_BUFFER_SIZE & (RL_BUFFER_SIZE - 1)) +#error "RL_BUFFER_SIZE must be power of two (256, 512, ...)"\ + "RL_BUFFER_PAYLOAD_SIZE must be equal to (240, 496, 1008, ...) [2^n - 16]." +#endif + + +/*! + * @brief + * Create a new rpmsg endpoint, which can be used + * for communication. + * + * @param rpmsg_lite_dev RPMsg Lite instance + * @param addr Local endpoint address + * + * @return RL_NULL if not found, node pointer containing the ept on success + * + */ +struct llist *rpmsg_lite_get_endpoint_from_addr(struct rpmsg_lite_instance *rpmsg_lite_dev, unsigned long addr) +{ + struct llist *rl_ept_lut_head; + + rl_ept_lut_head = rpmsg_lite_dev->rl_endpoints; + while (rl_ept_lut_head) + { + struct rpmsg_lite_endpoint *rl_ept = (struct rpmsg_lite_endpoint *)rl_ept_lut_head->data; + if (rl_ept->addr == addr) + { + return rl_ept_lut_head; + } + rl_ept_lut_head = rl_ept_lut_head->next; + } + return RL_NULL; +} + +/*************************************************************** + mmm mm m m mmmmm mm mmm m m mmmm + m" " ## # # # # ## m" " # m" #" " + # # # # # #mmmm" # # # #m# "#mmm + # #mm# # # # # #mm# # # #m "# + "mmm" # # #mmmmm #mmmmm #mmmm" # # "mmm" # "m "mmm#" +****************************************************************/ + +/*! + * @brief + * Called when remote side calls virtqueue_kick() + * at its transmit virtqueue. + * In this callback, the buffer is read-out + * of the rvq and user callback is called. + * + * @param vq Virtqueue affected by the kick + * + */ +static void rpmsg_lite_rx_callback(struct virtqueue *vq) +{ + struct rpmsg_std_msg *rpmsg_msg; + unsigned long len; + unsigned short idx; + struct rpmsg_lite_endpoint *ept; + int cb_ret; + struct llist *node; + struct rpmsg_hdr_reserved *rsvd; + struct rpmsg_lite_instance *rpmsg_lite_dev = (struct rpmsg_lite_instance *)vq->priv; + + RL_ASSERT(rpmsg_lite_dev != NULL); + + /* Process the received data from remote node */ + rpmsg_msg = (struct rpmsg_std_msg *)rpmsg_lite_dev->vq_ops->vq_rx(rpmsg_lite_dev->rvq, &len, &idx); + + while (rpmsg_msg) + { + node = rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, rpmsg_msg->hdr.dst); + + cb_ret = RL_RELEASE; + if (node != RL_NULL) + { + ept = (struct rpmsg_lite_endpoint *)node->data; + cb_ret = ept->rx_cb(rpmsg_msg->data, rpmsg_msg->hdr.len, rpmsg_msg->hdr.src, ept->rx_cb_data); + } + + if (cb_ret == RL_HOLD) + { + rsvd = (struct rpmsg_hdr_reserved *)&rpmsg_msg->hdr.reserved; + rsvd->idx = idx; + } + else + { + rpmsg_lite_dev->vq_ops->vq_rx_free(rpmsg_lite_dev->rvq, rpmsg_msg, len, idx); + } + rpmsg_msg = (struct rpmsg_std_msg *)rpmsg_lite_dev->vq_ops->vq_rx(rpmsg_lite_dev->rvq, &len, &idx); + } +} + +/*! + * @brief + * Called when remote side calls virtqueue_kick() + * at its receive virtqueue. + * + * @param vq Virtqueue affected by the kick + * + */ +static void rpmsg_lite_tx_callback(struct virtqueue *vq) +{ + struct rpmsg_lite_instance *rpmsg_lite_dev = (struct rpmsg_lite_instance *)vq->priv; + + RL_ASSERT(rpmsg_lite_dev != NULL); + rpmsg_lite_dev->link_state = 1; +} + +/**************************************************************************** + + m m mmmm m m mm mm m mmmm m mmmmm mm m mmm + "m m" m" "m # # ## #"m # # "m # # #"m # m" " + # # # # #mmmm# # # # #m # # # # # # #m # # mm + "mm" # # # # #mm# # # # # # # # # # # # # + ## #mm#" # # # # # ## #mmm" #mmmmm mm#mm # ## "mmm" + # + In case this processor has the REMOTE role +*****************************************************************************/ +/*! + * @brief + * Places buffer on the virtqueue for consumption by the other side. + * + * @param vq Virtqueue to use + * @param buffer Buffer pointer + * @param len Buffer length + * @idx Buffer index + * + * @return Status of function execution + * + */ +static void vq_tx_remote(struct virtqueue *tvq, void *buffer, unsigned long len, unsigned short idx) +{ + int status; + status = virtqueue_add_consumed_buffer(tvq, idx, len); + RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */ + + /* As long as the length of the virtqueue ring buffer is not shorter + * than the number of buffers in the pool, this function should not fail. + * This condition is always met, so we don't need to return anything here */ +} + +/*! + * @brief + * Provides buffer to transmit messages. + * + * @param vq Virtqueue to use + * @param len Length of returned buffer + * @param idx Buffer index + * + * return Pointer to buffer. + */ +static void *vq_tx_alloc_remote(struct virtqueue *tvq, unsigned long *len, unsigned short *idx) +{ + return virtqueue_get_available_buffer(tvq, idx, (uint32_t *)len); +} + +/*! + * @brief + * Retrieves the received buffer from the virtqueue. + * + * @param vq Virtqueue to use + * @param len Size of received buffer + * @param idx Index of buffer + * + * @return Pointer to received buffer + * + */ +static void *vq_rx_remote(struct virtqueue *rvq, unsigned long *len, unsigned short *idx) +{ + return virtqueue_get_available_buffer(rvq, idx, (uint32_t *)len); +} + +/*! + * @brief + * Places the used buffer back on the virtqueue. + * + * @param vq Virtqueue to use + * @param len Size of received buffer + * @param idx Index of buffer + * + */ +static void vq_rx_free_remote(struct virtqueue *rvq, void *buffer, unsigned long len, unsigned short idx) +{ + int status; +#if defined(RL_CLEAR_USED_BUFFERS) && (RL_CLEAR_USED_BUFFERS == 1) + env_memset(buffer, 0x00, len); +#endif + status = virtqueue_add_consumed_buffer(rvq, idx, len); + RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */ + /* As long as the length of the virtqueue ring buffer is not shorter + * than the number of buffers in the pool, this function should not fail. + * This condition is always met, so we don't need to return anything here */ +} + +/**************************************************************************** + + m m mmmm m m mm mm m mmmm m mmmmm mm m mmm + "m m" m" "m # # ## #"m # # "m # # #"m # m" " + # # # # #mmmm# # # # #m # # # # # # #m # # mm + "mm" # # # # #mm# # # # # # # # # # # # # + ## #mm#" # # # # # ## #mmm" #mmmmm mm#mm # ## "mmm" + # + In case this processor has the MASTER role +*****************************************************************************/ + +/*! + * @brief + * Places buffer on the virtqueue for consumption by the other side. + * + * @param vq Virtqueue to use + * @param buffer Buffer pointer + * @param len Buffer length + * @idx Buffer index + * + * @return Status of function execution + * + */ +static void vq_tx_master(struct virtqueue *tvq, void *buffer, unsigned long len, unsigned short idx) +{ + int status; + status = virtqueue_add_buffer(tvq, idx); + RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */ + + /* As long as the length of the virtqueue ring buffer is not shorter + * than the number of buffers in the pool, this function should not fail. + * This condition is always met, so we don't need to return anything here */ +} + +/*! + * @brief + * Provides buffer to transmit messages. + * + * @param vq Virtqueue to use + * @param len Length of returned buffer + * @param idx Buffer index + * + * return Pointer to buffer. + */ +static void *vq_tx_alloc_master(struct virtqueue *tvq, unsigned long *len, unsigned short *idx) +{ + return virtqueue_get_buffer(tvq, (uint32_t *)len, idx); +} + +/*! + * @brief + * Retrieves the received buffer from the virtqueue. + * + * @param vq Virtqueue to use + * @param len Size of received buffer + * @param idx Index of buffer + * + * @return Pointer to received buffer + * + */ +static void *vq_rx_master(struct virtqueue *rvq, unsigned long *len, unsigned short *idx) +{ + return virtqueue_get_buffer(rvq, (uint32_t *)len, idx); +} + +/*! + * @brief + * Places the used buffer back on the virtqueue. + * + * @param vq Virtqueue to use + * @param len Size of received buffer + * @param idx Index of buffer + * + */ +static void vq_rx_free_master(struct virtqueue *rvq, void *buffer, unsigned long len, unsigned short idx) +{ + int status; +#if defined(RL_CLEAR_USED_BUFFERS) && (RL_CLEAR_USED_BUFFERS == 1) + env_memset(buffer, 0x00, len); +#endif + status = virtqueue_add_buffer(rvq, idx); + RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */ + + /* As long as the length of the virtqueue ring buffer is not shorter + * than the number of buffers in the pool, this function should not fail. + * This condition is always met, so we don't need to return anything here */ +} + +/* Interface used in case this processor is MASTER */ +static const struct virtqueue_ops master_vq_ops = { + vq_tx_master, vq_tx_alloc_master, vq_rx_master, vq_rx_free_master, +}; + +/* Interface used in case this processor is REMOTE */ +static const struct virtqueue_ops remote_vq_ops = { + vq_tx_remote, vq_tx_alloc_remote, vq_rx_remote, vq_rx_free_remote, +}; + +/* helper function for virtqueue notification */ +void virtqueue_notify(struct virtqueue *vq) +{ + platform_notify(vq->vq_queue_index); +} + +/************************************************* + + mmmmmm mmmmm mmmmmmm mm m mmmmmmm m + # # "# # #"m # # # # # + #mmmmm #mmm#" # # #m # #mmmmm" #"# # + # # # # # # # ## ##" + #mmmmm # # # ## #mmmmm # # + +**************************************************/ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long addr, + rl_ept_rx_cb_t rx_cb, + void *rx_cb_data, + struct rpmsg_lite_ept_static_context *ept_context) +#else +struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long addr, + rl_ept_rx_cb_t rx_cb, + void *rx_cb_data) +#endif +{ + struct rpmsg_lite_endpoint *rl_ept; + struct llist *node; + unsigned int i; + + if (!rpmsg_lite_dev) + return RL_NULL; + + env_lock_mutex(rpmsg_lite_dev->lock); + { + if (addr == RL_ADDR_ANY) + { + /* find lowest free address */ + for (i = 1; i < 0xFFFFFFFF; i++) + { + if (rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, i) == RL_NULL) + { + addr = i; + break; + } + } + if (addr == RL_ADDR_ANY) + { + /* no address is free, cannot happen normally */ + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_NULL; + } + } + else + { + if (rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, addr) != RL_NULL) + { + /* Already exists! */ + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_NULL; + } + } + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (!ept_context) + { + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_NULL; + } + + rl_ept = &(ept_context->ept); + node = &(ept_context->node); +#else + rl_ept = env_allocate_memory(sizeof(struct rpmsg_lite_endpoint)); + if (!rl_ept) + { + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_NULL; + } + node = env_allocate_memory(sizeof(struct llist)); + if (!node) + { + env_free_memory(rl_ept); + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_NULL; + } +#endif /* RL_USE_STATIC_API */ + + env_memset(rl_ept, 0x00, sizeof(struct rpmsg_lite_endpoint)); + + rl_ept->addr = addr; + rl_ept->rx_cb = rx_cb; + rl_ept->rx_cb_data = rx_cb_data; + + node->data = rl_ept; + + add_to_list((struct llist **)&rpmsg_lite_dev->rl_endpoints, node); + } + env_unlock_mutex(rpmsg_lite_dev->lock); + + return rl_ept; +} +/************************************************* + + mmmmmm mmmmm mmmmmmm mmmm mmmmmm m + # # "# # # "m # # + #mmmmm #mmm#" # # # #mmmmm # + # # # # # # # + #mmmmm # # #mmm" #mmmmm #mmmmm + +**************************************************/ + +int rpmsg_lite_destroy_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, struct rpmsg_lite_endpoint *rl_ept) +{ + struct llist *node; + + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + + if (!rl_ept) + return RL_ERR_PARAM; + + env_lock_mutex(rpmsg_lite_dev->lock); + node = rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, rl_ept->addr); + if (node) + { + remove_from_list((struct llist **)&rpmsg_lite_dev->rl_endpoints, node); + env_unlock_mutex(rpmsg_lite_dev->lock); +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(node); + env_free_memory(rl_ept); +#endif + return RL_SUCCESS; + } + else + { + env_unlock_mutex(rpmsg_lite_dev->lock); + return RL_ERR_PARAM; + } +} + +/****************************************** + +mmmmmmm m m mm mmmmm mmmmm + # # # ## # "# # + # ## # # #mmm#" # + # m""m #mm# # # + # m" "m # # # mm#mm + +*******************************************/ + +int rpmsg_lite_is_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev) +{ + if (!rpmsg_lite_dev) + return 0; + + return rpmsg_lite_dev->link_state; +} + +/*! + * @brief + * Internal function to format a RPMsg compatible + * message and sends it + * + * @param rpmsg_lite_dev RPMsg Lite instance + * @param src Local endpoint address + * @param dst Remote endpoint address + * @param data Payload buffer + * @param size Size of payload, in bytes + * @param flags Value of flags field + * @param timeout Timeout in ms, 0 if nonblocking + * + * @return Status of function execution, RL_SUCCESS on success + * + */ +int rpmsg_lite_format_message(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long src, + unsigned long dst, + char *data, + unsigned long size, + int flags, + unsigned long timeout) +{ + struct rpmsg_std_msg *rpmsg_msg; + void *buffer; + unsigned short idx; + unsigned long tick_count = 0; + unsigned long buff_len; + + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + + if (!data) + return RL_ERR_PARAM; + + if (!rpmsg_lite_dev->link_state) + return RL_NOT_READY; + + /* Lock the device to enable exclusive access to virtqueues */ + env_lock_mutex(rpmsg_lite_dev->lock); + /* Get rpmsg buffer for sending message. */ + buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx); + env_unlock_mutex(rpmsg_lite_dev->lock); + + if (!buffer && !timeout) + return RL_ERR_NO_MEM; + + while (!buffer) + { + env_sleep_msec(RL_MS_PER_INTERVAL); + env_lock_mutex(rpmsg_lite_dev->lock); + buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx); + env_unlock_mutex(rpmsg_lite_dev->lock); + tick_count += RL_MS_PER_INTERVAL; + if ((tick_count >= timeout) && (!buffer)) + { + return RL_ERR_NO_MEM; + } + } + + rpmsg_msg = (struct rpmsg_std_msg *)buffer; + + /* Initialize RPMSG header. */ + rpmsg_msg->hdr.dst = dst; + rpmsg_msg->hdr.src = src; + rpmsg_msg->hdr.len = size; + rpmsg_msg->hdr.flags = flags; + + /* Copy data to rpmsg buffer. */ + env_memcpy(rpmsg_msg->data, data, size); + + env_lock_mutex(rpmsg_lite_dev->lock); + /* Enqueue buffer on virtqueue. */ + rpmsg_lite_dev->vq_ops->vq_tx(rpmsg_lite_dev->tvq, buffer, buff_len, idx); + /* Let the other side know that there is a job to process. */ + virtqueue_kick(rpmsg_lite_dev->tvq); + env_unlock_mutex(rpmsg_lite_dev->lock); + + return RL_SUCCESS; +} + +int rpmsg_lite_send(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *ept, + unsigned long dst, + char *data, + unsigned long size, + unsigned long timeout) +{ + if (!ept) + return RL_ERR_PARAM; + + // FIXME : may be just copy the data size equal to buffer length and Tx it. + if (size > RL_BUFFER_PAYLOAD_SIZE) + return RL_ERR_BUFF_SIZE; + + return rpmsg_lite_format_message(rpmsg_lite_dev, ept->addr, dst, data, size, 0, timeout); +} + +#if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1) + +void *rpmsg_lite_alloc_tx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, unsigned long *size, unsigned long timeout) +{ + struct rpmsg_std_msg *rpmsg_msg; + struct rpmsg_hdr_reserved *reserved = RL_NULL; + void *buffer; + unsigned short idx; + unsigned int tick_count = 0; + + if (!size) + return NULL; + + if (!rpmsg_lite_dev->link_state) + { + *size = 0; + return NULL; + } + + /* Lock the device to enable exclusive access to virtqueues */ + env_lock_mutex(rpmsg_lite_dev->lock); + /* Get rpmsg buffer for sending message. */ + buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, size, &idx); + env_unlock_mutex(rpmsg_lite_dev->lock); + + if (!buffer && !timeout) + { + *size = 0; + return NULL; + } + + while (!buffer) + { + env_sleep_msec(RL_MS_PER_INTERVAL); + env_lock_mutex(rpmsg_lite_dev->lock); + buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, size, &idx); + env_unlock_mutex(rpmsg_lite_dev->lock); + tick_count += RL_MS_PER_INTERVAL; + if ((tick_count >= timeout) && (!buffer)) + { + *size = 0; + return NULL; + } + } + + rpmsg_msg = (struct rpmsg_std_msg *)buffer; + + /* keep idx and totlen information for nocopy tx function */ + reserved = (struct rpmsg_hdr_reserved *)&rpmsg_msg->hdr.reserved; + reserved->idx = idx; + + /* return the maximum payload size */ + *size -= sizeof(struct rpmsg_std_hdr); + + return rpmsg_msg->data; +} + +int rpmsg_lite_send_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *ept, + unsigned long dst, + void *data, + unsigned long size) +{ + struct rpmsg_std_msg *rpmsg_msg; + unsigned long src; + struct rpmsg_hdr_reserved *reserved = RL_NULL; + + if (!ept || !data) + return RL_ERR_PARAM; + + if (size > RL_BUFFER_PAYLOAD_SIZE) + return RL_ERR_BUFF_SIZE; + + if (!rpmsg_lite_dev->link_state) + return RL_NOT_READY; + + src = ept->addr; + + rpmsg_msg = RPMSG_STD_MSG_FROM_BUF(data); + + /* Initialize RPMSG header. */ + rpmsg_msg->hdr.dst = dst; + rpmsg_msg->hdr.src = src; + rpmsg_msg->hdr.len = size; + rpmsg_msg->hdr.flags = 0; + + reserved = (struct rpmsg_hdr_reserved *)&rpmsg_msg->hdr.reserved; + + env_lock_mutex(rpmsg_lite_dev->lock); + /* Enqueue buffer on virtqueue. */ + rpmsg_lite_dev->vq_ops->vq_tx(rpmsg_lite_dev->tvq, (void *)rpmsg_msg, + (unsigned long)virtqueue_get_buffer_length(rpmsg_lite_dev->tvq, reserved->idx), + reserved->idx); + /* Let the other side know that there is a job to process. */ + virtqueue_kick(rpmsg_lite_dev->tvq); + env_unlock_mutex(rpmsg_lite_dev->lock); + + return RL_SUCCESS; +} + +/****************************************** + + mmmmm m m mm mmmmm mmmmm + # "# # # ## # "# # + #mmmm" ## # # #mmm#" # + # "m m""m #mm# # # + # " m" "m # # # mm#mm + + *******************************************/ + +int rpmsg_lite_release_rx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, void *rxbuf) +{ + struct rpmsg_std_msg *rpmsg_msg; + struct rpmsg_hdr_reserved *reserved = RL_NULL; + + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + if (!rxbuf) + return RL_ERR_PARAM; + + rpmsg_msg = RPMSG_STD_MSG_FROM_BUF(rxbuf); + + /* Get the pointer to the reserved field that contains buffer size and the index */ + reserved = (struct rpmsg_hdr_reserved *)&rpmsg_msg->hdr.reserved; + + env_lock_mutex(rpmsg_lite_dev->lock); + + /* Return used buffer, with total length (header length + buffer size). */ + rpmsg_lite_dev->vq_ops->vq_rx_free(rpmsg_lite_dev->rvq, rpmsg_msg, + (unsigned long)virtqueue_get_buffer_length(rpmsg_lite_dev->rvq, reserved->idx), + reserved->idx); + + env_unlock_mutex(rpmsg_lite_dev->lock); + + return RL_SUCCESS; +} + +#endif /* RL_API_HAS_ZEROCOPY */ + +/****************************** + + mmmmm mm m mmmmm mmmmmmm + # #"m # # # + # # #m # # # + # # # # # # + mm#mm # ## mm#mm # + + *****************************/ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_instance *rpmsg_lite_master_init( + void *shmem_addr, size_t shmem_length, int link_id, uint32_t init_flags, struct rpmsg_lite_instance *static_context) +#else +struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr, + size_t shmem_length, + int link_id, + uint32_t init_flags) +#endif +{ + int status; + void (*callback[2])(struct virtqueue *vq); + const char *vq_names[2]; + struct vring_alloc_info ring_info; + struct virtqueue *vqs[2]; + void *buffer; + int idx, j; + struct rpmsg_lite_instance *rpmsg_lite_dev = NULL; + + if ((2 * RL_BUFFER_COUNT) > ((RL_WORD_ALIGN_DOWN(shmem_length - RL_VRING_OVERHEAD)) / RL_BUFFER_SIZE)) + return NULL; + + if (link_id > RL_PLATFORM_HIGHEST_LINK_ID) + return NULL; + + if (!shmem_addr) + return NULL; + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (!static_context) + return NULL; + rpmsg_lite_dev = static_context; +#else + rpmsg_lite_dev = env_allocate_memory(sizeof(struct rpmsg_lite_instance)); + if (!rpmsg_lite_dev) + return NULL; +#endif + + env_memset(rpmsg_lite_dev, 0, sizeof(struct rpmsg_lite_instance)); + + status = env_init(); + if (status != RL_SUCCESS) + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + /* + * Since device is RPMSG Remote so we need to manage the + * shared buffers. Create shared memory pool to handle buffers. + */ + rpmsg_lite_dev->sh_mem_base = (char *)RL_WORD_ALIGN_UP(shmem_addr + RL_VRING_OVERHEAD); + rpmsg_lite_dev->sh_mem_remaining = (RL_WORD_ALIGN_DOWN(shmem_length - RL_VRING_OVERHEAD)) / RL_BUFFER_SIZE; + rpmsg_lite_dev->sh_mem_total = rpmsg_lite_dev->sh_mem_remaining; + + /* Initialize names and callbacks*/ + vq_names[0] = "rx_vq"; + vq_names[1] = "tx_vq"; + callback[0] = rpmsg_lite_rx_callback; + callback[1] = rpmsg_lite_tx_callback; + rpmsg_lite_dev->vq_ops = &master_vq_ops; + + /* Create virtqueue for each vring. */ + for (idx = 0; idx < 2; idx++) + { + ring_info.phy_addr = (void *)((unsigned long)shmem_addr + (unsigned long)((idx == 0) ? (0) : (VRING_SIZE))); + ring_info.align = VRING_ALIGN; + ring_info.num_descs = RL_BUFFER_COUNT; + + env_memset((void *)ring_info.phy_addr, 0x00, vring_size(ring_info.num_descs, ring_info.align)); + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + status = virtqueue_create_static(RL_GET_VQ_ID(link_id, idx), (char *)vq_names[idx], &ring_info, callback[idx], + virtqueue_notify, &vqs[idx], + (struct vq_static_context *)&rpmsg_lite_dev->vq_ctxt[idx]); +#else + status = virtqueue_create(RL_GET_VQ_ID(link_id, idx), (char *)vq_names[idx], &ring_info, callback[idx], + virtqueue_notify, &vqs[idx]); +#endif /* RL_USE_STATIC_API */ + + if (status == RL_SUCCESS) + { + /* Initialize vring control block in virtqueue. */ + vq_ring_init(vqs[idx]); + + /* Disable callbacks - will be enabled by the application + * once initialization is completed. + */ + virtqueue_disable_cb(vqs[idx]); + } + else + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + /* virtqueue has reference to the RPMsg Lite instance */ + vqs[idx]->priv = (void *)rpmsg_lite_dev; + } + + status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1); + if (status != RL_SUCCESS) + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + // FIXME - a better way to handle this , tx for master is rx for remote and vice versa. + rpmsg_lite_dev->tvq = vqs[1]; + rpmsg_lite_dev->rvq = vqs[0]; + + for (j = 0; j < 2; j++) + { + for (idx = 0; ((idx < vqs[j]->vq_nentries) && (idx < rpmsg_lite_dev->sh_mem_total)); idx++) + { + /* Initialize TX virtqueue buffers for remote device */ + buffer = rpmsg_lite_dev->sh_mem_remaining ? + (rpmsg_lite_dev->sh_mem_base + + RL_BUFFER_SIZE * (rpmsg_lite_dev->sh_mem_total - rpmsg_lite_dev->sh_mem_remaining--)) : + (RL_NULL); + + RL_ASSERT(buffer); + + env_memset(buffer, 0x00, RL_BUFFER_SIZE); + if (vqs[j] == rpmsg_lite_dev->rvq) + status = virtqueue_fill_avail_buffers(vqs[j], buffer, RL_BUFFER_SIZE); + else if (vqs[j] == rpmsg_lite_dev->tvq) + status = virtqueue_fill_used_buffers(vqs[j], buffer, RL_BUFFER_SIZE); + else + RL_ASSERT(0); /* should not happen */ + + if (status != RL_SUCCESS) + { +/* Clean up! */ +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + env_delete_mutex(rpmsg_lite_dev->lock); + return NULL; + } + } + } + + /* Install ISRs */ + platform_init_interrupt(rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq); + platform_init_interrupt(rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq); + env_disable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_disable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + rpmsg_lite_dev->link_state = 1; + env_enable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_enable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + + /* + * Let the remote device know that Master is ready for + * communication. + */ + virtqueue_kick(rpmsg_lite_dev->rvq); + + return rpmsg_lite_dev; +} + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, + int link_id, + uint32_t init_flags, + struct rpmsg_lite_instance *static_context) +#else +struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, int link_id, uint32_t init_flags) +#endif +{ + int status; + void (*callback[2])(struct virtqueue *vq); + const char *vq_names[2]; + struct vring_alloc_info ring_info; + struct virtqueue *vqs[2]; + int idx; + struct rpmsg_lite_instance *rpmsg_lite_dev = NULL; + + if (link_id > RL_PLATFORM_HIGHEST_LINK_ID) + return NULL; + + if (!shmem_addr) + return NULL; + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (!static_context) + return NULL; + rpmsg_lite_dev = static_context; +#else + rpmsg_lite_dev = env_allocate_memory(sizeof(struct rpmsg_lite_instance)); + if (!rpmsg_lite_dev) + return NULL; +#endif + + env_memset(rpmsg_lite_dev, 0, sizeof(struct rpmsg_lite_instance)); + + status = env_init(); + if (status != RL_SUCCESS) + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + vq_names[0] = "tx_vq"; /* swapped in case of remote */ + vq_names[1] = "rx_vq"; + callback[0] = rpmsg_lite_tx_callback; + callback[1] = rpmsg_lite_rx_callback; + rpmsg_lite_dev->vq_ops = &remote_vq_ops; + + /* Create virtqueue for each vring. */ + for (idx = 0; idx < 2; idx++) + { + ring_info.phy_addr = (void *)((unsigned long)shmem_addr + (unsigned long)((idx == 0) ? (0) : (VRING_SIZE))); + ring_info.align = VRING_ALIGN; + ring_info.num_descs = RL_BUFFER_COUNT; + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + status = virtqueue_create_static(RL_GET_VQ_ID(link_id, idx), (char *)vq_names[idx], &ring_info, callback[idx], + virtqueue_notify, &vqs[idx], + (struct vq_static_context *)&rpmsg_lite_dev->vq_ctxt[idx]); +#else + status = virtqueue_create(RL_GET_VQ_ID(link_id, idx), (char *)vq_names[idx], &ring_info, callback[idx], + virtqueue_notify, &vqs[idx]); +#endif /* RL_USE_STATIC_API */ + + if (status != RL_SUCCESS) + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + /* virtqueue has reference to the RPMsg Lite instance */ + vqs[idx]->priv = (void *)rpmsg_lite_dev; + } + + status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1); + if (status != RL_SUCCESS) + { +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif + return NULL; + } + + // FIXME - a better way to handle this , tx for master is rx for remote and vice versa. + rpmsg_lite_dev->tvq = vqs[0]; + rpmsg_lite_dev->rvq = vqs[1]; + + /* Install ISRs */ + platform_init_interrupt(rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq); + platform_init_interrupt(rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq); + env_disable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_disable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + rpmsg_lite_dev->link_state = 0; + env_enable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_enable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + + return rpmsg_lite_dev; +} + +/******************************************* + + mmmm mmmmmm mmmmm mm m mmmmm mmmmmmm + # "m # # #"m # # # + # # #mmmmm # # #m # # # + # # # # # # # # # + #mmm" #mmmmm mm#mm # ## mm#mm # + +********************************************/ + +int rpmsg_lite_deinit(struct rpmsg_lite_instance *rpmsg_lite_dev) +{ + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + + if (!(rpmsg_lite_dev->rvq && rpmsg_lite_dev->tvq && rpmsg_lite_dev->lock)) + { + /* ERROR - trying to initialize uninitialized RPMSG? */ + RL_ASSERT((rpmsg_lite_dev->rvq && rpmsg_lite_dev->tvq && rpmsg_lite_dev->lock)); + return RL_ERR_PARAM; + } + + env_disable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_disable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + rpmsg_lite_dev->link_state = 0; + env_enable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + env_enable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + + platform_deinit_interrupt(rpmsg_lite_dev->rvq->vq_queue_index); + platform_deinit_interrupt(rpmsg_lite_dev->tvq->vq_queue_index); + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + virtqueue_free_static(rpmsg_lite_dev->rvq); + virtqueue_free_static(rpmsg_lite_dev->tvq); +#else + virtqueue_free(rpmsg_lite_dev->rvq); + virtqueue_free(rpmsg_lite_dev->tvq); +#endif /* RL_USE_STATIC_API */ + + env_delete_mutex(rpmsg_lite_dev->lock); + +#if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)) + env_free_memory(rpmsg_lite_dev); +#endif /* RL_USE_STATIC_API */ + + env_deinit(); + + return RL_SUCCESS; +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c new file mode 100644 index 000000000000..f67cd2451d2f --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "rpmsg_ns.h" + +/* from rpmsg_lite.c { */ +extern volatile struct rpmsg_lite_instance rpmsg_lite_dev; +int rpmsg_lite_format_message(struct rpmsg_lite_instance *rpmsg_lite_dev, + unsigned long src, + unsigned long dst, + char *data, + unsigned long size, + int flags, + unsigned long timeout); +/* } from rpmsg_lite.c*/ + +#define RL_NS_NAME_SIZE (32) + +/*! + * struct rpmsg_ns_msg - dynamic name service announcement message + * @name: name of remote service that is published + * @addr: address of remote service that is published + * @flags: indicates whether service is created or destroyed + * + * This message is sent across to publish a new service, or announce + * about its removal. When we receive these messages, an appropriate + * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe() + * or ->remove() handler of the appropriate rpmsg driver will be invoked + * (if/as-soon-as one is registered). + */ +RL_PACKED_BEGIN +struct rpmsg_ns_msg +{ + char name[RL_NS_NAME_SIZE]; + unsigned long addr; + unsigned long flags; +} RL_PACKED_END; + +/*! + * @brief + * Nameservice callback, called in interrupt context + * + * @param payload Pointer to the buffer containing received data + * @param payload_len Size of data received, in bytes + * @param src Pointer to address of the endpoint from which data is received + * @param priv Private data provided during endpoint creation + * + * @return RL_RELEASE, message is always freed + * + */ +int rpmsg_ns_rx_cb(void *payload, int payload_len, unsigned long src, void *priv) +{ + struct rpmsg_ns_msg *ns_msg_ptr = payload; + struct rpmsg_ns_callback_data *cb_ctxt = priv; + RL_ASSERT(priv); + RL_ASSERT(cb_ctxt->cb); + + /* Drop likely bad messages received at nameservice address */ + if (payload_len == sizeof(struct rpmsg_ns_msg)) + cb_ctxt->cb(ns_msg_ptr->addr, ns_msg_ptr->name, ns_msg_ptr->flags, cb_ctxt->user_data); + + return RL_RELEASE; +} + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_ns_new_ept_cb app_cb, + void *user_data, + rpmsg_ns_static_context *ns_ept_ctxt) +#else +rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_new_ept_cb app_cb, void *user_data) +#endif /* RL_USE_STATIC_API */ +{ + struct rpmsg_ns_context *ns_ctxt; + + if (app_cb == NULL) + return NULL; + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (ns_ept_ctxt == NULL) + return NULL; + + ns_ctxt = &ns_ept_ctxt->ns_ctxt; + + /* Set-up the nameservice callback context */ + ns_ept_ctxt->cb_ctxt.user_data = user_data; + ns_ept_ctxt->cb_ctxt.cb = app_cb; + + ns_ctxt->cb_ctxt = &ns_ept_ctxt->cb_ctxt; + + ns_ctxt->ept = rpmsg_lite_create_ept(rpmsg_lite_dev, RL_NS_EPT_ADDR, rpmsg_ns_rx_cb, (void *)ns_ctxt->cb_ctxt, + &ns_ept_ctxt->ept_ctxt); +#else + { + struct rpmsg_ns_callback_data *cb_ctxt; + + cb_ctxt = env_allocate_memory(sizeof(struct rpmsg_ns_callback_data)); + if (cb_ctxt == NULL) + return NULL; + ns_ctxt = env_allocate_memory(sizeof(struct rpmsg_ns_context)); + if (ns_ctxt == NULL) + { + env_free_memory(cb_ctxt); + return NULL; + } + + /* Set-up the nameservice callback context */ + cb_ctxt->user_data = user_data; + cb_ctxt->cb = app_cb; + + ns_ctxt->cb_ctxt = cb_ctxt; + + ns_ctxt->ept = rpmsg_lite_create_ept(rpmsg_lite_dev, RL_NS_EPT_ADDR, rpmsg_ns_rx_cb, (void *)ns_ctxt->cb_ctxt); + } +#endif /* RL_USE_STATIC_API */ + + return (rpmsg_ns_handle)ns_ctxt; +} + +int rpmsg_ns_unbind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_handle handle) +{ + struct rpmsg_ns_context *ns_ctxt = (struct rpmsg_ns_context *)handle; + +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + return rpmsg_lite_destroy_ept(rpmsg_lite_dev, ns_ctxt->ept); +#else + { + int retval; + + retval = rpmsg_lite_destroy_ept(rpmsg_lite_dev, ns_ctxt->ept); + env_free_memory(ns_ctxt->cb_ctxt); + env_free_memory(ns_ctxt); + return retval; + } +#endif +} + +int rpmsg_ns_announce(struct rpmsg_lite_instance *rpmsg_lite_dev, + struct rpmsg_lite_endpoint *new_ept, + char *ept_name, + unsigned long flags) +{ + struct rpmsg_ns_msg ns_msg; + + if (!ept_name) + return RL_ERR_PARAM; + + if (!new_ept) + return RL_ERR_PARAM; + + env_strncpy(ns_msg.name, ept_name, RL_NS_NAME_SIZE); + ns_msg.flags = flags; + ns_msg.addr = new_ept->addr; + + return rpmsg_lite_format_message(rpmsg_lite_dev, new_ept->addr, RL_NS_EPT_ADDR, (char *)&ns_msg, + sizeof(struct rpmsg_ns_msg), 0, RL_BLOCK); +} diff --git a/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c new file mode 100644 index 000000000000..432e7ea395af --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "rpmsg_lite.h" +#include "rpmsg_queue.h" + +typedef struct +{ + unsigned long src; + void *data; + short int len; +} rpmsg_queue_rx_cb_data_t; + +extern volatile struct rpmsg_lite_instance rpmsg_lite_dev; + +int rpmsg_queue_rx_cb(void *payload, int payload_len, unsigned long src, void *priv) +{ + rpmsg_queue_rx_cb_data_t msg; + + RL_ASSERT(priv); + + msg.data = payload; + msg.len = payload_len; + msg.src = src; + + /* if message is successfully added into queue then hold rpmsg buffer */ + if (env_put_queue(priv, &msg, 0)) + { + /* hold the rx buffer */ + return RL_HOLD; + } + + return RL_RELEASE; +} + +rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev) +{ + int status = -1; + void *q = NULL; + + if (rpmsg_lite_dev == RL_NULL) + return RL_NULL; + + /* create message queue for channel default endpoint */ + status = env_create_queue(&q, rpmsg_lite_dev->rvq->vq_nentries, sizeof(rpmsg_queue_rx_cb_data_t)); + if ((status) || (q == NULL)) + { + return RL_NULL; + } + + return ((rpmsg_queue_handle)q); +} + +int rpmsg_queue_destroy(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q) +{ + if (rpmsg_lite_dev == RL_NULL) + return RL_ERR_PARAM; + + if (q == RL_NULL) + return RL_ERR_PARAM; + env_delete_queue((void *)q); + return RL_SUCCESS; +} + +int rpmsg_queue_recv(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_queue_handle q, + unsigned long *src, + char *data, + int maxlen, + int *len, + unsigned long timeout) +{ + rpmsg_queue_rx_cb_data_t msg; + int retval = RL_SUCCESS; + + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + if (!q) + return RL_ERR_PARAM; + if (!data) + return RL_ERR_PARAM; + + /* Get an element out of the message queue for the selected endpoint */ + if (env_get_queue((void *)q, &msg, timeout)) + { + if (src != NULL) + *src = msg.src; + if (len != NULL) + *len = msg.len; + + if (maxlen >= msg.len) + { + env_memcpy(data, msg.data, msg.len); + } + else + { + retval = RL_ERR_BUFF_SIZE; + } + + /* Return used buffers. */ + rpmsg_lite_release_rx_buffer(rpmsg_lite_dev, msg.data); + + return retval; + } + else + { + return RL_ERR_NO_BUFF; /* failed */ + } +} + +int rpmsg_queue_recv_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev, + rpmsg_queue_handle q, + unsigned long *src, + char **data, + int *len, + unsigned long timeout) +{ + rpmsg_queue_rx_cb_data_t msg; + + if (!rpmsg_lite_dev) + return RL_ERR_PARAM; + if (!data) + return RL_ERR_PARAM; + if (!q) + return RL_ERR_PARAM; + + /* Get an element out of the message queue for the selected endpoint */ + if (env_get_queue((void *)q, &msg, timeout)) + { + if (src != NULL) + *src = msg.src; + if (len != NULL) + *len = msg.len; + + *data = msg.data; + + return RL_SUCCESS; /* success */ + } + + return RL_ERR_NO_BUFF; /* failed */ +} + +int rpmsg_queue_nocopy_free(struct rpmsg_lite_instance *rpmsg_lite_dev, void *data) +{ + if (!data) + return RL_ERR_PARAM; + + /* Return used buffer. */ + rpmsg_lite_release_rx_buffer(rpmsg_lite_dev, data); + + return RL_SUCCESS; +} diff --git a/ext/multicore/rpmsg_lite/lib/virtio/virtqueue.c b/ext/multicore/rpmsg_lite/lib/virtio/virtqueue.c new file mode 100644 index 000000000000..7a69b450963a --- /dev/null +++ b/ext/multicore/rpmsg_lite/lib/virtio/virtqueue.c @@ -0,0 +1,702 @@ +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "virtqueue.h" + +/* Prototype for internal functions. */ +static void vq_ring_update_avail(struct virtqueue *, uint16_t); +static void vq_ring_update_used(struct virtqueue *vq, uint16_t head_idx, uint32_t len); +static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *, uint16_t, void *, uint32_t); +static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); +static int vq_ring_must_notify_host(struct virtqueue *vq); +static void vq_ring_notify_host(struct virtqueue *vq); +static int virtqueue_nused(struct virtqueue *vq); + +/*! + * virtqueue_create - Creates new VirtIO queue + * + * @param id - VirtIO queue ID , must be unique + * @param name - Name of VirtIO queue + * @param ring - Pointer to vring_alloc_info control block + * @param callback - Pointer to callback function, invoked + * when message is available on VirtIO queue + * @param notify - Pointer to notify function, used to notify + * other side that there is job available for it + * @param v_queue - Created VirtIO queue. + * + * @return - Function status + */ +int virtqueue_create(unsigned short id, + char *name, + struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue **v_queue) +{ + struct virtqueue *vq = VQ_NULL; + int status = VQUEUE_SUCCESS; + uint32_t vq_size = 0; + + VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status, ERROR_VRING_ALIGN); + + if (status == VQUEUE_SUCCESS) + { + vq_size = sizeof(struct virtqueue); + vq = (struct virtqueue *)env_allocate_memory(vq_size); + + if (vq == VQ_NULL) + { + return (ERROR_NO_MEM); + } + + env_memset(vq, 0x00, vq_size); + + env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ); + vq->vq_queue_index = id; + vq->vq_alignment = ring->align; + vq->vq_nentries = ring->num_descs; + vq->callback = callback; + vq->notify = notify; + + // indirect addition is not supported + vq->vq_ring_size = vring_size(ring->num_descs, ring->align); + vq->vq_ring_mem = (void *)ring->phy_addr; + + vring_init(&vq->vq_ring, vq->vq_nentries, vq->vq_ring_mem, vq->vq_alignment); + + *v_queue = vq; + } + + return (status); +} + +/*! + * virtqueue_create_static - Creates new VirtIO queue - static version + * + * @param id - VirtIO queue ID , must be unique + * @param name - Name of VirtIO queue + * @param ring - Pointer to vring_alloc_info control block + * @param callback - Pointer to callback function, invoked + * when message is available on VirtIO queue + * @param notify - Pointer to notify function, used to notify + * other side that there is job available for it + * @param v_queue - Created VirtIO queue. + * @param vq_ctxt - Statically allocated virtqueue context + * + * @return - Function status + */ +int virtqueue_create_static(unsigned short id, + char *name, + struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue **v_queue, + struct vq_static_context *vq_ctxt) +{ + struct virtqueue *vq = VQ_NULL; + int status = VQUEUE_SUCCESS; + uint32_t vq_size = 0; + + VQ_PARAM_CHK(vq_ctxt == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status, ERROR_VRING_ALIGN); + + if (status == VQUEUE_SUCCESS) + { + vq_size = sizeof(struct virtqueue); + vq = (struct virtqueue *)vq_ctxt; + + env_memset(vq, 0x00, vq_size); + + env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ); + vq->vq_queue_index = id; + vq->vq_alignment = ring->align; + vq->vq_nentries = ring->num_descs; + vq->callback = callback; + vq->notify = notify; + + // indirect addition is not supported + vq->vq_ring_size = vring_size(ring->num_descs, ring->align); + vq->vq_ring_mem = (void *)ring->phy_addr; + + vring_init(&vq->vq_ring, vq->vq_nentries, vq->vq_ring_mem, vq->vq_alignment); + + *v_queue = vq; + } + + return (status); +} + +/*! + * virtqueue_add_buffer() - Enqueues new buffer in vring for consumption + * by other side. + * + * @param vq - Pointer to VirtIO queue control block. + * @param head_idx - Index of buffer to be added to the avail ring + * + * @return - Function status + */ +int virtqueue_add_buffer(struct virtqueue *vq, uint16_t head_idx) +{ + int status = VQUEUE_SUCCESS; + + VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + + VQUEUE_BUSY(vq, avail_write); + + if (status == VQUEUE_SUCCESS) + { + VQ_RING_ASSERT_VALID_IDX(vq, head_idx); + + /* + * Update vring_avail control block fields so that other + * side can get buffer using it. + */ + vq_ring_update_avail(vq, head_idx); + } + + VQUEUE_IDLE(vq, avail_write); + + return (status); +} + +/*! + * virtqueue_fill_avail_buffers - Enqueues single buffer in vring, updates avail + * + * @param vq - Pointer to VirtIO queue control block + * @param buffer - Address of buffer + * @param len - Length of buffer + * + * @return - Function status + */ +int virtqueue_fill_avail_buffers(struct virtqueue *vq, void *buffer, uint32_t len) +{ + struct vring_desc *dp; + uint16_t head_idx; + + int status = VQUEUE_SUCCESS; + + VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + + VQUEUE_BUSY(vq, avail_write); + + if (status == VQUEUE_SUCCESS) + { + head_idx = vq->vq_desc_head_idx; + + dp = &vq->vq_ring.desc[head_idx]; + dp->addr = env_map_vatopa(buffer); + dp->len = len; + dp->flags = VRING_DESC_F_WRITE; + + vq->vq_desc_head_idx++; + + vq_ring_update_avail(vq, head_idx); + } + + VQUEUE_IDLE(vq, avail_write); + + return (status); +} + +/*! + * virtqueue_get_buffer - Returns used buffers from VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param len - Length of conumed buffer + * @param idx - Index to buffer descriptor pool + * + * @return - Pointer to used buffer + */ +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) +{ + struct vring_used_elem *uep; + uint16_t used_idx, desc_idx; + + if ((vq == VQ_NULL) || (vq->vq_used_cons_idx == vq->vq_ring.used->idx)) + return (VQ_NULL); + + VQUEUE_BUSY(vq, used_read); + + used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1); + uep = &vq->vq_ring.used->ring[used_idx]; + + env_rmb(); + + desc_idx = (uint16_t)uep->id; + if (len != VQ_NULL) + *len = uep->len; + + if (idx != VQ_NULL) + *idx = desc_idx; + + vq->vq_used_cons_idx++; + + VQUEUE_IDLE(vq, used_read); + + return env_map_patova(vq->vq_ring.desc[desc_idx].addr); +} + +/*! + * virtqueue_get_buffer_length - Returns size of a buffer + * + * @param vq - Pointer to VirtIO queue control block + * @param idx - Index to buffer descriptor pool + * + * @return - Buffer length + */ +uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) +{ + return vq->vq_ring.desc[idx].len; +} + +/*! + * virtqueue_free - Frees VirtIO queue resources + * + * @param vq - Pointer to VirtIO queue control block + * + */ +void virtqueue_free(struct virtqueue *vq) +{ + if (vq != VQ_NULL) + { + if (vq->vq_ring_mem != VQ_NULL) + { + vq->vq_ring_size = 0; + vq->vq_ring_mem = VQ_NULL; + } + + env_free_memory(vq); + } +} + +/*! + * virtqueue_free - Frees VirtIO queue resources - static version + * + * @param vq - Pointer to VirtIO queue control block + * + */ +void virtqueue_free_static(struct virtqueue *vq) +{ + if (vq != VQ_NULL) + { + if (vq->vq_ring_mem != VQ_NULL) + { + vq->vq_ring_size = 0; + vq->vq_ring_mem = VQ_NULL; + } + } +} + +/*! + * virtqueue_get_available_buffer - Returns buffer available for use in the + * VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param avail_idx - Pointer to index used in vring desc table + * @param len - Length of buffer + * + * @return - Pointer to available buffer + */ +void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len) +{ + uint16_t head_idx = 0; + void *buffer; + + if (vq->vq_available_idx == vq->vq_ring.avail->idx) + { + return (VQ_NULL); + } + + VQUEUE_BUSY(vq, avail_read); + + head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1); + *avail_idx = vq->vq_ring.avail->ring[head_idx]; + + env_rmb(); + + buffer = env_map_patova(vq->vq_ring.desc[*avail_idx].addr); + *len = vq->vq_ring.desc[*avail_idx].len; + + VQUEUE_IDLE(vq, avail_read); + + return (buffer); +} + +/*! + * virtqueue_add_consumed_buffer - Returns consumed buffer back to VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param head_idx - Index of vring desc containing used buffer + * @param len - Length of buffer + * + * @return - Function status + */ +int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len) +{ + if (head_idx > vq->vq_nentries) + { + return (ERROR_VRING_NO_BUFF); + } + + VQUEUE_BUSY(vq, used_write); + vq_ring_update_used(vq, head_idx, len); + VQUEUE_IDLE(vq, used_write); + + return (VQUEUE_SUCCESS); +} + +/*! + * virtqueue_fill_used_buffers - Fill used buffer ring + * + * @param vq - Pointer to VirtIO queue control block + * @param buffer - Buffer to add + * @param len - Length of buffer + * + * @return - Function status + */ +int virtqueue_fill_used_buffers(struct virtqueue *vq, void *buffer, uint32_t len) +{ + uint16_t head_idx; + uint16_t idx; + + VQUEUE_BUSY(vq, used_write); + + head_idx = vq->vq_desc_head_idx; + VQ_RING_ASSERT_VALID_IDX(vq, head_idx); + + /* Enqueue buffer onto the ring. */ + idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, buffer, len); + + vq->vq_desc_head_idx = idx; + + vq_ring_update_used(vq, head_idx, len); + + VQUEUE_IDLE(vq, used_write); + + return (VQUEUE_SUCCESS); +} + +/*! + * virtqueue_enable_cb - Enables callback generation + * + * @param vq - Pointer to VirtIO queue control block + * + * @return - Function status + */ +int virtqueue_enable_cb(struct virtqueue *vq) +{ + return (vq_ring_enable_interrupt(vq, 0)); +} + +/*! + * virtqueue_enable_cb - Disables callback generation + * + * @param vq - Pointer to VirtIO queue control block + * + */ +void virtqueue_disable_cb(struct virtqueue *vq) +{ + VQUEUE_BUSY(vq, avail_write); + + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) + { + vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx - vq->vq_nentries - 1; + } + else + { + vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + } + + VQUEUE_IDLE(vq, avail_write); +} + +/*! + * virtqueue_kick - Notifies other side that there is buffer available for it. + * + * @param vq - Pointer to VirtIO queue control block + */ +void virtqueue_kick(struct virtqueue *vq) +{ + VQUEUE_BUSY(vq, avail_write); + + /* Ensure updated avail->idx is visible to host. */ + env_mb(); + + if (vq_ring_must_notify_host(vq)) + vq_ring_notify_host(vq); + + vq->vq_queued_cnt = 0; + + VQUEUE_IDLE(vq, avail_write); +} + +/*! + * virtqueue_dump Dumps important virtqueue fields , use for debugging purposes + * + * @param vq - Pointer to VirtIO queue control block + */ +void virtqueue_dump(struct virtqueue *vq) +{ + if (vq == VQ_NULL) + return; + + env_print( + "VQ: %s - size=%d; used=%d; queued=%d; " + "desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; " + "used.idx=%d; avail.flags=0x%x; used.flags=0x%x\r\n", + vq->vq_name, vq->vq_nentries, virtqueue_nused(vq), vq->vq_queued_cnt, vq->vq_desc_head_idx, + vq->vq_ring.avail->idx, vq->vq_used_cons_idx, vq->vq_ring.used->idx, vq->vq_ring.avail->flags, + vq->vq_ring.used->flags); +} + +/*! + * virtqueue_get_desc_size - Returns vring descriptor size + * + * @param vq - Pointer to VirtIO queue control block + * + * @return - Descriptor length + */ +uint32_t virtqueue_get_desc_size(struct virtqueue *vq) +{ + uint16_t head_idx = 0; + uint16_t avail_idx = 0; + uint32_t len = 0; + + if (vq->vq_available_idx == vq->vq_ring.avail->idx) + { + return 0; + } + + head_idx = vq->vq_available_idx & (vq->vq_nentries - 1); + avail_idx = vq->vq_ring.avail->ring[head_idx]; + len = vq->vq_ring.desc[avail_idx].len; + + return (len); +} + +/************************************************************************** + * Helper Functions * + **************************************************************************/ + +/*! + * + * vq_ring_add_buffer + * + */ +static uint16_t vq_ring_add_buffer( + struct virtqueue *vq, struct vring_desc *desc, uint16_t head_idx, void *buffer, uint32_t length) +{ + struct vring_desc *dp; + + if (buffer == VQ_NULL) + { + return head_idx; + } + + VQASSERT(vq, head_idx != VQ_RING_DESC_CHAIN_END, "premature end of free desc chain"); + + dp = &desc[head_idx]; + dp->addr = env_map_vatopa(buffer); + dp->len = length; + dp->flags = VRING_DESC_F_WRITE; + + return (head_idx + 1); +} + +/*! + * + * vq_ring_init + * + */ +void vq_ring_init(struct virtqueue *vq) +{ + struct vring *vr; + int i, size; + + size = vq->vq_nentries; + vr = &vq->vq_ring; + + for (i = 0; i < size - 1; i++) + vr->desc[i].next = i + 1; + vr->desc[i].next = VQ_RING_DESC_CHAIN_END; +} + +/*! + * + * vq_ring_update_avail + * + */ +static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx) +{ + uint16_t avail_idx; + + /* + * Place the head of the descriptor chain into the next slot and make + * it usable to the host. The chain is made available now rather than + * deferring to virtqueue_notify() in the hopes that if the host is + * currently running on another CPU, we can keep it processing the new + * descriptor. + */ + avail_idx = vq->vq_ring.avail->idx & (vq->vq_nentries - 1); + vq->vq_ring.avail->ring[avail_idx] = desc_idx; + + env_wmb(); + + vq->vq_ring.avail->idx++; + + /* Keep pending count until virtqueue_notify(). */ + vq->vq_queued_cnt++; +} + +/*! + * + * vq_ring_update_used + * + */ +static void vq_ring_update_used(struct virtqueue *vq, uint16_t head_idx, uint32_t len) +{ + uint16_t used_idx; + struct vring_used_elem *used_desc = VQ_NULL; + + /* + * Place the head of the descriptor chain into the next slot and make + * it usable to the host. The chain is made available now rather than + * deferring to virtqueue_notify() in the hopes that if the host is + * currently running on another CPU, we can keep it processing the new + * descriptor. + */ + used_idx = vq->vq_ring.used->idx & (vq->vq_nentries - 1); + used_desc = &(vq->vq_ring.used->ring[used_idx]); + used_desc->id = head_idx; + used_desc->len = len; + + env_wmb(); + + vq->vq_ring.used->idx++; +} + +/*! + * + * vq_ring_enable_interrupt + * + */ +static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) +{ + /* + * Enable interrupts, making sure we get the latest index of + * what's already been consumed. + */ + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) + { + vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx + ndesc; + } + else + { + vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; + } + + env_mb(); + + /* + * Enough items may have already been consumed to meet our threshold + * since we last checked. Let our caller know so it processes the new + * entries. + */ + if (virtqueue_nused(vq) > ndesc) + { + return (1); + } + + return (0); +} + +/*! + * + * virtqueue_interrupt + * + */ +void virtqueue_notification(struct virtqueue *vq) +{ + if (vq != VQ_NULL) + { + if (vq->callback != VQ_NULL) + vq->callback(vq); + } +} + +/*! + * + * vq_ring_must_notify_host + * + */ +static int vq_ring_must_notify_host(struct virtqueue *vq) +{ + uint16_t new_idx, prev_idx; + uint16_t *event_idx; + + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) + { + new_idx = vq->vq_ring.avail->idx; + prev_idx = new_idx - vq->vq_queued_cnt; + event_idx = vring_avail_event(&vq->vq_ring); + + return (vring_need_event(*event_idx, new_idx, prev_idx) != 0); + } + + return ((vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0); +} + +/*! + * + * vq_ring_notify_host + * + */ +static void vq_ring_notify_host(struct virtqueue *vq) +{ + if (vq->notify != VQ_NULL) + vq->notify(vq); +} + +/*! + * + * virtqueue_nused + * + */ +static int virtqueue_nused(struct virtqueue *vq) +{ + uint16_t used_idx, nused; + + used_idx = vq->vq_ring.used->idx; + + nused = (uint16_t)(used_idx - vq->vq_used_cons_idx); + VQASSERT(vq, nused <= vq->vq_nentries, "used more than available"); + + return (nused); +} diff --git a/samples/subsys/ipc/ipm_mcux/master/CMakeLists.txt b/samples/subsys/ipc/ipm_mcux/master/CMakeLists.txt new file mode 100644 index 000000000000..a2e9ba5fcce8 --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/master/CMakeLists.txt @@ -0,0 +1,14 @@ +set(BOARD lpcxpresso54114) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +enable_language(C ASM) + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/ipm_mcux/master/src) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/ipm_mcux/remote/build/zephyr) +target_sources(app PRIVATE src/main_master.c) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/hal/nxp/mcux/devices/LPC54114/incbin.S) +endif() diff --git a/samples/subsys/ipc/ipm_mcux/master/prj.conf b/samples/subsys/ipc/ipm_mcux/master/prj.conf new file mode 100644 index 000000000000..426eda63090e --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/master/prj.conf @@ -0,0 +1,7 @@ +CONFIG_PRINTK=y +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_SLAVE_CORE_MCUX=y +CONFIG_TIMESLICE_SIZE=1 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_MULTICORE_RPMSG_LITE=y diff --git a/samples/subsys/ipc/ipm_mcux/master/sample.yaml b/samples/subsys/ipc/ipm_mcux/master/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/master/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/ipm_mcux/master/src/main_master.c b/samples/subsys/ipc/ipm_mcux/master/src/main_master.c new file mode 100644 index 000000000000..ecfe8ffbb75f --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/master/src/main_master.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +struct device *ipm; +int gcounter; + +void ping_ipm_callback(void *context, u32_t id, volatile void *data) +{ + gcounter = *(int *)data; + /* Show current ping-pong counter value */ + printk("Received: %d\n", gcounter); + /* Increment on our side */ + gcounter++; + if (gcounter < 100) { + /* Send back to the other core */ + ipm_send(ipm, 1, 0, &gcounter, 4); + } +} + +void main(void) +{ + int first_message = 1; /* do not start from 0, + * zero value can't be sent via mailbox register + */ + printk("Hello World from MASTER! %s\n", CONFIG_ARCH); + + /* Get IPM device handle */ + ipm = device_get_binding("MAILBOX_0"); + if (!ipm) { + printk("Could not get IPM device handle!\n"); + while (1) { + } + } + + /* Register application callback with no context */ + ipm_register_callback(ipm, ping_ipm_callback, NULL); + /* Enable the IPM device */ + ipm_set_enabled(ipm, 1); + + /* Send initial message with 4 bytes length*/ + ipm_send(ipm, 1, 0, &first_message, 4); + while (1) { + } +} diff --git a/samples/subsys/ipc/ipm_mcux/remote/CMakeLists.txt b/samples/subsys/ipc/ipm_mcux/remote/CMakeLists.txt new file mode 100644 index 000000000000..f521ea8992bd --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/remote/CMakeLists.txt @@ -0,0 +1,7 @@ +set(BOARD lpcxpresso54114_m0) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_sources(app PRIVATE src/main_remote.c) diff --git a/samples/subsys/ipc/ipm_mcux/remote/prj.conf b/samples/subsys/ipc/ipm_mcux/remote/prj.conf new file mode 100644 index 000000000000..dc5ce4b2770a --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/remote/prj.conf @@ -0,0 +1,6 @@ +CONFIG_KERNEL_BIN_NAME="core1_image" +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_PLATFORM_SPECIFIC_INIT=n diff --git a/samples/subsys/ipc/ipm_mcux/remote/sample.yaml b/samples/subsys/ipc/ipm_mcux/remote/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/remote/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/ipm_mcux/remote/src/main_remote.c b/samples/subsys/ipc/ipm_mcux/remote/src/main_remote.c new file mode 100644 index 000000000000..3f8bc627de23 --- /dev/null +++ b/samples/subsys/ipc/ipm_mcux/remote/src/main_remote.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +struct device *ipm; + +void ping_ipm_callback(void *context, u32_t id, volatile void *data) +{ + ipm_send(ipm, 1, 0, (const void *)data, 4); +} + + + +void main(void) +{ + ipm = device_get_binding("MAILBOX_0"); + if (!ipm) { + while (1) { + } + } + ipm_register_callback(ipm, ping_ipm_callback, NULL); + ipm_set_enabled(ipm, 1); + while (1) { + } +} diff --git a/samples/subsys/ipc/openamp/README.rst b/samples/subsys/ipc/openamp/README.rst new file mode 100644 index 000000000000..da1d51f2df66 --- /dev/null +++ b/samples/subsys/ipc/openamp/README.rst @@ -0,0 +1,86 @@ +.. _openAMP_example: + +OpenAMP Example Application +########################### + +Overview +******** + +This application demostrates how to use OpenAMP with Zephyr. It is designed to +be an OpenAMP counterpart to the RPMsg-Lite example for the LPCXpresso5411x +chip, to be used for comparison and benchmarking of the two RPC libraries. + +Building the application +************************* + +Building and running this application requires that libmetal and OpenAMP are +compiled first. Clone the libmetal and OpenAMP repositories in an appropriate +location (outside the Zephyr code tree): + +.. code-block:: bash + + $ git clone https://github.com/OpenAMP/libmetal.git + $ git clone https://github.com/OpenAMP/open-amp.git + +Compile and build libmetal for both cores: + +.. code-block:: bash + + $ cd libmetal + $ mkdir build-master build-remote + $ cd build-master + $ cmake -DWITH_ZEPHYR=ON -DBOARD=lpcxpresso54114 .. + $ make + $ cd ../build-remote + $ cmake -DWITH_ZEPHYR=ON -DBOARD=lpcxpresso54114_m0 .. + $ make + +Compile and build OpenAMP for both cores: + +.. code-block:: bash + + $ cd ../../open-amp + $ mkdir build-master build-remote + $ cd build-master + $ cmake -DWITH_ZEPHYR=ON -DWITH_PROXY=OFF -DBOARD=lpcxpresso54114 \ + -DLIBMETAL_INCLUDE_DIR=/build-master/lib/include \ + -DLIBMETAL_LIB=/build-master/lib/libmetal.a .. + $ make + $ cd ../build-remote + $ cmake -DWITH_ZEPHYR=ON -DWITH_PROXY=OFF -DBOARD=lpcxpresso54114_m0 \ + -DLIBMETAL_INCLUDE_DIR=/build-remote/lib/include \ + -DLIBMETAL_LIB=/build-remote/lib/libmetal.a .. + $ make + +Compile the remote application, by running the following commands: + +.. code-block:: bash + + $ cd $ZEPHYR_BASE/samples/subsys/ipc/openamp/remote + $ mkdir build + $ cmake -DBOARD=lpcxpresso54114_m0 \ + -DLIBMETAL_INCLUDE_DIR=/build-remote/lib/include \ + -DLIBMETAL_LIBRARY=/build-remote/lib/libmetal.a \ + -DOPENAMP_INCLUDE_DIR=/lib/include \ + -DOPENAMP_LIBRARY=/build-remote/lib/libopen_amp.a .. + $ make + +Compile the master application, by running the following commands: + +.. code-block:: bash + + $ cd $ZEPHYR_BASE/samples/subsys/ipc/openamp/master + $ mkdir build + $ cmake -DBOARD=lpcxpresso54114 \ + -DLIBMETAL_INCLUDE_DIR=/build-master/lib/include \ + -DLIBMETAL_LIBRARY=/build-master/lib/libmetal.a \ + -DOPENAMP_INCLUDE_DIR=/lib/include \ + -DOPENAMP_LIBRARY=/build-master/lib/libopen_amp.a .. + $ make + +Flash the project to the board from the master build directory: + +.. code-block:: bash + + $ make flash + diff --git a/samples/subsys/ipc/openamp/master/CMakeLists.txt b/samples/subsys/ipc/openamp/master/CMakeLists.txt new file mode 100644 index 000000000000..ba4ea267a9ac --- /dev/null +++ b/samples/subsys/ipc/openamp/master/CMakeLists.txt @@ -0,0 +1,30 @@ +set(BOARD lpcxpresso54114) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +enable_language(C ASM) + +# Location of external dependencies: +set(LIBMETAL_INCLUDE_DIR "/home/kristian/libmetal/build-lpc/lib/include" CACHE PATH "Path to the libmetal header files") +set(LIBMETAL_LIBRARY "/home/kristian/libmetal/build-lpc/lib/libmetal.a" CACHE FILEPATH "Path to the libmetal library") +set(OPENAMP_INCLUDE_DIR "/home/kristian/openamp/lib/include" CACHE PATH "Path to the OpenAMP header files") +set(OPENAMP_LIBRARY "/home/kristian/openamp/build-lpc/lib/libopen_amp.a" CACHE FILEPATH "Path to the OpenAMP library") + +set(ZEPHYR_KERNEL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/zephyr/kernel/libkernel.a") +set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../platform") + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/openamp/remote/build/zephyr) +target_include_directories(app PRIVATE ${LIBMETAL_INCLUDE_DIR} ${OPENAMP_INCLUDE_DIR} ${PLATFORM_DIR}) + +target_sources(app PRIVATE src/main_master.c ${PLATFORM_DIR}/platform.c ${PLATFORM_DIR}/platform_ops.c ${PLATFORM_DIR}/resource_table.c) +if(CONFIG_SOC_SERIES_LPC54XXX) + target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/hal/nxp/mcux/devices/LPC54114/incbin.S) +endif() + +target_link_libraries(app + ${OPENAMP_LIBRARY} + ${LIBMETAL_LIBRARY} + ${ZEPHYR_KERNEL_LIBRARY}) + diff --git a/samples/subsys/ipc/openamp/master/prj.conf b/samples/subsys/ipc/openamp/master/prj.conf new file mode 100644 index 000000000000..cf6d42055f65 --- /dev/null +++ b/samples/subsys/ipc/openamp/master/prj.conf @@ -0,0 +1,7 @@ +CONFIG_PRINTK=y +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_SLAVE_CORE_MCUX=y +CONFIG_TIMESLICE_SIZE=1 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_HEAP_MEM_POOL_SIZE=4096 diff --git a/samples/subsys/ipc/openamp/master/sample.yaml b/samples/subsys/ipc/openamp/master/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/openamp/master/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/openamp/master/src/main_master.c b/samples/subsys/ipc/openamp/master/src/main_master.c new file mode 100644 index 000000000000..aa2fe2543255 --- /dev/null +++ b/samples/subsys/ipc/openamp/master/src/main_master.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018, NXP + * Copyright (c) 2018, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "platform.h" +#include "resource_table.h" + +#define APP_TASK_STACK_SIZE (256) +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +static struct rpmsg_channel *rp_channel; +static struct rpmsg_endpoint *rp_endpoint; + +static K_SEM_DEFINE(channel_created, 0, 1); + +static K_SEM_DEFINE(message_received, 0, 1); +static volatile unsigned int received_data; + +static struct rsc_table_info rsc_info; +static struct hil_proc *proc; + +static void rpmsg_recv_callback(struct rpmsg_channel *channel, void *data, + int data_length, void *private, unsigned long src) +{ + received_data = *((unsigned int *) data); + k_sem_give(&message_received); +} + +static void rpmsg_channel_created(struct rpmsg_channel *channel) +{ + rp_channel = channel; + rp_endpoint = rpmsg_create_ept(rp_channel, rpmsg_recv_callback, RPMSG_NULL, RPMSG_ADDR_ANY); + k_sem_give(&channel_created); +} + +static void rpmsg_channel_deleted(struct rpmsg_channel *channel) +{ + rpmsg_destroy_ept(rp_endpoint); +} + +static unsigned int receive_message(void) +{ + while (k_sem_take(&message_received, K_NO_WAIT) != 0) + hil_poll(proc, 0); + return received_data; +} + +static int send_message(unsigned int message) +{ + return rpmsg_send(rp_channel, &message, sizeof(message)); +} + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + printk("\r\nOpenAMP demo started\r\n"); + + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + metal_init(&metal_params); + + proc = platform_init(RPMSG_MASTER); + if (proc == NULL) { + printk("platform_init() failed\n"); + goto _cleanup; + } + + resource_table_init((void **) &rsc_info.rsc_tab, &rsc_info.size); + + struct remote_proc *rproc_ptr = NULL; + int status = remoteproc_resource_init(&rsc_info, proc, + rpmsg_channel_created, rpmsg_channel_deleted, + rpmsg_recv_callback, &rproc_ptr, RPMSG_MASTER); + if (status != 0) { + printk("remoteproc_resource_init() failed with status %d\n", status); + goto _cleanup; + } + + while (k_sem_take(&channel_created, K_NO_WAIT) != 0) + hil_poll(proc, 0); + + unsigned int message = 0; + status = send_message(message); + if (status < 0) { + printk("send_message(%d) failed with status %d\n", message, status); + goto _cleanup; + } + + while (message <= 100) { + message = receive_message(); + printk("Primary core received a message: %d\n", message); + + message++; + status = send_message(message); + if (status < 0) { + printk("send_message(%d) failed with status %d\n", message, status); + goto _cleanup; + } + } + +_cleanup: + if (rproc_ptr) { + remoteproc_resource_deinit(rproc_ptr); + } + metal_finish(); + + printk("OpenAMP demo ended.\n"); +} + +void main(void) +{ + printk("Starting application thread!\n"); + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/openamp/platform/platform.c b/samples/subsys/ipc/openamp/platform/platform.c new file mode 100644 index 000000000000..232fff49c97b --- /dev/null +++ b/samples/subsys/ipc/openamp/platform/platform.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "platform.h" +#include "resource_table.h" + +extern struct hil_platform_ops platform_ops; + +static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDRESS }; +static struct metal_device shm_device = { + .name = SHM_DEVICE_NAME, + .bus = NULL, + .num_regions = 1, + { + { + .virt = (void *) SHM_START_ADDRESS, + .physmap = shm_physmap, + .size = SHM_SIZE, + .page_shift = 0xffffffff, + .page_mask = 0xffffffff, + .mem_flags = 0, + .ops = { NULL }, + }, + }, + .node = { NULL }, + .irq_num = 0, + .irq_info = NULL +}; + +struct hil_proc *platform_init(int role) +{ + int status; + + status = metal_register_generic_device(&shm_device); + if (status != 0) { + printk("metal_register_generic_device(): could not register shared memory device: error code %d\n", status); + return NULL; + } + + struct hil_proc *proc = hil_create_proc(&platform_ops, role != RPMSG_MASTER, NULL); + if (proc == NULL) { + printk("platform_create(): could not allocate hil_proc\n"); + return NULL; + } + + hil_set_shm(proc, "generic", SHM_DEVICE_NAME, SHM_START_ADDRESS, SHM_SIZE); + return proc; +} + diff --git a/samples/subsys/ipc/openamp/platform/platform.h b/samples/subsys/ipc/openamp/platform/platform.h new file mode 100644 index 000000000000..b7c41505b60a --- /dev/null +++ b/samples/subsys/ipc/openamp/platform/platform.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef PLATFORM_H__ +#define PLATFORM_H__ + +#include + +#define SHM_START_ADDRESS 0x04000400 +#define SHM_SIZE 0x7c00 +#define SHM_DEVICE_NAME "sramx.shm" + +#define VRING_COUNT 2 +#define VRING_RX_ADDRESS 0x04000400 +#define VRING_TX_ADDRESS 0x04000800 +#define VRING_ALIGNMENT 4 +#define VRING_SIZE 32 + +struct hil_proc *platform_init(int role); + +#endif + diff --git a/samples/subsys/ipc/openamp/platform/platform_ops.c b/samples/subsys/ipc/openamp/platform/platform_ops.c new file mode 100644 index 000000000000..caff23113769 --- /dev/null +++ b/samples/subsys/ipc/openamp/platform/platform_ops.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include "platform.h" + +static K_SEM_DEFINE(data_sem, 0, 1); +static struct device *ipm_handle = NULL; + +static void platform_ipm_callback(void *context, u32_t id, volatile void *data) +{ + k_sem_give(&data_sem); +} + +static int enable_interrupt(struct proc_intr *intr) +{ + return ipm_set_enabled(ipm_handle, 1); +} + +static void notify(struct hil_proc *proc, struct proc_intr *intr_info) +{ + uint32_t dummy_data = 0x12345678; /* Some data must be provided */ + + ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data)); +} + +static int boot_cpu(struct hil_proc *proc, unsigned int load_addr) +{ + return -1; +} + +static void shutdown_cpu(struct hil_proc *proc) +{ +} + +static int poll(struct hil_proc *proc, int nonblock) +{ + int status = k_sem_take(&data_sem, nonblock ? K_NO_WAIT : K_FOREVER); + + if (status == 0) { + hil_notified(proc, 0xffffffff); + } + + return status; +} + +static struct metal_io_region *alloc_shm(struct hil_proc *proc, + metal_phys_addr_t physical, size_t size, + struct metal_device **device) +{ + int status = metal_device_open("generic", SHM_DEVICE_NAME, device); + + if (status != 0) { + return NULL; + } + + return metal_device_io_region(*device, 0); +} + +static void release_shm(struct hil_proc *proc, struct metal_device *device, + struct metal_io_region *io) +{ + metal_device_close(device); +} + +static int initialize(struct hil_proc *proc) +{ + ipm_handle = device_get_binding("MAILBOX_0"); + if (!ipm_handle) { + return -1; + } + + ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); + return 0; +} + +static void release(struct hil_proc *proc) +{ + ipm_set_enabled(ipm_handle, 0); +} + +struct hil_platform_ops platform_ops = { + .enable_interrupt = enable_interrupt, + .notify = notify, + .boot_cpu = boot_cpu, + .shutdown_cpu = shutdown_cpu, + .poll = poll, + .alloc_shm = alloc_shm, + .release_shm = release_shm, + .initialize = initialize, + .release = release +}; + diff --git a/samples/subsys/ipc/openamp/platform/resource_table.c b/samples/subsys/ipc/openamp/platform/resource_table.c new file mode 100644 index 000000000000..db2d99ce2539 --- /dev/null +++ b/samples/subsys/ipc/openamp/platform/resource_table.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "platform.h" +#include "resource_table.h" + +struct lpc_resource_table *rsc_table_ptr = (void *) RSC_TABLE_ADDRESS; + +#if defined(CPU_LPC54114J256BD64_cm4) +static const struct lpc_resource_table rsc_table = { + .ver = 1, + .num = 2, + .offset = { + offsetof(struct lpc_resource_table, mem), + offsetof(struct lpc_resource_table, vdev), + }, + .mem = { RSC_RPROC_MEM, SHM_START_ADDRESS, SHM_START_ADDRESS, SHM_SIZE, 0 }, + .vdev = { RSC_VDEV, VIRTIO_ID_RPMSG, 0, 1 << VIRTIO_RPMSG_F_NS, 0, 0, 0, VRING_COUNT, { 0, 0 } }, + .vring0 = { VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_SIZE, 1, 0 }, + .vring1 = { VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_SIZE, 2, 0 }, +}; +#endif + +void resource_table_init(void **table_ptr, int *length) +{ +#if defined(CPU_LPC54114J256BD64_cm4) + /* Master: copy the resource table to shared memory. */ + memcpy(rsc_table_ptr, &rsc_table, sizeof(struct lpc_resource_table)); +#endif + + *length = sizeof(struct lpc_resource_table); + *table_ptr = rsc_table_ptr; +} + diff --git a/samples/subsys/ipc/openamp/platform/resource_table.h b/samples/subsys/ipc/openamp/platform/resource_table.h new file mode 100644 index 000000000000..c647bb06dfbd --- /dev/null +++ b/samples/subsys/ipc/openamp/platform/resource_table.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RESOURCE_TABLE_H__ +#define RESOURCE_TABLE_H__ + +#include + +#define RSC_TABLE_ADDRESS 0x04000000 + +OPENAMP_PACKED_BEGIN +struct lpc_resource_table { + uint32_t ver; + uint32_t num; + uint32_t reserved[2]; + uint32_t offset[2]; + struct fw_rsc_rproc_mem mem; + struct fw_rsc_vdev vdev; + struct fw_rsc_vdev_vring vring0, vring1; +} OPENAMP_PACKED_END; + +void resource_table_init(void **table_ptr, int *length); + +#endif + diff --git a/samples/subsys/ipc/openamp/remote/CMakeLists.txt b/samples/subsys/ipc/openamp/remote/CMakeLists.txt new file mode 100644 index 000000000000..dc6e6a5310f5 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/CMakeLists.txt @@ -0,0 +1,23 @@ +set(BOARD lpcxpresso54114_m0) + +# Location of external dependencies: +set(LIBMETAL_INCLUDE_DIR "/home/kristian/libmetal/build-lpc-m0/lib/include" CACHE PATH "Path to the libmetal header files") +set(LIBMETAL_LIBRARY "/home/kristian/libmetal/build-lpc-m0/lib/libmetal.a" CACHE FILEPATH "Path to the libmetal library") +set(OPENAMP_INCLUDE_DIR "/home/kristian/openamp/lib/include" CACHE PATH "Path to the OpenAMP header files") +set(OPENAMP_LIBRARY "/home/kristian/openamp/build-lpc-m0/lib/libopen_amp.a" CACHE FILEPATH "Path to the OpenAMP library") + +set(ZEPHYR_KERNEL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/zephyr/kernel/libkernel.a") +set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../platform") + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_include_directories(app PRIVATE ${LIBMETAL_INCLUDE_DIR} ${OPENAMP_INCLUDE_DIR} ${PLATFORM_DIR}) + +target_sources(app PRIVATE src/main_remote.c ${PLATFORM_DIR}/platform.c ${PLATFORM_DIR}/resource_table.c ${PLATFORM_DIR}/platform_ops.c) +target_link_libraries(app + ${OPENAMP_LIBRARY} + ${LIBMETAL_LIBRARY} + ${ZEPHYR_KERNEL_LIBRARY}) + diff --git a/samples/subsys/ipc/openamp/remote/prj.conf b/samples/subsys/ipc/openamp/remote/prj.conf new file mode 100644 index 000000000000..a437d1bc5a2d --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/prj.conf @@ -0,0 +1,8 @@ +CONFIG_KERNEL_BIN_NAME="core1_image" +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_PLATFORM_SPECIFIC_INIT=n +CONFIG_HEAP_MEM_POOL_SIZE=4096 + diff --git a/samples/subsys/ipc/openamp/remote/sample.yaml b/samples/subsys/ipc/openamp/remote/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/openamp/remote/src/main_remote.c b/samples/subsys/ipc/openamp/remote/src/main_remote.c new file mode 100644 index 000000000000..9d4fb490d677 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/src/main_remote.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, NXP + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "platform.h" +#include "resource_table.h" + +#define APP_TASK_STACK_SIZE (256) +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +static K_SEM_DEFINE(channel_created, 0, 1); + +static K_SEM_DEFINE(message_received, 0, 1); +static volatile unsigned int received_data; + +static struct rsc_table_info rsc_info; +static struct hil_proc *proc; + +static struct rpmsg_channel *rp_channel; +static struct rpmsg_endpoint *rp_endpoint; + +static void rpmsg_recv_callback(struct rpmsg_channel *channel, void *data, + int data_length, void *private, unsigned long src) +{ + received_data = *((unsigned int *) data); + k_sem_give(&message_received); +} + +static void rpmsg_channel_created(struct rpmsg_channel *channel) +{ + rp_channel = channel; + rp_endpoint = rpmsg_create_ept(rp_channel, rpmsg_recv_callback, RPMSG_NULL, RPMSG_ADDR_ANY); + k_sem_give(&channel_created); +} + +static void rpmsg_channel_deleted(struct rpmsg_channel *channel) +{ + rpmsg_destroy_ept(rp_endpoint); +} + +static unsigned int receive_message(void) +{ + while (k_sem_take(&message_received, K_NO_WAIT) != 0) + hil_poll(proc, 0); + return received_data; +} + +static int send_message(unsigned int message) +{ + return rpmsg_send(rp_channel, &message, sizeof(message)); +} + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + metal_init(&metal_params); + + proc = platform_init(RPMSG_MASTER); + if (proc == NULL) { + goto _cleanup; + } + + resource_table_init((void **) &rsc_info.rsc_tab, &rsc_info.size); + + struct remote_proc *rproc_ptr = NULL; + int status = remoteproc_resource_init(&rsc_info, proc, + rpmsg_channel_created, rpmsg_channel_deleted, + rpmsg_recv_callback, &rproc_ptr, RPMSG_REMOTE); + if (status != 0) { + goto _cleanup; + } + + while (k_sem_take(&channel_created, K_NO_WAIT) != 0) + hil_poll(proc, 0); + + unsigned int message = 0; + while (message <= 100) { + message = receive_message(); + message++; + status = send_message(message); + if (status <= 0) { + goto _cleanup; + } + } + +_cleanup: + if (rproc_ptr) { + remoteproc_resource_deinit(rproc_ptr); + } +} + +void main(void) +{ + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/rpmsg_lite/master/CMakeLists.txt b/samples/subsys/ipc/rpmsg_lite/master/CMakeLists.txt new file mode 100644 index 000000000000..4f6a8fb5dc40 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/master/CMakeLists.txt @@ -0,0 +1,32 @@ +set(BOARD lpcxpresso54114) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +enable_language(C ASM) + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/rpmsg_lite) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/rpmsg_lite/master/src) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/rpmsg_lite/remote/build/zephyr) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/include) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/include/platform/lpc5411x) +endif() + +if(CONFIG_MULTICORE_RPMSG_LITE) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/common/llist.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c) +endif() +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/virtio/virtqueue.c) +endif() + +target_sources(app PRIVATE src/main_master.c) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/hal/nxp/mcux/devices/LPC54114/incbin.S) +endif() diff --git a/samples/subsys/ipc/rpmsg_lite/master/prj.conf b/samples/subsys/ipc/rpmsg_lite/master/prj.conf new file mode 100644 index 000000000000..1c88c940eeeb --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/master/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PRINTK=y +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_SLAVE_CORE_MCUX=y +CONFIG_TIMESLICE_SIZE=1 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_MULTICORE_RPMSG_LITE=y +CONFIG_HEAP_MEM_POOL_SIZE=4096 diff --git a/samples/subsys/ipc/rpmsg_lite/master/sample.yaml b/samples/subsys/ipc/rpmsg_lite/master/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/master/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/rpmsg_lite/master/src/main_master.c b/samples/subsys/ipc/rpmsg_lite/master/src/main_master.c new file mode 100644 index 000000000000..f49fd2346b38 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/master/src/main_master.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "rpmsg_lite.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" + +#define APP_TASK_STACK_SIZE (256) +#define REMOTE_EPT_ADDR (30) +#define LOCAL_EPT_ADDR (40) + +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +#ifdef CPU_LPC54114J256BD64_cm4 +#define RPMSG_LITE_LINK_ID (RL_PLATFORM_LPC5411x_M4_M0_LINK_ID) +#define SH_MEM_TOTAL_SIZE (6144) +#else +#error Please define RPMSG_LITE_LINK_ID and SH_MEM_TOTAL_SIZE for the CPU used. +#endif + +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__(( + section(".noinit.$rpmsg_sh_mem") + )); +#elif defined(__CC_ARM) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__(( + section("rpmsg_sh_mem_section") + )); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif + +struct the_message { + u32_t DATA; +}; + +struct the_message volatile msg = {0}; + +void app_nameservice_isr_cb(unsigned int new_ept, const char *new_ept_name, + unsigned long flags, void *user_data) +{ + unsigned long *data = (unsigned long *)user_data; + + *data = new_ept; +} + + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + volatile unsigned long remote_addr = 0; + struct rpmsg_lite_endpoint *my_ept; + rpmsg_queue_handle my_queue; + struct rpmsg_lite_instance *my_rpmsg; + rpmsg_ns_handle ns_handle; + int len; + + /* Print the initial banner */ + printk("\r\nRPMsg demo starts\r\n"); + + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, + RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + + my_queue = rpmsg_queue_create(my_rpmsg); + my_ept = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, + rpmsg_queue_rx_cb, my_queue); + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, + (void *)&remote_addr); + + /* Wait until the secondary core application issues the nameservice isr + * and the remote endpoint address is known. + */ + while (remote_addr == 0) { + } + + /* Send the first message to the remoteproc */ + msg.DATA = 0; + rpmsg_lite_send(my_rpmsg, my_ept, remote_addr, (char *)&msg, + sizeof(struct the_message), RL_DONT_BLOCK); + + while (msg.DATA <= 100) { + rpmsg_queue_recv(my_rpmsg, my_queue, + (unsigned long *)&remote_addr, (char *)&msg, + sizeof(struct the_message), &len, RL_BLOCK); + printk("Primary core received a msg\r\n"); + printk("Message: Size=%x, DATA = %i\r\n", len, msg.DATA); + msg.DATA++; + + rpmsg_lite_send(my_rpmsg, my_ept, remote_addr, (char *)&msg, + sizeof(struct the_message), RL_BLOCK); + } + + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + my_ept = NULL; + rpmsg_queue_destroy(my_rpmsg, my_queue); + my_queue = NULL; + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + + /* Print the ending banner */ + printk("\r\nRPMsg demo ends\r\n"); + while (1) { + } +} + +void main(void) +{ + printk("===== app started ========\n"); + + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/rpmsg_lite/remote/CMakeLists.txt b/samples/subsys/ipc/rpmsg_lite/remote/CMakeLists.txt new file mode 100644 index 000000000000..6773707f7897 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/remote/CMakeLists.txt @@ -0,0 +1,26 @@ +set(BOARD lpcxpresso54114_m0) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/ipc/rpmsg_lite) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/drivers) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/include) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/include/platform/lpc5411x) +endif() + +if(CONFIG_MULTICORE_RPMSG_LITE) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/common/llist.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c) +if(CONFIG_SOC_SERIES_LPC54XXX) +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c) +endif() +target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/ext/multicore/rpmsg_lite/lib/virtio/virtqueue.c) +endif() + +target_sources(app PRIVATE src/main_remote.c) + diff --git a/samples/subsys/ipc/rpmsg_lite/remote/prj.conf b/samples/subsys/ipc/rpmsg_lite/remote/prj.conf new file mode 100644 index 000000000000..99509c516699 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/remote/prj.conf @@ -0,0 +1,9 @@ +CONFIG_KERNEL_BIN_NAME="core1_image" +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_IPM=y +CONFIG_IPM_MCUX=y +CONFIG_PLATFORM_SPECIFIC_INIT=n +CONFIG_MULTICORE_RPMSG_LITE=y +CONFIG_HEAP_MEM_POOL_SIZE=4096 + diff --git a/samples/subsys/ipc/rpmsg_lite/remote/sample.yaml b/samples/subsys/ipc/rpmsg_lite/remote/sample.yaml new file mode 100644 index 000000000000..1b4c03be8874 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/remote/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: TBD + name: TBD +tests: + test: + build_only: true + filter: CONFIG_SOC_MCUX + tags: samples ipm diff --git a/samples/subsys/ipc/rpmsg_lite/remote/src/main_remote.c b/samples/subsys/ipc/rpmsg_lite/remote/src/main_remote.c new file mode 100644 index 000000000000..8a0efabcb291 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/remote/src/main_remote.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "rpmsg_lite.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" + +#define APP_TASK_STACK_SIZE (256) +#define LOCAL_EPT_ADDR (30) + +#ifdef CPU_LPC54114J256BD64_cm0plus +#define RPMSG_LITE_LINK_ID (RL_PLATFORM_LPC5411x_M4_M0_LINK_ID) +#define RPMSG_LITE_SHMEM_BASE (0x20026800) +#define RPMSG_LITE_NS_USED (1) +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-openamp-demo-channel" +#else +#error Please define ERPC_TRANSPORT_RPMSG_LITE_LINK_ID, RPMSG_LITE_SHMEM_BASE, \ +RPMSG_LITE_NS_USED and RPMSG_LITE_NS_ANNOUNCE_STRING values for the CPU used. +#endif + +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +struct the_message { + u32_t DATA; +}; + +struct the_message volatile msg = {0}; + +void app_nameservice_isr_cb(unsigned int new_ept, const char *new_ept_name, + unsigned long flags, void *user_data) +{ +} + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + volatile unsigned long remote_addr; + struct rpmsg_lite_endpoint *volatile my_ept; + volatile rpmsg_queue_handle my_queue; + struct rpmsg_lite_instance *volatile my_rpmsg; +#ifdef RPMSG_LITE_NS_USED + volatile rpmsg_ns_handle ns_handle; +#endif /*RPMSG_LITE_NS_USED*/ + + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, + RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + + while (!rpmsg_lite_is_link_up(my_rpmsg)) { + } + + my_queue = rpmsg_queue_create(my_rpmsg); + my_ept = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, + rpmsg_queue_rx_cb, my_queue); + +#ifdef RPMSG_LITE_NS_USED + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, NULL); + rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, + RL_NS_CREATE); + printk("Nameservice announce sent.\r\n"); +#endif /*RPMSG_LITE_NS_USED*/ + + while (msg.DATA <= 100) { + printk("Waiting for ping...\r\n"); + rpmsg_queue_recv(my_rpmsg, my_queue, + (unsigned long *)&remote_addr, (char *)&msg, + sizeof(struct the_message), NULL, RL_BLOCK); + msg.DATA++; + printk("Sending pong...\r\n"); + rpmsg_lite_send(my_rpmsg, my_ept, remote_addr, (char *)&msg, + sizeof(struct the_message), RL_BLOCK); + } + + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + my_ept = NULL; + rpmsg_queue_destroy(my_rpmsg, my_queue); + my_queue = NULL; +#ifdef RPMSG_LITE_NS_USED + rpmsg_ns_unbind(my_rpmsg, ns_handle); +#endif + rpmsg_lite_deinit(my_rpmsg); + msg.DATA = 0; + + /* End of example */ + while (1) { + } +} + +void main(void) +{ + printk("===== app started ========\n"); + + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/rpmsg_lite/rpmsg_config.h b/samples/subsys/ipc/rpmsg_lite/rpmsg_config.h new file mode 100644 index 000000000000..92802a28e491 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_lite/rpmsg_config.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _RPMSG_CONFIG_H +#define _RPMSG_CONFIG_H + +/* + * RPMsg config values. + * See $ZEPHYR_BASE/ext/multicore/rpmsg_lite/lib/include/rpmsg_default_config.h + * for the list of all config items. + */ + +#define RL_MS_PER_INTERVAL (1) + +#define RL_BUFFER_PAYLOAD_SIZE (496) + +#define RL_API_HAS_ZEROCOPY (1) + +#define RL_USE_STATIC_API (0) + +#endif /* _RPMSG_CONFIG_H */