diff --git a/bsp/stm32/stm32mp157a-st-ev1/.config b/bsp/stm32/stm32mp157a-st-ev1/.config index 4f6a2ab164..8886fca66a 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/.config +++ b/bsp/stm32/stm32mp157a-st-ev1/.config @@ -422,12 +422,14 @@ CONFIG_SOC_STM32MP157A=y # Onboard Peripheral Drivers # CONFIG_BSP_USING_STLINK_TO_USART=y +# CONFIG_BSP_USING_PMIC is not set +# CONFIG_BSP_USING_NAND is not set +# CONFIG_BSP_USING_OPENAMP is not set # # On-chip Peripheral Drivers # CONFIG_BSP_USING_GPIO=y -# CONFIG_BSP_USING_WWDG is not set CONFIG_BSP_USING_UART=y # CONFIG_BSP_USING_UART3 is not set # CONFIG_BSP_UART3_RX_USING_DMA is not set @@ -435,11 +437,10 @@ CONFIG_BSP_USING_UART4=y # CONFIG_BSP_UART4_RX_USING_DMA is not set # CONFIG_BSP_UART4_TX_USING_DMA is not set # CONFIG_BSP_USING_TIM is not set -# CONFIG_BSP_USING_LPTIM is not set # CONFIG_BSP_USING_PWM is not set # CONFIG_BSP_USING_ADC is not set # CONFIG_BSP_USING_DAC is not set -# CONFIG_BSP_USING_I2C1 is not set +# CONFIG_BSP_USING_I2C is not set # CONFIG_BSP_USING_SPI is not set # CONFIG_BSP_USING_CRC is not set # CONFIG_BSP_USING_RNG is not set diff --git a/bsp/stm32/stm32mp157a-st-ev1/.cproject b/bsp/stm32/stm32mp157a-st-ev1/.cproject index 942edf4226..f21f6d8902 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/.cproject +++ b/bsp/stm32/stm32mp157a-st-ev1/.cproject @@ -67,15 +67,14 @@ - - - - - - + + + + + + - @@ -159,15 +158,14 @@ - - - - - - + + + + + + - @@ -180,7 +178,7 @@ - + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/ipcc.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/ipcc.h new file mode 100644 index 0000000000..3f07bf7536 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/ipcc.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * File Name : IPCC.h + * Description : This file provides code for the configuration + * of the IPCC instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ipcc_H +#define __ipcc_H +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern IPCC_HandleTypeDef hipcc; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_IPCC_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ ipcc_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/mbox_ipcc.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/mbox_ipcc.h new file mode 100644 index 0000000000..0e605cc919 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/mbox_ipcc.h @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * @file mbox_ipcc.h + * @author MCD Application Team + * @brief Header for mbox_ipcc.c module + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBOX_IPCC_H_ +#define MBOX_IPCC_H_ + +/* USER CODE BEGIN firstSection */ +/* can be used to modify / undefine following code or add new definitions */ +/* USER CODE END firstSection */ + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +int MAILBOX_Notify(void *priv, uint32_t id); +int MAILBOX_Init(void); +int MAILBOX_Poll(struct virtio_device *vdev); + +/* USER CODE BEGIN lastSection */ +/* can be used to modify / undefine previous code or add new definitions */ +/* USER CODE END lastSection */ + +#endif /* MBOX_IPCC_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp.h new file mode 100644 index 0000000000..3589f3bdd1 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * @file openamp.h + * @brief Header for openamp applications + * @author MCD Application Team + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __openamp_H +#define __openamp_H +#ifdef __cplusplus + extern "C" { +#endif + +#include "openamp/open_amp.h" +#include "openamp_conf.h" + +#define OPENAMP_send rpmsg_send +#define OPENAMP_destroy_ept rpmsg_destroy_ept + +/* Initialize the openamp framework*/ +int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb); + +/* Deinitialize the openamp framework*/ +void OPENAMP_DeInit(void); + +/* Initialize the endpoint struct*/ +void OPENAMP_init_ept(struct rpmsg_endpoint *ept); + +/* Create and register the endpoint */ +int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, + uint32_t dest, rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb unbind_cb); + +/* Check for new rpmsg reception */ +void OPENAMP_check_for_message(void); + +/* Wait loop on endpoint ready ( message dest address is know)*/ +void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept); + +#ifdef __cplusplus +} +#endif +#endif /*__openamp_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_conf.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_conf.h new file mode 100644 index 0000000000..e6c32798dd --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_conf.h @@ -0,0 +1,242 @@ +/** + ****************************************************************************** + * @file openamp_conf.h + * @author MCD Application Team + * @brief Configuration file for OpenAMP MW + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __OPENAMP_CONF__H__ +#define __OPENAMP_CONF__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) +#include "openamp_log.h" +#endif + + /* ########################## Mailbox Interface Selection ############################## */ + /** + * @brief This is the list of Mailbox interface to be used in the OpenAMP MW + * Please note that not all interfaces are supported by a STM32 device + */ +#define MAILBOX_IPCC_IF_ENABLED +//#define MAILBOX_HSEM_IF_ENABLED + + /* Includes ------------------------------------------------------------------*/ + /** + * @brief Include Maibox interface header file + */ + +#ifdef MAILBOX_IPCC_IF_ENABLED +#include "mbox_ipcc.h" +#endif /* MAILBOX_IPCC_IF_ENABLED */ + +#ifdef MAILBOX_HSEM_IF_ENABLED +#include "mbox_hsem.h" +#endif /* MAILBOX_HSEM_IF_ENABLED */ + + /* ########################## Virtual Diver Module Selection ############################## */ + /** + * @brief This is the list of modules to be used in the OpenAMP Virtual driver module + * Please note that virtual driver are not supported on all stm32 families + */ +//#define VIRTUAL_UART_MODULE_ENABLED +//#define VIRTUAL_I2C_MODULE_ENABLED + + /* Includes ------------------------------------------------------------------*/ + /** + * @brief Include Virtual Driver module's header file + */ + +#ifdef VIRTUAL_UART_MODULE_ENABLED +#include "virt_uart.h" +#endif /* VIRTUAL_UART_MODULE_ENABLED */ + +#ifdef VIRTUAL_I2C_MODULE_ENABLED +#include "virt_i2c.h" +#endif /* VIRTUAL_I2C_MODULE_ENABLED */ + + /* ########################## Linux Master Selection ############################## */ + /** + * @brief Due to Linux compatibility, it's important to distinguish if the MASTER is Linux or not. + * In that case, the LINUX_RPROC_MASTER define is required + */ +#define LINUX_RPROC_MASTER + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup OPENAMP_MW + * @{ + */ + +/** @defgroup OPENAMP_CONF OPENAMP_CONF + * @brief Configuration file for Openamp mw + * @{ + */ + +/** @defgroup OPENAMP_CONF_Exported_Variables OPENAMP_CONF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Defines OPENAMP_CONF_Exported_Defines + * @brief Defines for configuration of the Openamp mw + * @{ + */ + +#if defined (__ICCARM__) +/* + * For IAR, the .icf file should contain the following lines: + * define symbol __OPENAMP_region_start__ = BASE_ADDRESS; (0x38000400 for example) + * define symbol __OPENAMP_region_size__ = MEM_SIZE; (0xB000 as example) + * + * export symbol __OPENAMP_region_start__; + * export symbol __OPENAMP_region_size__; + */ +extern const uint32_t __OPENAMP_region_start__; +extern const uint8_t __OPENAMP_region_size__; +#define SHM_START_ADDRESS ((metal_phys_addr_t)&__OPENAMP_region_start__) +#define SHM_SIZE ((size_t)&__OPENAMP_region_size__) + +#elif defined(__CC_ARM) +/* + * For MDK-ARM, the scatter file .sct should contain the following line: + * LR_IROM1 .... { + * ... + * __OpenAMP_SHMEM__ 0x38000400 EMPTY 0x0000B000 {} ; Shared Memory area used by OpenAMP + * } + * + */ +extern unsigned int Image$$__OpenAMP_SHMEM__$$Base; +extern unsigned int Image$$__OpenAMP_SHMEM__$$ZI$$Length; +#define SHM_START_ADDRESS (unsigned int)&Image$$__OpenAMP_SHMEM__$$Base +#define SHM_SIZE ((size_t)&Image$$__OpenAMP_SHMEM__$$ZI$$Length) + +#else +/* + * for GCC add the following content to the .ld file: + * MEMORY + * { + * ... + * OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K + * } + * __OPENAMP_region_start__ = ORIGIN(OPEN_AMP_SHMEM); + * __OPENAMP_region_end__ = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM); + * + * using the LENGTH(OPEN_AMP_SHMEM) to set the SHM_SIZE lead to a crash thus we + * use the start and end address. + */ + +extern int __OPENAMP_region_start__[]; /* defined by linker script */ +extern int __OPENAMP_region_end__[]; /* defined by linker script */ + +#define SHM_START_ADDRESS ((metal_phys_addr_t)__OPENAMP_region_start__) +#define SHM_SIZE (size_t)((void *)__OPENAMP_region_end__ - (void *) __OPENAMP_region_start__) + +#endif + +#if defined LINUX_RPROC_MASTER +#define VRING_RX_ADDRESS -1 /* allocated by Master processor: CA7 */ +#define VRING_TX_ADDRESS -1 /* allocated by Master processor: CA7 */ +#define VRING_BUFF_ADDRESS -1 /* allocated by Master processor: CA7 */ +#define VRING_ALIGNMENT 16 /* fixed to match with linux constraint */ +#define VRING_NUM_BUFFS 16 /* number of rpmsg buffer */ +#else + +#define VRING_RX_ADDRESS 0x10040000 /* allocated by Master processor: CA7 */ +#define VRING_TX_ADDRESS 0x10040400 /* allocated by Master processor: CA7 */ +#define VRING_BUFF_ADDRESS 0x10040800 /* allocated by Master processor: CA7 */ +#define VRING_ALIGNMENT 16 /* fixed to match with 4k page alignement requested by linux */ +#define VRING_NUM_BUFFS 16 /* number of rpmsg buffer */ +#endif +/* Fixed parameter */ +#define NUM_RESOURCE_ENTRIES 2 +#define VRING_COUNT 2 +#define VDEV_ID 0xFF +#define VRING0_ID 0 /* VRING0 ID (master to remote) fixed to 0 for linux compatibility*/ +#define VRING1_ID 1 /* VRING1 ID (remote to master) fixed to 1 for linux compatibility */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Macros OPENAMP_CONF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* DEBUG macros */ + +#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) + #define OPENAMP_log_dbg log_dbg + #define OPENAMP_log_info log_info + #define OPENAMP_log_warn log_warn + #define OPENAMP_log_err log_err +#else + #define OPENAMP_log_dbg(...) + #define OPENAMP_log_info(...) + #define OPENAMP_log_warn(...) + #define OPENAMP_log_err(...) +#endif + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Types OPENAMP_CONF_Exported_Types + * @brief Types. + * @{ + */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_FunctionsPrototype OPENAMP_CONF_Exported_FunctionsPrototype + * @brief Declaration of public functions for OpenAMP mw. + * @{ + */ + +/* Exported functions -------------------------------------------------------*/ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENAMP_CONF__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_log.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_log.h new file mode 100644 index 0000000000..60c3f2af58 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/openamp_log.h @@ -0,0 +1,134 @@ +/** + ****************************************************************************** + * @file log.h + * @author MCD Application Team + * @brief logging services + ****************************************************************************** + * + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + * + ****************************************************************************** + */ + +/** @addtogroup LOG + * @{ + */ + +/** @addtogroup stm32mp1xx_Log + * @{ + */ + +/** + * @brief Define to prevent recursive inclusion + */ +#ifndef __LOG_STM32MP1XX_H +#define __LOG_STM32MP1XX_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** @addtogroup STM32MP1xx_Log_Includes + * @{ + */ +#include "stm32mp1xx_hal.h" +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Exported_Constants + * @{ + */ +#if defined (__LOG_TRACE_IO_) +#define SYSTEM_TRACE_BUF_SZ 2048 +#endif + +#define LOGQUIET 0 +#define LOGERR 1 +#define LOGWARN 2 +#define LOGINFO 3 +#define LOGDBG 4 + +#ifndef LOGLEVEL +#define LOGLEVEL LOGINFO +#endif + +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Exported_types + * @{ + */ +#if defined (__LOG_TRACE_IO_) +extern char system_log_buf[SYSTEM_TRACE_BUF_SZ]; /*!< buffer for debug traces */ +#endif /* __LOG_TRACE_IO_ */ +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Exported_Macros + * @{ + */ +#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) +#if LOGLEVEL >= LOGDBG +#define log_dbg(fmt, ...) printf("[%05ld.%03ld][DBG ]" fmt, HAL_GetTick()/1000, HAL_GetTick() % 1000, ##__VA_ARGS__) +#else +#define log_dbg(fmt, ...) +#endif +#if LOGLEVEL >= LOGINFO +#define log_info(fmt, ...) printf("[%05ld.%03ld][INFO ]" fmt, HAL_GetTick()/1000, HAL_GetTick() % 1000, ##__VA_ARGS__) +#else +#define log_info(fmt, ...) +#endif +#if LOGLEVEL >= LOGWARN +#define log_warn(fmt, ...) printf("[%05ld.%03ld][WARN ]" fmt, HAL_GetTick()/1000, HAL_GetTick() % 1000, ##__VA_ARGS__) +#else +#define log_warn(fmt, ...) +#endif +#if LOGLEVEL >= LOGERR +#define log_err(fmt, ...) printf("[%05ld.%03ld][ERR ]" fmt, HAL_GetTick()/1000, HAL_GetTick() % 1000, ##__VA_ARGS__) +#else +#define log_err(fmt, ...) +#endif +#else +#define log_dbg(fmt, ...) +#define log_info(fmt, ...) +#define log_warn(fmt, ...) +#define log_err(fmt, ...) +#endif /* __LOG_TRACE_IO_ */ +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Exported_Functions + * @{ + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /*__LOG_STM32MP1XX_H */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/rsc_table.h b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/rsc_table.h new file mode 100644 index 0000000000..aaf818355c --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Inc/rsc_table.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + */ + +/* This file populates resource table for BM remote + * for use by the Linux Master */ + +#ifndef RSC_TABLE_H_ +#define RSC_TABLE_H_ + +#include "openamp/open_amp.h" +#include "openamp_conf.h" + +/* Place resource table in special ELF section */ +//#define __section_t(S) __attribute__((__section__(#S))) +//#define __resource __section_t(.resource_table) + +/* Resource table for the given remote */ +struct shared_resource_table { + unsigned int version; + unsigned int num; + unsigned int reserved[2]; + unsigned int offset[NUM_RESOURCE_ENTRIES]; + /* text carveout entry */ + + /* rpmsg vdev entry */ + struct fw_rsc_vdev vdev; + struct fw_rsc_vdev_vring vring0; + struct fw_rsc_vdev_vring vring1; + struct fw_rsc_trace cm_trace; +}; + +void resource_table_init(int RPMsgRole, void **table_ptr, int *length); + +#endif /* RSC_TABLE_H_ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/mbox_ipcc.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/mbox_ipcc.c new file mode 100644 index 0000000000..475f3a22cf --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/mbox_ipcc.c @@ -0,0 +1,182 @@ +/** + ****************************************************************************** + * @file mbox_ipcc.c + * @author MCD Application Team + * @brief This file provides code for the configuration + * of the mailbox_ipcc_if.c MiddleWare. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* + * Channel direction and usage: + * + * ======== <-- new msg ---=============--------<------ ======= + * || || || CHANNEL 1 || || || + * || A7 || ------->-------=============--- buf free--> || M4 || + * || || || || + * ||master|| <-- buf free---=============--------<------ ||slave|| + * || || || CHANNEL 2 || || || + * ======== ------->-------=============----new msg --> ======= + */ + +/* Includes ------------------------------------------------------------------*/ +#include "openamp/open_amp.h" +#include "stm32mp1xx_hal.h" +#include "openamp_conf.h" + +/* Within 'USER CODE' section, code will be kept by default at each generation */ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* Private define ------------------------------------------------------------*/ +#define MASTER_CPU_ID 0 +#define REMOTE_CPU_ID 1 +#define IPCC_CPU_A7 MASTER_CPU_ID +#define IPCC_CPU_M4 REMOTE_CPU_ID +#define RX_NO_MSG 0 +#define RX_NEW_MSG 1 +#define RX_BUF_FREE 2 + +/* Private variables ---------------------------------------------------------*/ +extern IPCC_HandleTypeDef hipcc; +int msg_received_ch1 = RX_NO_MSG; +int msg_received_ch2 = RX_NO_MSG; +uint32_t vring0_id = 0; /* used for channel 1 */ +uint32_t vring1_id = 1; /* used for channel 2 */ + +/* Private function prototypes -----------------------------------------------*/ +void IPCC_channel1_callback(IPCC_HandleTypeDef * hipcc, uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir); +void IPCC_channel2_callback(IPCC_HandleTypeDef * hipcc, uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir); + +/** + * @brief Initialize MAILBOX with IPCC peripheral + * @param None + * @retval : Operation result + */ +int MAILBOX_Init(void) +{ + + if (HAL_IPCC_ActivateNotification(&hipcc, IPCC_CHANNEL_1, IPCC_CHANNEL_DIR_RX, + IPCC_channel1_callback) != HAL_OK) { + OPENAMP_log_err("%s: ch_1 RX fail\n", __func__); + return -1; + } + + if (HAL_IPCC_ActivateNotification(&hipcc, IPCC_CHANNEL_2, IPCC_CHANNEL_DIR_RX, + IPCC_channel2_callback) != HAL_OK) { + OPENAMP_log_err("%s: ch_2 RX fail\n", __func__); + return -1; + } + + return 0; +} + +/** + * @brief Initialize MAILBOX with IPCC peripheral + * @param virtio device + * @retval : Operation result + */ +int MAILBOX_Poll(struct virtio_device *vdev) +{ + /* If we got an interrupt, ask for the corresponding virtqueue processing */ + + if (msg_received_ch1 == RX_BUF_FREE) { + OPENAMP_log_dbg("Running virt0 (ch_1 buf free)\r\n"); + rproc_virtio_notified(vdev, VRING0_ID); + msg_received_ch1 = RX_NO_MSG; + return 0; + } + + if (msg_received_ch2 == RX_NEW_MSG) { + OPENAMP_log_dbg("Running virt1 (ch_2 new msg)\r\n"); + rproc_virtio_notified(vdev, VRING1_ID); + msg_received_ch2 = RX_NO_MSG; + + /* The OpenAMP framework does not notify for free buf: do it here */ + rproc_virtio_notified(NULL, VRING1_ID); + return 0; + } + + return -1; +} + +/** + * @brief Callback function called by OpenAMP MW to notify message processing + * @param VRING id + * @retval Operation result + */ +int MAILBOX_Notify(void *priv, uint32_t id) +{ + uint32_t channel; + (void)priv; + + /* Called after virtqueue processing: time to inform the remote */ + if (id == VRING0_ID) { + channel = IPCC_CHANNEL_1; + OPENAMP_log_dbg("Send msg on ch_1\r\n"); + } + else if (id == VRING1_ID) { + /* Note: the OpenAMP framework never notifies this */ + channel = IPCC_CHANNEL_2; + OPENAMP_log_dbg("Send 'buff free' on ch_2\r\n"); + } + else { + OPENAMP_log_err("invalid vring (%d)\r\n", (int)id); + return -1; + } + + /* Check that the channel is free (otherwise wait until it is) */ + if (HAL_IPCC_GetChannelStatus(&hipcc, channel, IPCC_CHANNEL_DIR_TX) == IPCC_CHANNEL_STATUS_OCCUPIED) { + OPENAMP_log_dbg("Waiting for channel to be freed\r\n"); + while (HAL_IPCC_GetChannelStatus(&hipcc, channel, IPCC_CHANNEL_DIR_TX) == IPCC_CHANNEL_STATUS_OCCUPIED) + ; + } + + /* Inform A7 (either new message, or buf free) */ + HAL_IPCC_NotifyCPU(&hipcc, channel, IPCC_CHANNEL_DIR_TX); + + return 0; +} + +/* Private function ---------------------------------------------------------*/ +/* Callback from IPCC Interrupt Handler: Master Processor informs that there are some free buffers */ +void IPCC_channel1_callback(IPCC_HandleTypeDef * hipcc, + uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir) +{ + if (msg_received_ch1 != RX_NO_MSG) + OPENAMP_log_dbg("IPCC_channel1_callback: previous IRQ not treated (status = %d)\r\n", msg_received_ch1); + + msg_received_ch1 = RX_BUF_FREE; + + /* Inform A7 that we have received the 'buff free' msg */ + OPENAMP_log_dbg("Ack 'buff free' message on ch1\r\n"); + HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX); +} + +/* Callback from IPCC Interrupt Handler: new message received from Master Processor */ +void IPCC_channel2_callback(IPCC_HandleTypeDef * hipcc, + uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir) +{ + if (msg_received_ch2 != RX_NO_MSG) + OPENAMP_log_dbg("IPCC_channel2_callback: previous IRQ not treated (status = %d)\r\n", msg_received_ch2); + + msg_received_ch2 = RX_NEW_MSG; + + /* Inform A7 that we have received the new msg */ + OPENAMP_log_dbg("Ack new message on ch2\r\n"); + HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp.c new file mode 100644 index 0000000000..08ef2d4c02 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp.c @@ -0,0 +1,176 @@ +/** + ****************************************************************************** + * @file openamp.c + * @author MCD Application Team + * @brief Code for openamp applications + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "openamp.h" +#include "rsc_table.h" +#include "metal/sys.h" +#include "metal/device.h" +/* Private define ------------------------------------------------------------*/ + +#define SHM_DEVICE_NAME "STM32_SHM" + +/* Globals */ + +static struct metal_io_region *shm_io; +static struct metal_io_region *rsc_io; +static struct shared_resource_table *rsc_table; +static struct rpmsg_virtio_shm_pool shpool; +static struct rpmsg_virtio_device rvdev; + +static metal_phys_addr_t shm_physmap; + +struct metal_device shm_device = { + .name = SHM_DEVICE_NAME, + .num_regions = 2, + .regions = { + {.virt = NULL}, /* shared memory */ + {.virt = NULL}, /* rsc_table memory */ + }, + .node = { NULL }, + .irq_num = 0, + .irq_info = NULL +}; + +static int OPENAMP_shmem_init(int RPMsgRole) +{ + int status = 0; + struct metal_device *device; + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + void* rsc_tab_addr; + int rsc_size; + + metal_init(&metal_params); + + status = metal_register_generic_device(&shm_device); + if (status != 0) { + return status; + } + + status = metal_device_open("generic", SHM_DEVICE_NAME, &device); + if (status != 0) { + return status; + } + + shm_physmap = SHM_START_ADDRESS; + metal_io_init(&device->regions[0], (void *)SHM_START_ADDRESS, &shm_physmap, + SHM_SIZE, -1, 0, NULL); + + shm_io = metal_device_io_region(device, 0); + if (shm_io == NULL) { + return -1; + } + + /* Initialize resources table variables */ + resource_table_init(RPMsgRole, &rsc_tab_addr, &rsc_size); + rsc_table = (struct shared_resource_table *)rsc_tab_addr; + if (!rsc_table) + { + return -1; + } + + metal_io_init(&device->regions[1], rsc_table, + (metal_phys_addr_t *)rsc_table, rsc_size, -1U, 0, NULL); + + rsc_io = metal_device_io_region(device, 1); + if (rsc_io == NULL) { + return -1; + } + + return 0; +} + +int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb) +{ + struct fw_rsc_vdev_vring *vring_rsc; + struct virtio_device *vdev; + int status = 0; + + MAILBOX_Init(); + + /* Libmetal Initilalization */ + status = OPENAMP_shmem_init(RPMsgRole); + if(status) + { + return status; + } + + vdev = rproc_virtio_create_vdev(RPMsgRole, VDEV_ID, &rsc_table->vdev, + rsc_io, NULL, MAILBOX_Notify, NULL); + if (vdev == NULL) + { + return -1; + } + + rproc_virtio_wait_remote_ready(vdev); + vring_rsc = &rsc_table->vring0; + status = rproc_virtio_init_vring(vdev, 0, vring_rsc->notifyid, + (void *)vring_rsc->da, shm_io, + vring_rsc->num, vring_rsc->align); + if (status != 0) + { + return status; + } + vring_rsc = &rsc_table->vring1; + status = rproc_virtio_init_vring(vdev, 1, vring_rsc->notifyid, + (void *)vring_rsc->da, shm_io, + vring_rsc->num, vring_rsc->align); + if (status != 0) + { + return status; + } + + rpmsg_virtio_init_shm_pool(&shpool, (void *)VRING_BUFF_ADDRESS, + (size_t)SHM_SIZE); + rpmsg_init_vdev(&rvdev, vdev, ns_bind_cb, shm_io, &shpool); + + return 0; +} + +void OPENAMP_DeInit() +{ + rpmsg_deinit_vdev(&rvdev); + + metal_finish(); +} + +void OPENAMP_init_ept(struct rpmsg_endpoint *ept) +{ + rpmsg_init_ept(ept, "", RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, NULL, NULL); +} + +int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, + uint32_t dest, rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb unbind_cb) +{ + return rpmsg_create_ept(ept, &rvdev.rdev, name, RPMSG_ADDR_ANY, dest, cb, + unbind_cb); +} + +void OPENAMP_check_for_message(void) +{ + MAILBOX_Poll(rvdev.vdev); +} + +void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept) +{ + while(!is_rpmsg_ept_ready(rp_ept)) + MAILBOX_Poll(rvdev.vdev); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp_log.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp_log.c new file mode 100644 index 0000000000..7ce1ba6a2a --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/openamp_log.c @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * @file log.c + * @author MCD Application Team + * @brief Ressource table + * + * This file provides services for logging + * + ****************************************************************************** + * + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + * + ****************************************************************************** + */ +/** @addtogroup LOG + * @{ + */ + +/** @addtogroup STM32MP1xx_log + * @{ + */ + +/** @addtogroup STM32MP1xx_Log_Private_Includes + * @{ + */ +#include "openamp_log.h" +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32MP1xx_Log_Private_Defines + * @{ + */ + +/** + * @} + */ + +#if defined (__LOG_TRACE_IO_) +char system_log_buf[SYSTEM_TRACE_BUF_SZ]; + +__weak void log_buff(int ch) +{ + /* Place your implementation of fputc here */ + /* e.g. write a character to the USART1 and Loop until the end of transmission */ + static int offset = 0; + + if (offset + 1 >= SYSTEM_TRACE_BUF_SZ) + offset = 0; + + system_log_buf[offset] = ch; + system_log_buf[offset++ + 1] = '\0'; +} + +#endif + +#if defined ( __CC_ARM) || (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) +#define PUTCHAR_PROTOTYPE int stdout_putchar(int ch) +#elif __GNUC__ +/* With GCC/RAISONANCE, small log_info (option LD Linker->Libraries->Small log_info + set to 'Yes') calls __io_putchar() */ +#define PUTCHAR_PROTOTYPE int __attribute__(( weak )) __io_putchar(int ch) +#else +#define PUTCHAR_PROTOTYPE int __attribute__(( weak )) fputc(int ch, FILE *f) +#endif /* __GNUC__ */ + +#if defined (__LOG_UART_IO_) || defined (__LOG_TRACE_IO_) +PUTCHAR_PROTOTYPE +{ + /* Place your implementation of fputc here */ + /* e.g. write a character to the USART1 and Loop until the end of transmission */ +#if defined (__LOG_UART_IO_) +extern UART_HandleTypeDef huart; + HAL_UART_Transmit(&huart, (uint8_t *)&ch, 1, HAL_MAX_DELAY); +#endif +#if defined (__LOG_TRACE_IO_) + log_buff(ch); +#endif + return ch; +} +#else +/* No printf output */ +#endif + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/rsc_table.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/rsc_table.c new file mode 100644 index 0000000000..581636ddca --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/rsc_table.c @@ -0,0 +1,174 @@ +/** + ****************************************************************************** + * @file rsc_table.c + * @author MCD Application Team + * @brief Ressource table + * + * This file provides a default resource table requested by remote proc to + * load the elf file. It also allows to add debug trace using a shared buffer. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** @addtogroup RSC_TABLE + * @{ + */ + +/** @addtogroup resource_table + * @{ + */ + +/** @addtogroup resource_table_Private_Includes + * @{ + */ + +#if defined(__ICCARM__) || defined (__CC_ARM) +#include /* needed for offsetof definition*/ +#endif +#include "rsc_table.h" +#include "openamp/open_amp.h" + +/** + * @} + */ + +/** @addtogroup resource_table_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup resource_table_Private_Defines + * @{ + */ + +/* Place resource table in special ELF section */ +#if defined(__GNUC__) +#define __section_t(S) __attribute__((__section__(#S))) +#define __resource __section_t(.resource_table) +#endif + +#if defined (LINUX_RPROC_MASTER) + #ifdef VIRTIO_MASTER_ONLY + #define CONST + #else + #define CONST const + #endif +#else + #define CONST +#endif + +#define RPMSG_IPU_C0_FEATURES 1 +#define VRING_COUNT 2 + +/* VirtIO rpmsg device id */ +#define VIRTIO_ID_RPMSG_ 7 + +#if defined (__LOG_TRACE_IO_) +extern char system_log_buf[]; +#endif + +#if defined(__GNUC__) +#if !defined (__CC_ARM) && !defined (LINUX_RPROC_MASTER) + +/* Since GCC is not initializing the resource_table at startup, it is declared as volatile to avoid compiler optimization + * for the CM4 (see resource_table_init() below) + */ +volatile struct shared_resource_table __resource __attribute__((used)) resource_table; +#else +CONST struct shared_resource_table __resource __attribute__((used)) resource_table = { +#endif +#elif defined(__ICCARM__) +__root CONST struct shared_resource_table resource_table @ ".resource_table" = { +#endif + +#if defined(__ICCARM__) || defined (__CC_ARM) || defined (LINUX_RPROC_MASTER) + .version = 1, +#if defined (__LOG_TRACE_IO_) + .num = 2, +#else + .num = 1, +#endif + .reserved = {0, 0}, + .offset = { + offsetof(struct shared_resource_table, vdev), + offsetof(struct shared_resource_table, cm_trace), + }, + + /* Virtio device entry */ + .vdev= { + RSC_VDEV, VIRTIO_ID_RPMSG_, 0, RPMSG_IPU_C0_FEATURES, 0, 0, 0, + VRING_COUNT, {0, 0}, + }, + + /* Vring rsc entry - part of vdev rsc entry */ + .vring0 = {VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING0_ID, 0}, + .vring1 = {VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING1_ID, 0}, + +#if defined (__LOG_TRACE_IO_) + .cm_trace = { + RSC_TRACE, + (uint32_t)system_log_buf, SYSTEM_TRACE_BUF_SZ, 0, "cm4_log", + }, +#endif +} ; +#endif + +void resource_table_init(int RPMsgRole, void **table_ptr, int *length) +{ + +#if !defined (LINUX_RPROC_MASTER) +#if defined (__GNUC__) && ! defined (__CC_ARM) +#ifdef VIRTIO_MASTER_ONLY + + /* + * Currently the GCC linker doesn't initialize the resource_table global variable at startup + * it is done here by the master application. + */ + memset(&resource_table, '\0', sizeof(struct shared_resource_table)); + resource_table.num = 1; + resource_table.version = 1; + resource_table.offset[0] = offsetof(struct shared_resource_table, vdev); + + resource_table.vring0.da = VRING_TX_ADDRESS; + resource_table.vring0.align = VRING_ALIGNMENT; + resource_table.vring0.num = VRING_NUM_BUFFS; + resource_table.vring0.notifyid = VRING0_ID; + + resource_table.vring1.da = VRING_RX_ADDRESS; + resource_table.vring1.align = VRING_ALIGNMENT; + resource_table.vring1.num = VRING_NUM_BUFFS; + resource_table.vring1.notifyid = VRING1_ID; + + resource_table.vdev.type = RSC_VDEV; + resource_table.vdev.id = VIRTIO_ID_RPMSG_; + resource_table.vdev.num_of_vrings=VRING_COUNT; + resource_table.vdev.dfeatures = RPMSG_IPU_C0_FEATURES; +#else + + /* For the slave application let's wait until the resource_table is correctly initialized */ + while(resource_table.vring1.da != VRING_RX_ADDRESS) + { + + } +#endif +#endif +#endif + + (void)RPMsgRole; + *length = sizeof(resource_table); + *table_ptr = (void *)&resource_table; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c index 9361ca70b1..5e6a4a3d34 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c +++ b/bsp/stm32/stm32mp157a-st-ev1/board/CubeMX_Config/CM4/Src/stm32mp1xx_hal_msp.c @@ -73,7 +73,14 @@ void HAL_MspInit(void) /* System interrupt init*/ /* USER CODE BEGIN MspInit 1 */ - +#if !defined(BSP_USING_OPENAMP) + __HAL_RCC_SYSRAM_CLK_ENABLE(); + __HAL_RCC_RETRAM_CLK_ENABLE(); +#endif + + HAL_NVIC_SetPriority(RCC_WAKEUP_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(RCC_WAKEUP_IRQn); + __HAL_RCC_ENABLE_IT(RCC_IT_WKUP); /* USER CODE END MspInit 1 */ } diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig b/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig index 10a58a6b8b..e52a1601fe 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig +++ b/bsp/stm32/stm32mp157a-st-ev1/board/Kconfig @@ -28,6 +28,11 @@ menu "Onboard Peripheral Drivers" select RT_MTD_NAND_DEBUG default n + config BSP_USING_OPENAMP + bool "Enable OpenAMP" + select RT_USING_OPENAMP + default n + endmenu menu "On-chip Peripheral Drivers" diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/SConscript b/bsp/stm32/stm32mp157a-st-ev1/board/SConscript index 29b406616d..15e6070c81 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/SConscript +++ b/bsp/stm32/stm32mp157a-st-ev1/board/SConscript @@ -19,10 +19,32 @@ if GetDepend(['BSP_USING_PMIC']): if GetDepend(['BSP_USING_NAND']): src += Glob('ports/drv_nand.c') +if GetDepend(['BSP_USING_OPENAMP']): + src += Glob('CubeMX_Config/CM4/Src/ipcc.c') + src += Glob('CubeMX_Config/CM4/Src/openamp.c') + src += Glob('CubeMX_Config/CM4/Src/openamp_log.c') + src += Glob('CubeMX_Config/CM4/Src/mbox_ipcc.c') + src += Glob('CubeMX_Config/CM4/Src/rsc_table.c') + src += Glob('ports/OpenAMP/libmetal/lib/*.c') + src += Glob('ports/OpenAMP/libmetal/lib/system/generic/*.c') + src += Glob('ports/OpenAMP/libmetal/lib/system/generic/cortexm/*.c') + src += Glob('ports/OpenAMP/open-amp/lib/rpmsg/*.c') + src += Glob('ports/OpenAMP/open-amp/lib/remoteproc/*.c') + src += Glob('ports/OpenAMP/open-amp/lib/virtio/*.c') + src += Glob('ports/OpenAMP/virtual_driver/*.c') + src += Glob('ports/OpenAMP/drv_openamp.c') + path = [cwd] path += [cwd + '/CubeMX_Config/CM4/Inc'] path += [cwd + '/ports'] +if GetDepend(['BSP_USING_OPENAMP']): + path += [cwd + '/ports/OpenAMP'] + path += [cwd + '/ports/OpenAMP/open-amp/lib/include'] + path += [cwd + '/ports/OpenAMP/libmetal/lib/include'] + path += [cwd + '/ports/OpenAMP/virtual_driver'] + path += [cwd + '/CubeMX_Config/CM4/Inc'] + startup_path_prefix = SDK_LIB if rtconfig.CROSS_TOOL == 'gcc': @@ -34,7 +56,7 @@ elif rtconfig.CROSS_TOOL == 'iar': src = list(set(src)) -CPPDEFINES = ['CORE_CM4', 'STM32MP157Axx', 'USE_HAL_DRIVER'] +CPPDEFINES = ['CORE_CM4','NO_ATOMIC_64_SUPPORT','METAL_INTERNAL','METAL_MAX_DEVICE_REGIONS=2','VIRTIO_SLAVE_ONLY','STM32MP157Axx','__LOG_TRACE_IO_'] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path, CPPDEFINES = CPPDEFINES) diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/board.h b/bsp/stm32/stm32mp157a-st-ev1/board/board.h index b23b83ee30..84e097714a 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/board.h +++ b/bsp/stm32/stm32mp157a-st-ev1/board/board.h @@ -22,25 +22,25 @@ extern "C" { #endif -#define STM32_FLASH_START_ADRESS ((uint32_t)0x10000000) -#define STM32_FLASH_SIZE (256 * 1024) +#define STM32_FLASH_START_ADRESS ((uint32_t)0x10000000) +#if defined(BSP_USING_OPENAMP) +#define STM32_FLASH_SIZE (64 * 1024) +#else +#define STM32_FLASH_SIZE (256 * 1024) +#endif #define STM32_FLASH_END_ADDRESS ((uint32_t)(STM32_FLASH_START_ADRESS + STM32_FLASH_SIZE)) -#define STM32_SRAM_SIZE (128) -#define STM32_SRAM_END ((uint32_t)0x10040000 + (STM32_SRAM_SIZE * 1024)) - -#if defined(__CC_ARM) || defined(__CLANG_ARM) -extern int Image$$RW_IRAM1$$ZI$$Limit; -#define HEAP_BEGIN (&Image$$RW_IRAM1$$ZI$$Limit) -#elif __ICCARM__ -#pragma section="CSTACK" -#define HEAP_BEGIN (__segment_end("CSTACK")) + +#if defined(BSP_USING_OPENAMP) +#define STM32_SRAM_BEGIN (uint32_t)0x10020000 #else -extern int __bss_end__; -#define HEAP_BEGIN (0x10040000 + 64 * 1024) +#define STM32_SRAM_BEGIN (uint32_t)0x2FFF0000 #endif +#define STM32_SRAM_SIZE (64) +#define STM32_SRAM_END (STM32_SRAM_BEGIN + (STM32_SRAM_SIZE * 1024)) -#define HEAP_END STM32_SRAM_END +#define HEAP_BEGIN STM32_SRAM_BEGIN +#define HEAP_END STM32_SRAM_END void SystemClock_Config(void); diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/linker_scripts/link.icf b/bsp/stm32/stm32mp157a-st-ev1/board/linker_scripts/link.icf index 9aa4aad24e..ee4ff6ade6 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/board/linker_scripts/link.icf +++ b/bsp/stm32/stm32mp157a-st-ev1/board/linker_scripts/link.icf @@ -4,33 +4,42 @@ /*-Specials-*/ define symbol __ICFEDIT_intvec_start__ = 0x00000000; /*-Memory Regions-*/ -define symbol __ICFEDIT_region_ROM_start__ = 0x10000000; -define symbol __ICFEDIT_region_ROM_end__ = 0x1003FFFF; -define symbol __ICFEDIT_region_RAM_start__ = 0x10050000; -define symbol __ICFEDIT_region_RAM_end__ = 0x1005FFFF; - +define symbol __ICFEDIT_region_text_start__ = 0x10000000; +define symbol __ICFEDIT_region_text_end__ = 0x1001FFFF; +define symbol __ICFEDIT_region_data_start__ = 0x10030000; +define symbol __ICFEDIT_region_data_end__ = 0x1003FFFF; /*-Sizes-*/ -define symbol __ICFEDIT_size_cstack__ = 0x0400; -define symbol __ICFEDIT_size_heap__ = 0x0000; +define symbol __ICFEDIT_size_cstack__ = 0x400; +define symbol __ICFEDIT_size_heap__ = 0x000; /**** End of ICF editor section. ###ICF###*/ + define memory mem with size = 4G; -define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; -define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; +define region text_region = mem:[from __ICFEDIT_region_text_start__ to __ICFEDIT_region_text_end__]; +define region data_region = mem:[from __ICFEDIT_region_data_start__ to __ICFEDIT_region_data_end__]; -define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; - -initialize by copy { readwrite }; -do not initialize { section .noinit }; +keep { section .resource_table }; +".resource_table" : place in data_region {section .resource_table}; /* Create region for OPENAMP */ /* !!! These 4 lines can be commented if OPENAMP is not used !!!*/ -define symbol __OPENAMP_region_start__ = 0x10040000; +define symbol __OPENAMP_region_start__ = 0x10040000; define symbol __OPENAMP_region_size__ = 0x8000; export symbol __OPENAMP_region_start__; export symbol __OPENAMP_region_size__; -place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; +define symbol __SDMMC_region_start__ = 0x10048000; +define symbol __SDMMC_region_size__ = 0x1FFFF; +export symbol __SDMMC_region_start__; +export symbol __SDMMC_region_size__; -place in ROM_region { readonly }; -place in RAM_region { readwrite, last block CSTACK}; \ No newline at end of file +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit}; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; +place in text_region { readonly }; +place in data_region { readwrite, + block CSTACK, block HEAP}; diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.c new file mode 100644 index 0000000000..2705f068a3 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-06-24 thread-liu first version + */ + +#include + +#ifdef BSP_USING_OPENAMP + +#include +#include +#include +#include + +//#define DRV_DEBUG +#define LOG_TAG "drv.openamp" +#include + +IPCC_HandleTypeDef hipcc; +static VIRT_UART_HandleTypeDef huart0; + +static rt_uint8_t rx_buffer[MAX_BUFFER_SIZE]; +static rt_uint8_t tx_buffer[MAX_BUFFER_SIZE]; + +struct rthw_openamp +{ + struct rt_device parent; + struct rt_openamp serial; + struct rt_semaphore sema; +}; +static struct rthw_openamp dev_openamp; + +void IPCC_RX1_IRQHandler(void) +{ + rt_interrupt_enter(); + + HAL_IPCC_RX_IRQHandler(&hipcc); + + rt_interrupt_leave(); +} + +void IPCC_TX1_IRQHandler(void) +{ + rt_interrupt_enter(); + + HAL_IPCC_TX_IRQHandler(&hipcc); + + rt_interrupt_leave(); +} + +void VIRT_UART0_RxCpltCallback(VIRT_UART_HandleTypeDef *huart) +{ + rt_uint16_t rx_size = 0, i = 0; + rt_size_t count, size, offset; + rt_uint8_t *buf = RT_NULL; + + struct rthw_openamp *device; + device = (struct rthw_openamp *)rt_device_find("openamp"); + RT_ASSERT(device != RT_NULL); + + buf = device->serial.rbuf; + count = device->serial.rbuf_count; + size = device->serial.rbuf_size; + offset = device->serial.rbuf_start + count; + + rt_sem_take(&device->sema, RT_WAITING_FOREVER); + + rx_size = (huart->RxXferSize < MAX_BUFFER_SIZE) ? huart->RxXferSize : MAX_BUFFER_SIZE - 1; + + if (count < size) + { + if (offset >= size) + { + offset -= size; + } + + for (i = 0; i < rx_size; i++) + { + buf[offset++] = huart->pRxBuffPtr[i]; + count++; + } + } + + device->serial.rbuf_count = count; + + rt_sem_release(&device->sema); +} + +static rt_err_t _init(struct rt_device *dev) +{ + struct rthw_openamp *device; + device = (struct rthw_openamp *)dev; + RT_ASSERT(device != RT_NULL); + + device->serial.rbuf_start = 0; + device->serial.rbuf_count = 0; + device->serial.tbuf_start = 0; + device->serial.tbuf_count = 0; + device->serial.rbuf_size = MAX_BUFFER_SIZE; + device->serial.tbuf_size = MAX_BUFFER_SIZE; + device->serial.rbuf = rx_buffer; + device->serial.tbuf = tx_buffer; + + if (rt_sem_init(&device->sema, "openamplock", 1, RT_IPC_FLAG_FIFO) != RT_EOK) + { + return RT_ERROR; + } + + return RT_EOK; +} + +static rt_size_t _read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_size_t count, rbsize, offset; + rt_uint8_t *buf = RT_NULL; + rt_uint8_t *pBuffer = RT_NULL; + rt_uint16_t i = 0; + + struct rthw_openamp *device; + device = (struct rthw_openamp *)dev; + RT_ASSERT(device != RT_NULL); + + pBuffer = (unsigned char*)buffer; + count = device->serial.rbuf_count; + buf = device->serial.rbuf; + + if (count == 0) + { + return -RT_ERROR; + } + + rt_sem_take(&device->sema, RT_WAITING_FOREVER); + + if (count >= size) + { + count = size; + } + + offset = device->serial.rbuf_start; + rbsize = device->serial.rbuf_size; + + for (i = 0; i < count; i++) + { + *pBuffer++ = buf[offset++]; + if (offset > rbsize) + { + offset = 0; + } + } + + device->serial.rbuf_start = offset; + device->serial.rbuf_count -= count; + + rt_sem_release(&device->sema); + + return count; +} + +static rt_size_t _write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_err_t result = VIRT_UART_OK; + + struct rthw_openamp *device; + device = (struct rthw_openamp *)dev; + RT_ASSERT(device != RT_NULL); + + rt_sem_take(&device->sema, RT_WAITING_FOREVER); + result = VIRT_UART_Transmit(&huart0, (uint8_t *)buffer, size); + rt_sem_release(&device->sema); + + if (result != VIRT_UART_OK) + { + return -RT_ERROR; + } + + return size; +} + +static rt_err_t rt_hw_openamp_register(struct rthw_openamp *openamp, const char *name, rt_uint32_t flag, void *data) +{ + struct rt_device *device; + RT_ASSERT(openamp != RT_NULL); + + device = &(openamp->parent); + + device->type = RT_Device_Class_Char; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + + device->init = _init; + device->open = RT_NULL; + device->close = RT_NULL; + device->read = _read; + device->write = _write; + device->control = RT_NULL; + device->user_data = data; + + /* register a character device */ + return rt_device_register(device, name, flag); +} + +static int openamp_init(void) +{ + extern int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb); + + /* IPCC init */ + hipcc.Instance = IPCC; + if (HAL_IPCC_Init(&hipcc) != HAL_OK) + { + return RT_ERROR; + } + /* openamp slave device */ + MX_OPENAMP_Init(RPMSG_REMOTE, NULL); + + if (VIRT_UART_Init(&huart0) != VIRT_UART_OK) + { + return RT_ERROR; + } + if (VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID, VIRT_UART0_RxCpltCallback) != VIRT_UART_OK) + { + return RT_ERROR; + } + + return RT_EOK; +} + +int rt_hw_openamp_init(void) +{ + openamp_init(); + + rt_hw_openamp_register(&dev_openamp, "openamp", 0, NULL); + + rt_console_set_device("openamp"); + + return RT_EOK; +} +INIT_PREV_EXPORT(rt_hw_openamp_init); + +static void openamp_thread_entry(void *parameter) +{ + rt_size_t size = 0; + struct rthw_openamp *device = RT_NULL; + + device = (struct rthw_openamp *)rt_device_find("openamp"); + RT_ASSERT(device != RT_NULL); + + for (;;) + { + OPENAMP_check_for_message(); + + size = device->serial.rbuf_count; + if (size > 0) + { + if (device->parent.rx_indicate != RT_NULL) + { + device->parent.rx_indicate(&device->parent, size); + } + } + + rt_thread_mdelay(1); + } +} + +static int creat_openamp_thread(void) +{ + rt_thread_t tid = RT_NULL; + + tid = rt_thread_create("OpenAMP", + openamp_thread_entry, + RT_NULL, + OPENAMP_THREAD_STACK_SIZE, + OPENAMP_THREAD_PRIORITY, + OPENAMP_THREAD_TIMESLICE); + + if (tid == RT_NULL) + { + LOG_E("openamp thread create failed!"); + return RT_ERROR; + } + + rt_thread_startup(tid); + + return RT_EOK; +} +INIT_APP_EXPORT(creat_openamp_thread); + +#endif diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.h new file mode 100644 index 0000000000..df1533b38b --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/drv_openamp.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-06-24 thread-liu first version + */ + +#ifndef __DRV_OPENAMP_H__ +#define __DRV_OPENAMP_H__ + +#include "board.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct rt_openamp +{ + rt_uint8_t *rbuf; + rt_uint8_t *tbuf; + volatile rt_uint16_t rbuf_size; + volatile rt_uint16_t tbuf_size; + volatile rt_uint16_t rbuf_start; + volatile rt_uint16_t rbuf_count; + volatile rt_uint16_t tbuf_start; + volatile rt_uint16_t tbuf_count; +}; + +#define OPENAMP_THREAD_STACK_SIZE 512 +#define OPENAMP_THREAD_PRIORITY 5 +#define OPENAMP_THREAD_TIMESLICE 10 + +#define MAX_BUFFER_SIZE 256 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/dma.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/dma.c new file mode 100644 index 0000000000..baeb21bd2a --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/dma.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +int metal_dma_map(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out) +{ + int nents_out; + + if (!dev || !sg_in || !sg_out) + return -EINVAL; + if (!dev->bus->ops.dev_dma_map) + return -ENODEV; + + /* memory barrier */ + if (dir == METAL_DMA_DEV_R) + /* If it is device read, apply memory write fence. */ + atomic_thread_fence(memory_order_release); + else + /* If it is device write or device r/w, + apply memory r/w fence. */ + atomic_thread_fence(memory_order_acq_rel); + nents_out = dev->bus->ops.dev_dma_map(dev->bus, + dev, dir, sg_in, nents_in, sg_out); + return nents_out; +} + +void metal_dma_unmap(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg, + int nents) +{ + /* memory barrier */ + if (dir == METAL_DMA_DEV_R) + /* If it is device read, apply memory write fence. */ + atomic_thread_fence(memory_order_release); + else + /* If it is device write or device r/w, + apply memory r/w fence. */ + atomic_thread_fence(memory_order_acq_rel); + + if (!dev || !dev->bus->ops.dev_dma_unmap || !sg) + return; + dev->bus->ops.dev_dma_unmap(dev->bus, + dev, dir, sg, nents); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/alloc.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/alloc.h new file mode 100644 index 0000000000..0e2d070c9b --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/alloc.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file alloc.h + * @brief Memory allocation handling primitives for libmetal. + */ + +#ifndef __METAL_ALLOC__H__ +#define __METAL_ALLOC__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Memory Allocation Interfaces + * @{ */ + +/** + * @brief allocate requested memory size + * return a pointer to the allocated memory + * + * @param[in] size size in byte of requested memory + * @return memory pointer, or 0 if it failed to allocate + */ +static inline void *metal_allocate_memory(unsigned int size); + +/** + * @brief free the memory previously allocated + * + * @param[in] ptr pointer to memory + */ +static inline void metal_free_memory(void *ptr); + +#include + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_ALLOC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/assert.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/assert.h new file mode 100644 index 0000000000..4476b641ae --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/assert.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file assert.h + * @brief Assertion support. + */ + +#ifndef __METAL_ASSERT__H__ +#define __METAL_ASSERT__H__ + +#include + +/** + * @brief Assertion macro. + * @param cond Condition to test. + */ +#define metal_assert(cond) metal_sys_assert(cond) + +#endif /* __METAL_ASSERT_H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/atomic.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/atomic.h new file mode 100644 index 0000000000..f80c2971cd --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/atomic.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file atomic.h + * @brief Atomic primitives for libmetal. + */ + +#ifndef __METAL_ATOMIC__H__ +#define __METAL_ATOMIC__H__ + +#include + +#if defined(HAVE_STDATOMIC_H) && !defined (__CC_ARM) && \ + !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) + +# include + +#ifndef atomic_thread_fence +#define atomic_thread_fence(order) +#endif + +#elif defined(__GNUC__) +# include +#else +# include +#endif + +#endif /* __METAL_ATOMIC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cache.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cache.h new file mode 100644 index 0000000000..31a94abe2b --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cache.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cache.h + * @brief CACHE operation primitives for libmetal. + */ + +#ifndef __METAL_CACHE__H__ +#define __METAL_CACHE__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup cache CACHE Interfaces + * @{ */ + +/** + * @brief flush specified data cache + * + * @param[in] addr start memory logical address + * @param[in] len length of memory + * If addr is NULL, and len is 0, + * It will flush the whole data cache. + */ +static inline void metal_cache_flush(void *addr, unsigned int len) +{ + __metal_cache_flush(addr, len); +} + +/** + * @brief invalidate specified data cache + * + * @param[in] addr start memory logical address + * @param[in] len length of memory + * If addr is NULL, and len is 0, + * It will invalidate the whole data cache. + */ +static inline void metal_cache_invalidate(void *addr, unsigned int len) +{ + __metal_cache_invalidate(addr, len); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_CACHE__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler.h new file mode 100644 index 0000000000..c581d4dc4f --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file compiler.h + * @brief Compiler specific primitives for libmetal. + */ + +#ifndef __METAL_COMPILER__H__ +#define __METAL_COMPILER__H__ + +#if defined(__GNUC__) +# include +#elif defined(__ICCARM__) +# include +#elif defined (__CC_ARM) +# error "MDK-ARM ARMCC compiler requires the GNU extentions to work correctly" +#else +# error "Missing compiler support" +#endif + +#endif /* __METAL_COMPILER__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/atomic.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/atomic.h new file mode 100644 index 0000000000..9d046785c8 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/atomic.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file gcc/atomic.h + * @brief GCC specific atomic primitives for libmetal. + */ + +#ifndef __METAL_GCC_ATOMIC__H__ +#define __METAL_GCC_ATOMIC__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int atomic_flag; +typedef char atomic_char; +typedef unsigned char atomic_uchar; +typedef short atomic_short; +typedef unsigned short atomic_ushort; +typedef int atomic_int; +typedef unsigned int atomic_uint; +typedef long atomic_long; +typedef unsigned long atomic_ulong; +typedef long long atomic_llong; +typedef unsigned long long atomic_ullong; + +#define ATOMIC_FLAG_INIT 0 +#define ATOMIC_VAR_INIT(VAL) (VAL) + +typedef enum { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst, +} memory_order; + +#define atomic_flag_test_and_set(FLAG) \ + __sync_lock_test_and_set((FLAG), 1) +#define atomic_flag_test_and_set_explicit(FLAG, MO) \ + atomic_flag_test_and_set(FLAG) +#define atomic_flag_clear(FLAG) \ + __sync_lock_release((FLAG)) +#define atomic_flag_clear_explicit(FLAG, MO) \ + atomic_flag_clear(FLAG) +#define atomic_init(OBJ, VAL) \ + do { *(OBJ) = (VAL); } while (0) +#define atomic_is_lock_free(OBJ) \ + (sizeof(*(OBJ)) <= sizeof(long)) +#define atomic_store(OBJ, VAL) \ + do { *(OBJ) = (VAL); __sync_synchronize(); } while (0) +#define atomic_store_explicit(OBJ, VAL, MO) \ + atomic_store((OBJ), (VAL)) +#define atomic_load(OBJ) \ + ({ __sync_synchronize(); *(OBJ); }) +#define atomic_load_explicit(OBJ, MO) \ + atomic_load(OBJ) +#define atomic_exchange(OBJ, DES) \ + ({ \ + typeof(OBJ) obj = (OBJ); \ + typeof(*obj) des = (DES); \ + typeof(*obj) expval; \ + typeof(*obj) oldval = atomic_load(obj); \ + do { \ + expval = oldval; \ + oldval = __sync_val_compare_and_swap( \ + obj, expval, des); \ + } while (oldval != expval); \ + oldval; \ + }) +#define atomic_exchange_explicit(OBJ, DES, MO) \ + atomic_exchange((OBJ), (DES)) +#define atomic_compare_exchange_strong(OBJ, EXP, DES) \ + ({ \ + typeof(OBJ) obj = (OBJ); \ + typeof(EXP) exp = (EXP); \ + typeof(*obj) expval = *exp; \ + typeof(*obj) oldval = __sync_val_compare_and_swap( \ + obj, expval, (DES)); \ + *exp = oldval; \ + oldval == expval; \ + }) +#define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO) \ + atomic_compare_exchange_strong((OBJ), (EXP), (DES)) +#define atomic_compare_exchange_weak(OBJ, EXP, DES) \ + atomic_compare_exchange_strong((OBJ), (EXP), (DES)) +#define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO) \ + atomic_compare_exchange_weak((OBJ), (EXP), (DES)) +#define atomic_fetch_add(OBJ, VAL) \ + __sync_fetch_and_add((OBJ), (VAL)) +#define atomic_fetch_add_explicit(OBJ, VAL, MO) \ + atomic_fetch_add((OBJ), (VAL)) +#define atomic_fetch_sub(OBJ, VAL) \ + __sync_fetch_and_sub((OBJ), (VAL)) +#define atomic_fetch_sub_explicit(OBJ, VAL, MO) \ + atomic_fetch_sub((OBJ), (VAL)) +#define atomic_fetch_or(OBJ, VAL) \ + __sync_fetch_and_or((OBJ), (VAL)) +#define atomic_fetch_or_explicit(OBJ, VAL, MO) \ + atomic_fetch_or((OBJ), (VAL)) +#define atomic_fetch_xor(OBJ, VAL) \ + __sync_fetch_and_xor((OBJ), (VAL)) +#define atomic_fetch_xor_explicit(OBJ, VAL, MO) \ + atomic_fetch_xor((OBJ), (VAL)) +#define atomic_fetch_and(OBJ, VAL) \ + __sync_fetch_and_and((OBJ), (VAL)) +#define atomic_fetch_and_explicit(OBJ, VAL, MO) \ + atomic_fetch_and((OBJ), (VAL)) +#define atomic_thread_fence(MO) \ + __sync_synchronize() +#define atomic_signal_fence(MO) \ + __sync_synchronize() + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GCC_ATOMIC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/compiler.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/compiler.h new file mode 100644 index 0000000000..fe6a11552f --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/gcc/compiler.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file gcc/compiler.h + * @brief GCC specific primitives for libmetal. + */ + +#ifndef __METAL_GCC_COMPILER__H__ +#define __METAL_GCC_COMPILER__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define restrict __restrict__ +#define metal_align(n) __attribute__((aligned(n))) +#define metal_weak __attribute__((weak)) + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GCC_COMPILER__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/compiler.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/compiler.h new file mode 100644 index 0000000000..618ba2cc16 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/compiler.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, ST Microelectronics. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file iar/compiler.h + * @brief IAR specific primitives for libmetal. + */ + +#ifndef __METAL_IAR_COMPILER__H__ +#define __METAL_IAR_COMPILER__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define restrict __restrict__ +#define metal_align(n) __attribute__((aligned(n))) +#define metal_weak __attribute__((weak)) + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IAR_COMPILER__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/errno.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/errno.h new file mode 100644 index 0000000000..d05461c073 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/iar/errno.h @@ -0,0 +1,289 @@ +/* + * * Copyright (c) 2019 STMicroelectronics. All rights reserved. + * * + * * Copyright (c) 1982, 1986, 1989, 1993 + * * The Regents of the University of California. All rights reserved. + * * Copyright (c) 1982, 1986, 1989, 1993 + * * The Regents of the University of California. All rights reserved. + * * (c) UNIX System Laboratories, Inc. + * * All or some portions of this file are derived from material licensed + * * to the University of California by American Telephone and Telegraph + * * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * * the permission of UNIX System Laboratories, Inc. + * + * * SPDX-License-Identifier: BSD-3-Clause + * */ + +#ifndef __METAL_ERRNO__H__ +#error "Include metal/errno.h instead of metal/iar/errno.h" +#endif + +#ifndef _ERRNO_H_ +#ifdef __cplusplus +extern "C" { +#endif +#define _ERRNO_H_ + + +#ifndef EPERM +#define EPERM 1 /* Not owner */ +#endif +#ifndef ENOENT +#define ENOENT 2 /* No such file or directory */ +#endif +#ifndef ESRCH +#define ESRCH 3 /* No such process */ +#endif +#ifndef EINTR +#define EINTR 4 /* Interrupted system call */ +#endif +#ifndef EIO +#define EIO 5 /* I/O error */ +#endif +#ifndef ENXIO +#define ENXIO 6 /* No such device or address */ +#endif +#ifndef E2BIG +#define E2BIG 7 /* Arg list too long */ +#endif +#ifndef ENOEXEC +#define ENOEXEC 8 /* Exec format error */ +#endif +#ifndef EBADF +#define EBADF 9 /* Bad file number */ +#endif +#ifndef ECHILD +#define ECHILD 10 /* No children */ +#endif +#ifndef EAGAIN +#define EAGAIN 11 /* No more processes */ +#endif +#ifndef ENOMEM +#define ENOMEM 12 /* Not enough space */ +#endif +#ifndef EACCES +#define EACCES 13 /* Permission denied */ +#endif +#ifndef EFAULT +#define EFAULT 14 /* Bad address */ +#endif +#ifndef EBUSY +#define EBUSY 16 /* Device or resource busy */ +#endif +#ifndef EEXIST +#define EEXIST 17 /* File exists */ +#endif +#ifndef EXDEV +#define EXDEV 18 /* Cross-device link */ +#endif +#ifndef ENODEV +#define ENODEV 19 /* No such device */ +#endif +#ifndef ENOTDIR +#define ENOTDIR 20 /* Not a directory */ +#endif +#ifndef EISDIR +#define EISDIR 21 /* Is a directory */ +#endif +#ifndef EINVAL +#define EINVAL 22 /* Invalid argument */ +#endif +#ifndef ENFILE +#define ENFILE 23 /* Too many open files in system */ +#endif +#ifndef EMFILE +#define EMFILE 24 /* File descriptor value too large */ +#endif +#ifndef ENOTTY +#define ENOTTY 25 /* Not a character device */ +#endif +#ifndef ETXTBSY +#define ETXTBSY 26 /* Text file busy */ +#endif +#ifndef EFBIG +#define EFBIG 27 /* File too large */ +#endif +#ifndef ENOSPC +#define ENOSPC 28 /* No space left on device */ +#endif +#ifndef ESPIPE +#define ESPIPE 29 /* Illegal seek */ +#endif +#ifndef EROFS +#define EROFS 30 /* Read-only file system */ +#endif +#ifndef EMLINK +#define EMLINK 31 /* Too many links */ +#endif +#ifndef EPIPE +#define EPIPE 32 /* Broken pipe */ +#endif +#ifndef EDOM +#define EDOM 33 /* Mathematics argument out of domain of function */ +#endif +#ifndef ERANGE +#define ERANGE 34 /* Result too large */ +#endif +#ifndef ENOMSG +#define ENOMSG 35 /* No message of desired type */ +#endif +#ifndef EIDRM +#define EIDRM 36 /* Identifier removed */ +#endif +#ifndef EDEADLK +#define EDEADLK 45 /* Deadlock */ +#endif +#ifndef ENOLCK +#define ENOLCK 46 /* No lock */ +#endif +#ifndef ENOSTR +#define ENOSTR 60 /* Not a stream */ +#endif +#ifndef ENODATA +#define ENODATA 61 /* No data (for no delay io) */ +#endif +#ifndef ETIME +#define ETIME 62 /* Stream ioctl timeout */ +#endif +#ifndef ENOSR +#define ENOSR 63 /* No stream resources */ +#endif +#ifndef ENOLINK +#define ENOLINK 67 /* Virtual circuit is gone */ +#endif +#ifndef EPROTO +#define EPROTO 71 /* Protocol error */ +#endif +#ifndef EMULTIHOP +#define EMULTIHOP 74 /* Multihop attempted */ +#endif +#ifndef EBADMSG +#define EBADMSG 77 /* Bad message */ +#endif +#ifndef EFTYPE +#define EFTYPE 79 /* Inappropriate file type or format */ +#endif +#ifndef ENOSYS +#define ENOSYS 88 /* Function not implemented */ +#endif +#ifndef ENOTEMPTY +#define ENOTEMPTY 90 /* Directory not empty */ +#endif +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 91 /* File or path name too long */ +#endif +#ifndef ELOOP +#define ELOOP 92 /* Too many symbolic links */ +#endif +#ifndef EOPNOTSUPP +#define EOPNOTSUPP 95 /* Operation not supported on socket */ +#endif +#ifndef EPFNOSUPPORT +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#endif +#ifndef ECONNRESET +#define ECONNRESET 104 /* Connection reset by peer */ +#endif +#ifndef ENOBUFS +#define ENOBUFS 105 /* No buffer space available */ +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#endif +#ifndef EPROTOTYPE +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#endif +#ifndef ENOTSOCK +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#endif +#ifndef ENOPROTOOPT +#define ENOPROTOOPT 109 /* Protocol not available */ +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED 111 /* Connection refused */ +#endif +#ifndef EADDRINUSE +#define EADDRINUSE 112 /* Address already in use */ +#endif +#ifndef ECONNABORTED +#define ECONNABORTED 113 /* Software caused connection abort */ +#endif +#ifndef ENETUNREACH +#define ENETUNREACH 114 /* Network is unreachable */ +#endif +#ifndef ENETDOWN +#define ENETDOWN 115 /* Network interface is not configured */ +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT 116 /* Connection timed out */ +#endif +#ifndef EHOSTDOWN +#define EHOSTDOWN 117 /* Host is down */ +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH 118 /* Host is unreachable */ +#endif +#ifndef EINPROGRESS +#define EINPROGRESS 119 /* Connection already in progress */ +#endif +#ifndef EALREADY +#define EALREADY 120 /* Socket already connected */ +#endif +#ifndef EDESTADDRREQ +#define EDESTADDRREQ 121 /* Destination address required */ +#endif +#ifndef EMSGSIZE +#define EMSGSIZE 122 /* Message too long */ +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL 125 /* Address not available */ +#endif +#ifndef ENETRESET +#define ENETRESET 126 /* Connection aborted by network */ +#endif +#ifndef EISCONN +#define EISCONN 127 /* Socket is already connected */ +#endif +#ifndef ENOTCONN +#define ENOTCONN 128 /* Socket is not connected */ +#endif +#ifndef ETOOMANYREFS +#define ETOOMANYREFS 129 +#endif +#ifndef EDQUOT +#define EDQUOT 132 +#endif +#ifndef ESTALE +#define ESTALE 133 +#endif +#ifndef ENOTSUP +#define ENOTSUP 134 /* Not supported */ +#endif +#ifndef EILSEQ +#define EILSEQ 138 /* Illegal byte sequence */ +#endif +#ifndef EOVERFLOW +#define EOVERFLOW 139 /* Value too large for defined data type */ +#endif +#ifndef ECANCELED +#define ECANCELED 140 /* Operation canceled */ +#endif +#ifndef ENOTRECOVERABLE +#define ENOTRECOVERABLE 141 /* State not recoverable */ +#endif +#ifndef EOWNERDEAD +#define EOWNERDEAD 142 /* Previous owner died */ +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#endif + +#define __ELASTERROR 2000 /* Users can add values starting here */ + +#ifdef __cplusplus +} +#endif +#endif /* _ERRNO_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/mdk-arm/errno.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/mdk-arm/errno.h new file mode 100644 index 0000000000..5fc060eabb --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/compiler/mdk-arm/errno.h @@ -0,0 +1,137 @@ +/* + * * Copyright (c) 2019 STMicroelectronics. All rights reserved. + * * + * * Copyright (c) 1982, 1986, 1989, 1993 + * * The Regents of the University of California. All rights reserved. + * * Copyright (c) 1982, 1986, 1989, 1993 + * * The Regents of the University of California. All rights reserved. + * * (c) UNIX System Laboratories, Inc. + * * All or some portions of this file are derived from material licensed + * * to the University of California by American Telephone and Telegraph + * * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * * the permission of UNIX System Laboratories, Inc. + * + * * SPDX-License-Identifier: BSD-3-Clause + * */ + + +#ifndef __METAL_ERRNO__H__ +#error "Include metal/errno.h instead of metal/mdk-arm/errno.h" +#endif + +#ifndef _ERRNO_H_ +#ifdef __cplusplus +extern "C" { +#endif +#define _ERRNO_H_ + +#define EPERM 1 /* Not owner */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#ifdef ENOMEM +#undef ENOMEM +#endif +#define ENOMEM 12 /* Not enough space */ + +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#ifdef EINVAL +#undef EINVAL +#endif +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* File descriptor value too large */ +#define ENOTTY 25 /* Not a character device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#ifdef EDOM +#undef EDOM +#endif +#define EDOM 33 /* Mathematics argument out of domain of function */ + +#ifdef ERANGE +#undef ERANGE +#endif +#define ERANGE 34 /* Result too large */ + +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#define EDEADLK 45 /* Deadlock */ +#define ENOLCK 46 /* No lock */ +#define ENOSTR 60 /* Not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Stream ioctl timeout */ +#define ENOSR 63 /* No stream resources */ +#define ENOLINK 67 /* Virtual circuit is gone */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define EBADMSG 77 /* Bad message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#define ENOSYS 88 /* Function not implemented */ +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on socket */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Software caused connection abort */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 /* Connection aborted by network */ +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#ifdef EILSEQ +#undef EILSEQ +#endif +#define EILSEQ 138 /* Illegal byte sequence */ +#define EOVERFLOW 139 /* Value too large for defined data type */ +#define ECANCELED 140 /* Operation canceled */ +#define ENOTRECOVERABLE 141 /* State not recoverable */ +#define EOWNERDEAD 142 /* Previous owner died */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ + +#define __ELASTERROR 2000 /* Users can add values starting here */ + +#ifdef __cplusplus +} +#endif +#endif /* _ERRNO_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/condition.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/condition.h new file mode 100644 index 0000000000..fc0cc0dcab --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/condition.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file condition.h + * @brief Condition variable for libmetal. + */ + +#ifndef __METAL_CONDITION__H__ +#define __METAL_CONDITION__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup condition Condition Variable Interfaces + * @{ */ + +/** Opaque libmetal condition variable data structure. */ +struct metal_condition; + +/** + * @brief Initialize a libmetal condition variable. + * @param[in] cv condition variable to initialize. + */ +static inline void metal_condition_init(struct metal_condition *cv); + +/** + * @brief Notify one waiter. + * Before calling this function, the caller + * should have acquired the mutex. + * @param[in] cv condition variable + * @return zero on no errors, non-zero on errors + * @see metal_condition_wait, metal_condition_broadcast + */ +static inline int metal_condition_signal(struct metal_condition *cv); + +/** + * @brief Notify all waiters. + * Before calling this function, the caller + * should have acquired the mutex. + * @param[in] cv condition variable + * @return zero on no errors, non-zero on errors + * @see metal_condition_wait, metal_condition_signal + */ +static inline int metal_condition_broadcast(struct metal_condition *cv); + +/** + * @brief Block until the condition variable is notified. + * Before calling this function, the caller should + * have acquired the mutex. + * @param[in] cv condition variable + * @param[in] m mutex + * @return 0 on success, non-zero on failure. + * @see metal_condition_signal + */ +int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m); + +#include + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_CONDITION__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/config.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/config.h new file mode 100644 index 0000000000..256efa3861 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/config.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file config.h + * @brief Generated configuration settings for libmetal. + */ + +#ifndef __METAL_CONFIG__H__ +#define __METAL_CONFIG__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Library major version number. */ +#define METAL_VER_MAJOR 0 + +/** Library minor version number. */ +#define METAL_VER_MINOR 1 + +/** Library patch level. */ +#define METAL_VER_PATCH 0 + +/** Library version string. */ +#define METAL_VER "0.1.0" + +/** System type (linux, generic, ...). */ +#define METAL_SYSTEM "generic" +#define METAL_SYSTEM_GENERIC + +/** Processor type (arm, x86_64, ...). */ +#define METAL_PROCESSOR "arm" +#define METAL_PROCESSOR_ARM + +/** Machine type (zynq, zynqmp, ...). */ +#define METAL_MACHINE "cortexm" +#define METAL_MACHINE_CORTEXM + +#define HAVE_STDATOMIC_H +/* #undef HAVE_FUTEX_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_CONFIG__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cpu.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cpu.h new file mode 100644 index 0000000000..26dbaa2af7 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/cpu.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU primitives for libmetal. + */ + +#ifndef __METAL_CPU__H__ +#define __METAL_CPU__H__ + +# include + +#endif /* __METAL_CPU__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/device.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/device.h new file mode 100644 index 0000000000..5ed43d63b7 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/device.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file device.h + * @brief Bus abstraction for libmetal. + */ + +#ifndef __METAL_BUS__H__ +#define __METAL_BUS__H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup device Bus Abstraction + * @{ */ + +#ifndef METAL_MAX_DEVICE_REGIONS +#define METAL_MAX_DEVICE_REGIONS 32 +#endif + +struct metal_bus; +struct metal_device; + +/** Bus operations. */ +struct metal_bus_ops { + void (*bus_close)(struct metal_bus *bus); + int (*dev_open)(struct metal_bus *bus, + const char *dev_name, + struct metal_device **device); + void (*dev_close)(struct metal_bus *bus, + struct metal_device *device); + void (*dev_irq_ack)(struct metal_bus *bus, + struct metal_device *device, + int irq); + int (*dev_dma_map)(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); + void (*dev_dma_unmap)(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg, + int nents); +}; + +/** Libmetal bus structure. */ +struct metal_bus { + const char *name; + struct metal_bus_ops ops; + struct metal_list devices; + struct metal_list node; +}; + +/** Libmetal generic bus. */ +extern struct metal_bus metal_generic_bus; + +/** Libmetal device structure. */ +struct metal_device { + const char *name; /**< Device name */ + struct metal_bus *bus; /**< Bus that contains device */ + unsigned num_regions; /**< Number of I/O regions in + device */ + struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of + I/O regions in device*/ + struct metal_list node; /**< Node on bus' list of devices */ + int irq_num; /**< Number of IRQs per device */ + void *irq_info; /**< IRQ ID */ +}; + +/** + * @brief Register a libmetal bus. + * @param[in] bus Pre-initialized bus structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_register(struct metal_bus *bus); + +/** + * @brief Unregister a libmetal bus. + * @param[in] bus Pre-registered bus structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_unregister(struct metal_bus *bus); + +/** + * @brief Find a libmetal bus by name. + * @param[in] name Bus name. + * @param[out] bus Returned bus handle. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_find(const char *name, struct metal_bus **bus); + +/** + * @brief Statically register a generic libmetal device. + * + * In non-Linux systems, devices are always required to be statically + * registered at application initialization. + * In Linux system, devices can be dynamically opened via sysfs or libfdt based + * enumeration at runtime. + * This interface is used for static registration of devices. Subsequent calls + * to metal_device_open() look up in this list of pre-registered devices on the + * "generic" bus. + * "generic" bus is used on non-Linux system to group the memory mapped devices. + * + * @param[in] device Generic device. + * @return 0 on success, or -errno on failure. + */ +extern int metal_register_generic_device(struct metal_device *device); + +/** + * @brief Open a libmetal device by name. + * @param[in] bus_name Bus name. + * @param[in] dev_name Device name. + * @param[out] device Returned device handle. + * @return 0 on success, or -errno on failure. + */ +extern int metal_device_open(const char *bus_name, const char *dev_name, + struct metal_device **device); + +/** + * @brief Close a libmetal device. + * @param[in] device Device handle. + */ +extern void metal_device_close(struct metal_device *device); + +/** + * @brief Get an I/O region accessor for a device region. + * + * @param[in] device Device handle. + * @param[in] index Region index. + * @return I/O accessor handle, or NULL on failure. + */ +static inline struct metal_io_region * +metal_device_io_region(struct metal_device *device, unsigned index) +{ + return (index < device->num_regions + ? &device->regions[index] + : NULL); +} + +/** @} */ + +#ifdef METAL_INTERNAL +extern int metal_generic_dev_sys_open(struct metal_device *dev); +extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name, + struct metal_device **device); +extern int metal_generic_dev_dma_map(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); +extern void metal_generic_dev_dma_unmap(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg, + int nents); +#endif /* METAL_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_BUS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/dma.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/dma.h new file mode 100644 index 0000000000..6675adc347 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/dma.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file dma.h + * @brief DMA primitives for libmetal. + */ + +#ifndef __METAL_DMA__H__ +#define __METAL_DMA__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup dma DMA Interfaces + * @{ */ + +#include +#include + +#define METAL_DMA_DEV_R 1 /**< DMA direction, device read */ +#define METAL_DMA_DEV_W 2 /**< DMA direction, device write */ +#define METAL_DMA_DEV_WR 3 /**< DMA direction, device read/write */ + +/** + * @brief scatter/gather list element structure + */ +struct metal_sg { + void *virt; /**< CPU virtual address */ + struct metal_io_region *io; /**< IO region */ + int len; /**< length */ +}; + +struct metal_device; + +/** + * @brief Map memory for DMA transaction. + * After the memory is DMA mapped, the memory should be + * accessed by the DMA device but not the CPU. + * + * @param[in] dev DMA device + * @param[in] dir DMA direction + * @param[in] sg_in sg list of memory to map + * @param[in] nents_in number of sg list entries of memory to map + * @param[out] sg_out sg list of mapped memory + * @return number of mapped sg entries, -error on failure. + */ +int metal_dma_map(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); + +/** + * @brief Unmap DMA memory + * After the memory is DMA unmapped, the memory should + * be accessed by the CPU but not the DMA device. + * + * @param[in] dev DMA device + * @param[in] dir DMA direction + * @param[in] sg sg list of mapped DMA memory + * @param[in] nents number of sg list entries of DMA memory + */ +void metal_dma_unmap(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg, + int nents); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_DMA__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/errno.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/errno.h new file mode 100644 index 0000000000..1d1b677c9d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/errno.h @@ -0,0 +1,24 @@ +/* + * * Copyright (c) 2019 STMicrolectonics , Xilinx Inc. and Contributors. All rights reserved. + * * + * * SPDX-License-Identifier: BSD-3-Clause + * */ + +/* + * * @file metal/errno.h + * * @brief error specific primitives for libmetal. + * */ + +#ifndef __METAL_ERRNO__H__ +#define __METAL_ERRNO__H__ + +#if defined (__CC_ARM) +# include +#elif defined (__ICCARM__) +# include +#else +#include +#endif + +#endif /* __METAL_ERRNO__H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/io.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/io.h new file mode 100644 index 0000000000..6aeafc4969 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/io.h @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file io.h + * @brief I/O access primitives for libmetal. + */ + +#ifndef __METAL_IO__H__ +#define __METAL_IO__H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup io IO Interfaces + * @{ */ + +#ifdef __MICROBLAZE__ +#define NO_ATOMIC_64_SUPPORT +#endif + +struct metal_io_region; + +/** Generic I/O operations. */ +struct metal_io_ops { + uint64_t (*read)(struct metal_io_region *io, + unsigned long offset, + memory_order order, + int width); + void (*write)(struct metal_io_region *io, + unsigned long offset, + uint64_t value, + memory_order order, + int width); + int (*block_read)(struct metal_io_region *io, + unsigned long offset, + void *restrict dst, + memory_order order, + int len); + int (*block_write)(struct metal_io_region *io, + unsigned long offset, + const void *restrict src, + memory_order order, + int len); + void (*block_set)(struct metal_io_region *io, + unsigned long offset, + unsigned char value, + memory_order order, + int len); + void (*close)(struct metal_io_region *io); +}; + +/** Libmetal I/O region structure. */ +struct metal_io_region { + void *virt; /**< base virtual address */ + const metal_phys_addr_t *physmap; /**< table of base physical address + of each of the pages in the I/O + region */ + size_t size; /**< size of the I/O region */ + unsigned long page_shift; /**< page shift of I/O region */ + metal_phys_addr_t page_mask; /**< page mask of I/O region */ + unsigned int mem_flags; /**< memory attribute of the + I/O region */ + struct metal_io_ops ops; /**< I/O region operations */ +}; + +/** + * @brief Open a libmetal I/O region. + * + * @param[in, out] io I/O region handle. + * @param[in] virt Virtual address of region. + * @param[in] physmap Array of physical addresses per page. + * @param[in] size Size of region. + * @param[in] page_shift Log2 of page size (-1 for single page). + * @param[in] mem_flags Memory flags + * @param[in] ops ops + */ +void +metal_io_init(struct metal_io_region *io, void *virt, + const metal_phys_addr_t *physmap, size_t size, + unsigned page_shift, unsigned int mem_flags, + const struct metal_io_ops *ops); + +/** + * @brief Close a libmetal shared memory segment. + * @param[in] io I/O region handle. + */ +static inline void metal_io_finish(struct metal_io_region *io) +{ + if (io->ops.close) + (*io->ops.close)(io); + memset(io, 0, sizeof(*io)); +} + +/** + * @brief Get size of I/O region. + * + * @param[in] io I/O region handle. + * @return Size of I/O region. + */ +static inline size_t metal_io_region_size(struct metal_io_region *io) +{ + return io->size; +} + +/** + * @brief Get virtual address for a given offset into the I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into shared memory segment. + * @return NULL if offset is out of range, or pointer to offset. + */ +static inline void * +metal_io_virt(struct metal_io_region *io, unsigned long offset) +{ + return (io->virt != METAL_BAD_VA && offset <= io->size + ? (uint8_t *)io->virt + offset + : NULL); +} + +/** + * @brief Convert a virtual address to offset within I/O region. + * @param[in] io I/O region handle. + * @param[in] virt Virtual address within segment. + * @return METAL_BAD_OFFSET if out of range, or offset. + */ +static inline unsigned long +metal_io_virt_to_offset(struct metal_io_region *io, void *virt) +{ + size_t offset = (uint8_t *)virt - (uint8_t *)io->virt; + return (offset < io->size ? offset : METAL_BAD_OFFSET); +} + +/** + * @brief Get physical address for a given offset into the I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into shared memory segment. + * @return METAL_BAD_PHYS if offset is out of range, or physical address + * of offset. + */ +static inline metal_phys_addr_t +metal_io_phys(struct metal_io_region *io, unsigned long offset) +{ + unsigned long page = (io->page_shift >= + sizeof(offset) * CHAR_BIT ? + 0 : offset >> io->page_shift); + return (io->physmap != NULL && offset <= io->size + ? io->physmap[page] + (offset & io->page_mask) + : METAL_BAD_PHYS); +} + +/** + * @brief Convert a physical address to offset within I/O region. + * @param[in] io I/O region handle. + * @param[in] phys Physical address within segment. + * @return METAL_BAD_OFFSET if out of range, or offset. + */ +static inline unsigned long +metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys) +{ + unsigned long offset = + (io->page_mask == (metal_phys_addr_t)(-1) ? + phys - io->physmap[0] : phys & io->page_mask); + do { + if (metal_io_phys(io, offset) == phys) + return offset; + offset += io->page_mask + 1; + } while (offset < io->size); + return METAL_BAD_OFFSET; +} + +/** + * @brief Convert a physical address to virtual address. + * @param[in] io Shared memory segment handle. + * @param[in] phys Physical address within segment. + * @return NULL if out of range, or corresponding virtual address. + */ +static inline void * +metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys) +{ + return metal_io_virt(io, metal_io_phys_to_offset(io, phys)); +} + +/** + * @brief Convert a virtual address to physical address. + * @param[in] io Shared memory segment handle. + * @param[in] virt Virtual address within segment. + * @return METAL_BAD_PHYS if out of range, or corresponding + * physical address. + */ +static inline metal_phys_addr_t +metal_io_virt_to_phys(struct metal_io_region *io, void *virt) +{ + return metal_io_phys(io, metal_io_virt_to_offset(io, virt)); +} + +/** + * @brief Read a value from an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] order Memory ordering. + * @param[in] width Width in bytes of datatype to read. This must be 1, 2, + * 4, or 8, and a compile time constant for this function + * to inline cleanly. + * @return Value. + */ +static inline uint64_t +metal_io_read(struct metal_io_region *io, unsigned long offset, + memory_order order, int width) +{ + void *ptr = metal_io_virt(io, offset); + + if (io->ops.read) + return (*io->ops.read)(io, offset, order, width); + else if (ptr && sizeof(atomic_uchar) == width) + return atomic_load_explicit((atomic_uchar *)ptr, order); + else if (ptr && sizeof(atomic_ushort) == width) + return atomic_load_explicit((atomic_ushort *)ptr, order); + else if (ptr && sizeof(atomic_uint) == width) + return atomic_load_explicit((atomic_uint *)ptr, order); + else if (ptr && sizeof(atomic_ulong) == width) + return atomic_load_explicit((atomic_ulong *)ptr, order); +#ifndef NO_ATOMIC_64_SUPPORT + else if (ptr && sizeof(atomic_ullong) == width) + return atomic_load_explicit((atomic_ullong *)ptr, order); +#endif + metal_assert(0); + return 0; /* quiet compiler */ +} + +/** + * @brief Write a value into an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] value Value to write. + * @param[in] order Memory ordering. + * @param[in] width Width in bytes of datatype to read. This must be 1, 2, + * 4, or 8, and a compile time constant for this function + * to inline cleanly. + */ +static inline void +metal_io_write(struct metal_io_region *io, unsigned long offset, + uint64_t value, memory_order order, int width) +{ + void *ptr = metal_io_virt(io, offset); + if (io->ops.write) + (*io->ops.write)(io, offset, value, order, width); + else if (ptr && sizeof(atomic_uchar) == width) + atomic_store_explicit((atomic_uchar *)ptr, value, order); + else if (ptr && sizeof(atomic_ushort) == width) + atomic_store_explicit((atomic_ushort *)ptr, value, order); + else if (ptr && sizeof(atomic_uint) == width) + atomic_store_explicit((atomic_uint *)ptr, value, order); + else if (ptr && sizeof(atomic_ulong) == width) + atomic_store_explicit((atomic_ulong *)ptr, value, order); +#ifndef NO_ATOMIC_64_SUPPORT + else if (ptr && sizeof(atomic_ullong) == width) + atomic_store_explicit((atomic_ullong *)ptr, value, order); +#endif + else + metal_assert (0); +} + +#define metal_io_read8_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 1) +#define metal_io_read8(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 1) +#define metal_io_write8_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 1) +#define metal_io_write8(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1) + +#define metal_io_read16_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 2) +#define metal_io_read16(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 2) +#define metal_io_write16_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 2) +#define metal_io_write16(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2) + +#define metal_io_read32_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 4) +#define metal_io_read32(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 4) +#define metal_io_write32_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 4) +#define metal_io_write32(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4) + +#define metal_io_read64_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 8) +#define metal_io_read64(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 8) +#define metal_io_write64_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 8) +#define metal_io_write64(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8) + +/** + * @brief Read a block from an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] dst destination to store the read data. + * @param[in] len length in bytes to read. + * @return On success, number of bytes read. On failure, negative value + */ +int metal_io_block_read(struct metal_io_region *io, unsigned long offset, + void *restrict dst, int len); + +/** + * @brief Write a block into an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] src source to write. + * @param[in] len length in bytes to write. + * @return On success, number of bytes written. On failure, negative value + */ +int metal_io_block_write(struct metal_io_region *io, unsigned long offset, + const void *restrict src, int len); + +/** + * @brief fill a block of an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] value value to fill into the block + * @param[in] len length in bytes to fill. + * @return On success, number of bytes filled. On failure, negative value + */ +int metal_io_block_set(struct metal_io_region *io, unsigned long offset, + unsigned char value, int len); + +#include + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IO__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/irq.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/irq.h new file mode 100644 index 0000000000..e8c92f9f18 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/irq.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file irq.h + * @brief Interrupt handling primitives for libmetal. + */ + +#ifndef __METAL_IRQ__H__ +#define __METAL_IRQ__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup irq Interrupt Handling Interfaces + * @{ */ + +#include + +/** IRQ handled status */ +#define METAL_IRQ_NOT_HANDLED 0 +#define METAL_IRQ_HANDLED 1 + +/** + * @brief type of interrupt handler + * @param[in] irq interrupt id + * @param[in] priv private data + * @return irq handled status + */ +typedef int (*metal_irq_handler) (int irq, void *priv); + +struct metal_device; + +/** + * @brief Register interrupt handler for driver ID/device. + * + * @param[in] irq interrupt id + * @param[in] irq_handler interrupt handler + * @param[in] dev metal device this irq belongs to (can be NULL). + * @param[in] drv_id driver id is a unique interrupt handler identifier. + * It can also be used for driver data. + * @return 0 for success, non-zero on failure + */ +int metal_irq_register(int irq, + metal_irq_handler irq_handler, + struct metal_device *dev, + void *drv_id); + +/** + * @brief Unregister interrupt handler for driver ID and/or device. + * + * If interrupt handler (hd), driver ID (drv_id) and device (dev) + * are NULL, unregister all handlers for this interrupt. + * + * If interrupt handler (hd), device (dev) or driver ID (drv_id), + * are not NULL, unregister handlers matching non NULL criterias. + * e.g: when call is made with drv_id and dev non NULL, + * all handlers matching both are unregistered. + * + * If interrupt is not found, or other criterias not matching, + * return -ENOENT + * + * @param[in] irq interrupt id + * @param[in] irq_handler interrupt handler + * @param[in] dev metal device this irq belongs to + * @param[in] drv_id driver id. It can be used for driver data. + * @return 0 for success, non-zero on failure + */ +int metal_irq_unregister(int irq, + metal_irq_handler irq_handler, + struct metal_device *dev, + void *drv_id); + +/** + * @brief disable interrupts + * @return interrupts state + */ +unsigned int metal_irq_save_disable(void); + +/** + * @brief restore interrupts to their previous state + * @param[in] flags previous interrupts state + */ +void metal_irq_restore_enable(unsigned int flags); + +/** + * @brief metal_irq_enable + * + * Enables the given interrupt + * + * @param vector - interrupt vector number + */ +void metal_irq_enable(unsigned int vector); + +/** + * @brief metal_irq_disable + * + * Disables the given interrupt + * + * @param vector - interrupt vector number + */ +void metal_irq_disable(unsigned int vector); + +#include + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IRQ__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/list.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/list.h new file mode 100644 index 0000000000..554aebfdb6 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/list.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file list.h + * @brief List primitives for libmetal. + */ + +#ifndef __METAL_LIST__H__ +#define __METAL_LIST__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup list List Primitives + * @{ */ + +struct metal_list { + struct metal_list *next, *prev; +}; + +/* + * METAL_INIT_LIST - used for initializing an list elmenet in a static struct + * or global + */ +#define METAL_INIT_LIST(name) { .next = &name, .prev = &name } +/* + * METAL_DECLARE_LIST - used for defining and initializing a global or + * static singleton list + */ +#define METAL_DECLARE_LIST(name) \ + struct metal_list name = METAL_INIT_LIST(name) + +static inline void metal_list_init(struct metal_list *list) +{ + list->next = list->prev = list; +} + +static inline void metal_list_add_before(struct metal_list *node, + struct metal_list *new_node) +{ + new_node->prev = node->prev; + new_node->next = node; + new_node->next->prev = new_node; + new_node->prev->next = new_node; +} + +static inline void metal_list_add_after(struct metal_list *node, + struct metal_list *new_node) +{ + new_node->prev = node; + new_node->next = node->next; + new_node->next->prev = new_node; + new_node->prev->next = new_node; +} + +static inline void metal_list_add_head(struct metal_list *list, + struct metal_list *node) +{ + metal_list_add_after(list, node); +} + +static inline void metal_list_add_tail(struct metal_list *list, + struct metal_list *node) +{ + metal_list_add_before(list, node); +} + +static inline int metal_list_is_empty(struct metal_list *list) +{ + return list->next == list; +} + +static inline void metal_list_del(struct metal_list *node) +{ + node->next->prev = node->prev; + node->prev->next = node->next; + node->next = node->prev = node; +} + +static inline struct metal_list *metal_list_first(struct metal_list *list) +{ + return metal_list_is_empty(list) ? NULL : list->next; +} + +#define metal_list_for_each(list, node) \ + for ((node) = (list)->next; \ + (node) != (list); \ + (node) = (node)->next) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_LIST__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/log.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/log.h new file mode 100644 index 0000000000..3807bbbef4 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/log.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file log.h + * @brief Logging support for libmetal. + */ + +#ifndef __METAL_METAL_LOG__H__ +#define __METAL_METAL_LOG__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup logging Library Logging Interfaces + * @{ */ + +/** Log message priority levels for libmetal. */ +enum metal_log_level { + METAL_LOG_EMERGENCY, /**< system is unusable. */ + METAL_LOG_ALERT, /**< action must be taken immediately. */ + METAL_LOG_CRITICAL, /**< critical conditions. */ + METAL_LOG_ERROR, /**< error conditions. */ + METAL_LOG_WARNING, /**< warning conditions. */ + METAL_LOG_NOTICE, /**< normal but significant condition. */ + METAL_LOG_INFO, /**< informational messages. */ + METAL_LOG_DEBUG, /**< debug-level messages. */ +}; + +/** Log message handler type. */ +typedef void (*metal_log_handler)(enum metal_log_level level, + const char *format, ...); + +/** + * @brief Set libmetal log handler. + * @param[in] handler log message handler. + * @return 0 on success, or -errno on failure. + */ +extern void metal_set_log_handler(metal_log_handler handler); + +/** + * @brief Get the current libmetal log handler. + * @return Current log handler. + */ +extern metal_log_handler metal_get_log_handler(void); + +/** + * @brief Set the level for libmetal logging. + * @param[in] level log message level. + */ +extern void metal_set_log_level(enum metal_log_level level); + +/** + * @brief Get the current level for libmetal logging. + * @return Current log level. + */ +extern enum metal_log_level metal_get_log_level(void); + +/** + * @brief Default libmetal log handler. This handler prints libmetal log + * mesages to stderr. + * @param[in] level log message level. + * @param[in] format log message format string. + * @return 0 on success, or -errno on failure. + */ +extern void metal_default_log_handler(enum metal_log_level level, + const char *format, ...); + + +/** + * Emit a log message if the log level permits. + * + * @param level Log level. + * @param ... Format string and arguments. + */ +#define metal_log(level, ...) \ + ((level <= _metal.common.log_level && _metal.common.log_handler) \ + ? (void)_metal.common.log_handler(level, __VA_ARGS__) \ + : (void)0) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* __METAL_METAL_LOG__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/mutex.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/mutex.h new file mode 100644 index 0000000000..053f679200 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/mutex.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file mutex.h + * @brief Mutex primitives for libmetal. + */ + +#ifndef __METAL_MUTEX__H__ +#define __METAL_MUTEX__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup mutex Mutex Interfaces + * @{ */ + +#include + +/** + * @brief Initialize a libmetal mutex. + * @param[in] mutex Mutex to initialize. + */ +static inline void metal_mutex_init(metal_mutex_t *mutex) +{ + __metal_mutex_init(mutex); +} + +/** + * @brief Deinitialize a libmetal mutex. + * @param[in] mutex Mutex to deinitialize. + */ +static inline void metal_mutex_deinit(metal_mutex_t *mutex) +{ + __metal_mutex_deinit(mutex); +} + +/** + * @brief Try to acquire a mutex + * @param[in] mutex Mutex to mutex. + * @return 0 on failure to acquire, non-zero on success. + */ +static inline int metal_mutex_try_acquire(metal_mutex_t *mutex) +{ + return __metal_mutex_try_acquire(mutex); +} + +/** + * @brief Acquire a mutex + * @param[in] mutex Mutex to mutex. + */ +static inline void metal_mutex_acquire(metal_mutex_t *mutex) +{ + __metal_mutex_acquire(mutex); +} + +/** + * @brief Release a previously acquired mutex. + * @param[in] mutex Mutex to mutex. + * @see metal_mutex_try_acquire, metal_mutex_acquire + */ +static inline void metal_mutex_release(metal_mutex_t *mutex) +{ + __metal_mutex_release(mutex); +} + +/** + * @brief Checked if a mutex has been acquired. + * @param[in] mutex mutex to check. + * @see metal_mutex_try_acquire, metal_mutex_acquire + */ +static inline int metal_mutex_is_acquired(metal_mutex_t *mutex) +{ + return __metal_mutex_is_acquired(mutex); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_MUTEX__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/atomic.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/atomic.h new file mode 100644 index 0000000000..3a577e378d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/atomic.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file arm/atomic.h + * @brief ARM specific atomic primitives for libmetal. + */ + +#ifndef __METAL_ARM_ATOMIC__H__ +#define __METAL_ARM_ATOMIC__H__ + +#endif /* __METAL_ARM_ATOMIC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/cpu.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/cpu.h new file mode 100644 index 0000000000..2141fb3982 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/processor/arm/cpu.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU specific primatives + */ + +#ifndef __METAL_ARM_CPU__H__ +#define __METAL_ARM_CPU__H__ + +#define metal_cpu_yield() + +#endif /* __METAL_ARM_CPU__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/shmem.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/shmem.h new file mode 100644 index 0000000000..17e9d2067e --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/shmem.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file shmem.h + * @brief Shared memory primitives for libmetal. + */ + +#ifndef __METAL_SHMEM__H__ +#define __METAL_SHMEM__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup shmem Shared Memory Interfaces + * @{ */ + +/** Generic shared memory data structure. */ +struct metal_generic_shmem { + const char *name; + struct metal_io_region io; + struct metal_list node; +}; + +/** + * @brief Open a libmetal shared memory segment. + * + * Open a shared memory segment. + * + * @param[in] name Name of segment to open. + * @param[in] size Size of segment. + * @param[out] io I/O region handle, if successful. + * @return 0 on success, or -errno on failure. + * + * @see metal_shmem_create + */ +extern int metal_shmem_open(const char *name, size_t size, + struct metal_io_region **io); + +/** + * @brief Statically register a generic shared memory region. + * + * Shared memory regions may be statically registered at application + * initialization, or may be dynamically opened. This interface is used for + * static registration of regions. Subsequent calls to metal_shmem_open() look + * up in this list of pre-registered regions. + * + * @param[in] shmem Generic shmem structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_shmem_register_generic(struct metal_generic_shmem *shmem); + +#ifdef METAL_INTERNAL + +/** + * @brief Open a statically registered shmem segment. + * + * This interface is meant for internal libmetal use within system specific + * shmem implementations. + * + * @param[in] name Name of segment to open. + * @param[in] size Size of segment. + * @param[out] io I/O region handle, if successful. + * @return 0 on success, or -errno on failure. + */ +int metal_shmem_open_generic(const char *name, size_t size, + struct metal_io_region **result); + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SHMEM__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sleep.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sleep.h new file mode 100644 index 0000000000..1131934655 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sleep.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file sleep.h + * @brief Sleep primitives for libmetal. + */ + +#ifndef __METAL_SLEEP__H__ +#define __METAL_SLEEP__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup sleep Sleep Interfaces + * @{ */ + +/** + * @brief delay in microseconds + * delay the next execution in the calling thread + * fo usec microseconds. + * + * @param[in] usec microsecond intervals + * @return 0 on success, non-zero for failures + */ +static inline int metal_sleep_usec(unsigned int usec) +{ + return __metal_sleep_usec(usec); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SLEEP__H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/spinlock.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/spinlock.h new file mode 100644 index 0000000000..ebd4cae4ef --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/spinlock.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file spinlock.h + * @brief Spinlock primitives for libmetal. + */ + +#ifndef __METAL_SPINLOCK__H__ +#define __METAL_SPINLOCK__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup spinlock Spinlock Interfaces + * @{ */ +struct metal_spinlock { + union{ + atomic_int v; + atomic_flag w; + }; +}; + +/** Static metal spinlock initialization. */ +#define METAL_SPINLOCK_INIT {ATOMIC_VAR_INIT(0)} + +/** + * @brief Initialize a libmetal spinlock. + * @param[in] slock Spinlock to initialize. + */ +static inline void metal_spinlock_init(struct metal_spinlock *slock) +{ + atomic_store(&slock->v, 0); +} + +/** + * @brief Acquire a spinlock. + * @param[in] slock Spinlock to acquire. + * @see metal_spinlock_release + */ +static inline void metal_spinlock_acquire(struct metal_spinlock *slock) +{ + while (atomic_flag_test_and_set(&slock->w)) { + metal_cpu_yield(); + } +} + +/** + * @brief Release a previously acquired spinlock. + * @param[in] slock Spinlock to release. + * @see metal_spinlock_acquire + */ +static inline void metal_spinlock_release(struct metal_spinlock *slock) +{ + atomic_flag_clear(&slock->w); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SPINLOCK__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sys.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sys.h new file mode 100644 index 0000000000..908f796740 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/sys.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file sys.h + * @brief System primitives for libmetal. + * @brief Top level include internal to libmetal library code. + */ + +#ifndef __METAL_SYS__H__ +#define __METAL_SYS__H__ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup system Top Level Interfaces + * @{ */ + +/** Physical address type. */ +typedef unsigned long metal_phys_addr_t; + +/** Interrupt request number. */ +typedef int metal_irq_t; + +/** Bad offset into shared memory or I/O region. */ +#define METAL_BAD_OFFSET ((unsigned long)-1) + +/** Bad physical address value. */ +#define METAL_BAD_PHYS ((metal_phys_addr_t)-1) + +/** Bad virtual address value. */ +#define METAL_BAD_VA ((void *)-1) + +/** Bad IRQ. */ +#define METAL_BAD_IRQ ((metal_irq_t)-1) + +/** + * Initialization configuration for libmetal. + */ +struct metal_init_params { + + /** log message handler (defaults to stderr). */ + metal_log_handler log_handler; + + /** default log message level (defaults to emergency). */ + enum metal_log_level log_level; +}; + +/** + * System independent runtime state for libmetal. This is part of a system + * specific singleton data structure (@see _metal). + */ +struct metal_common_state { + /** Current log level. */ + enum metal_log_level log_level; + + /** Current log handler (null for none). */ + metal_log_handler log_handler; + + /** List of registered buses. */ + struct metal_list bus_list; + + /** Generic statically defined shared memory segments. */ + struct metal_list generic_shmem_list; + + /** Generic statically defined devices. */ + struct metal_list generic_device_list; +}; + +struct metal_state; + +#include + +#ifndef METAL_INIT_DEFAULTS +#define METAL_INIT_DEFAULTS \ +{ \ + .log_handler = metal_default_log_handler, \ + .log_level = METAL_LOG_INFO, \ +} +#endif + +/** System specific runtime data. */ +extern struct metal_state _metal; + +/** + * @brief Initialize libmetal. + * + * Initialize the libmetal library. + * + * @param[in] params Initialization params (@see metal_init_params). + * + * @return 0 on success, or -errno on failure. + * + * @see metal_finish + */ +extern int metal_init(const struct metal_init_params *params); + +/** + * @brief Shutdown libmetal. + * + * Shutdown the libmetal library, and release all reserved resources. + * + * @see metal_init + */ +extern void metal_finish(void); + +#ifdef METAL_INTERNAL + +/** + * @brief libmetal system initialization. + * + * This function initializes libmetal on Linux or Generic platforms. This + * involves obtaining necessary pieces of system information (sysfs mount path, + * page size, etc.). + * + * @param[in] params Initialization parameters (@see metal_init_params). + * @return 0 on success, or -errno on failure. + */ +extern int metal_sys_init(const struct metal_init_params *params); + +/** + * @brief libmetal system shutdown. + * + * This function shuts down and releases resources held by libmetal Linux or + * Generic platform layers. + * + * @see metal_sys_init + */ +extern void metal_sys_finish(void); + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SYS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/alloc.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/alloc.h new file mode 100644 index 0000000000..bcceba61a0 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/alloc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/alloc.c + * @brief generic libmetal memory allocattion definitions. + */ + +#ifndef __METAL_ALLOC__H__ +#error "Include metal/alloc.h instead of metal/generic/alloc.h" +#endif + +#ifndef __METAL_GENERIC_ALLOC__H__ +#define __METAL_GENERIC_ALLOC__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void *metal_allocate_memory(unsigned int size) +{ + return (malloc(size)); +} + +static inline void metal_free_memory(void *ptr) +{ + free(ptr); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_ALLOC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/assert.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/assert.h new file mode 100644 index 0000000000..97f88ee5a5 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/assert.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file assert.h + * @brief Generic assertion support. + */ + +#ifndef __METAL_ASSERT__H__ +#error "Include metal/assert.h instead of metal/generic/assert.h" +#endif + +#ifndef __METAL_GENERIC_ASSERT__H__ +#define __METAL_GENERIC_ASSERT__H__ + +#include + +/** + * @brief Assertion macro for bare-metal applications. + * @param cond Condition to evaluate. + */ +#define metal_sys_assert(cond) assert(cond) + +#endif /* __METAL_GENERIC_ASSERT__H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cache.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cache.h new file mode 100644 index 0000000000..962ffccfa9 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cache.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/cache.h + * @brief generic cache operation primitives for libmetal. + */ + +#ifndef __METAL_CACHE__H__ +#error "Include metal/cache.h instead of metal/generic/cache.h" +#endif + +#ifndef __METAL_GENERIC_CACHE__H__ +#define __METAL_GENERIC_CACHE__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void metal_machine_cache_flush(void *addr, unsigned int len); +extern void metal_machine_cache_invalidate(void *addr, unsigned int len); + +static inline void __metal_cache_flush(void *addr, unsigned int len) +{ + metal_machine_cache_flush(addr, len); +} + +static inline void __metal_cache_invalidate(void *addr, unsigned int len) +{ + metal_machine_cache_invalidate(addr, len); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_CACHE__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/condition.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/condition.h new file mode 100644 index 0000000000..5202f3345f --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/condition.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/condition.h + * @brief Generic condition variable primitives for libmetal. + */ + +#ifndef __METAL_CONDITION__H__ +#error "Include metal/condition.h instead of metal/generic/condition.h" +#endif + +#ifndef __METAL_GENERIC_CONDITION__H__ +#define __METAL_GENERIC_CONDITION__H__ + +#if defined (__CC_ARM) +#include +#endif +#include +#include +#include +#include + + + +#ifdef __cplusplus +extern "C" { +#endif + +struct metal_condition { + metal_mutex_t *m; /**< mutex. + The condition variable is attached to + this mutex when it is waiting. + It is also used to check correctness + in case there are multiple waiters. */ + + atomic_int v; /**< condition variable value. */ +}; + +/** Static metal condition variable initialization. */ +#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0) } + +static inline void metal_condition_init(struct metal_condition *cv) +{ + cv->m = NULL; + atomic_init(&cv->v, 0); +} + +static inline int metal_condition_signal(struct metal_condition *cv) +{ + if (!cv) + return -EINVAL; + + /** wake up waiters if there are any. */ + atomic_fetch_add(&cv->v, 1); + return 0; +} + +static inline int metal_condition_broadcast(struct metal_condition *cv) +{ + return metal_condition_signal(cv); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_CONDITION__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cortexm/sys.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cortexm/sys.h new file mode 100644 index 0000000000..f506887783 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/cortexm/sys.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. 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 Xilinx 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 generic/mp1_m4/sys.h + * @brief generic mp1_m4 system primitives for libmetal. + */ + +#ifndef __METAL_GENERIC_SYS__H__ +#error "Include metal/sys.h instead of metal/generic/cortexm/sys.h" +#endif + +#ifndef __METAL_GENERIC_MP1_M4_SYS__H__ +#define __METAL_GENERIC_MP1_M4_SYS__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MAX_IRQS) +#define MAX_IRQS 8 /**< maximum number of irqs */ +#endif + +static inline void sys_irq_enable(unsigned int vector) +{ + (void)vector; +} + +static inline void sys_irq_disable(unsigned int vector) +{ + (void)vector; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_MP1_M4_SYS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/io.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/io.h new file mode 100644 index 0000000000..adbbc44774 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/io.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/io.h + * @brief Generic specific io definitions. + */ + +#ifndef __METAL_IO__H__ +#error "Include metal/io.h instead of metal/generic/io.h" +#endif + +#ifndef __METAL_GENERIC_IO__H__ +#define __METAL_GENERIC_IO__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef METAL_INTERNAL + +/** + * @brief memory mapping for an I/O region + */ +void metal_sys_io_mem_map(struct metal_io_region *io); + +/** + * @brief memory mapping + */ +void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa, + size_t size, unsigned int flags); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_IO__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/irq.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/irq.h new file mode 100644 index 0000000000..c618c87fde --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/irq.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/irq.c + * @brief Generic libmetal irq definitions. + */ + +#ifndef __METAL_IRQ__H__ +#error "Include metal/irq.h instead of metal/generic/irq.h" +#endif + +#ifndef __METAL_GENERIC_IRQ__H__ +#define __METAL_GENERIC_IRQ__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief default interrupt handler + * @param[in] vector interrupt vector + */ +void metal_irq_isr(unsigned int vector); + + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_IRQ__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/log.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/log.h new file mode 100644 index 0000000000..32611288ad --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/log.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * 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 Linaro 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 generic/log.h + * @brief Generic libmetal log handler definition. + */ + +#ifndef __METAL_METAL_LOG__H__ +#error "Include metal/log.h instead of metal/generic/log.h" +#endif + +#ifndef __METAL_GENERIC_LOG__H__ +#define __METAL_GENERIC_LOG__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_LOG__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/mutex.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/mutex.h new file mode 100644 index 0000000000..3613c194d1 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/mutex.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/mutex.h + * @brief Generic mutex primitives for libmetal. + */ + +#ifndef __METAL_MUTEX__H__ +#error "Include metal/mutex.h instead of metal/generic/mutex.h" +#endif + +#ifndef __METAL_GENERIC_MUTEX__H__ +#define __METAL_GENERIC_MUTEX__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + union{ + atomic_int v; + atomic_flag w; + }; +} metal_mutex_t; + +/* + * METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct + * or global + */ +#define METAL_MUTEX_INIT(m) { ATOMIC_VAR_INIT(0) } +/* + * METAL_MUTEX_DEFINE - used for defining and initializing a global or + * static singleton mutex + */ +#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = METAL_MUTEX_INIT(m) + +static inline void __metal_mutex_init(metal_mutex_t *mutex) +{ + atomic_store(&mutex->v, 0); +} + +static inline void __metal_mutex_deinit(metal_mutex_t *mutex) +{ + (void)mutex; +} + +static inline int __metal_mutex_try_acquire(metal_mutex_t *mutex) +{ + return 1 - atomic_flag_test_and_set(&mutex->w); +} + +static inline void __metal_mutex_acquire(metal_mutex_t *mutex) +{ + while (atomic_flag_test_and_set(&mutex->w)) { + ; + } +} + +static inline void __metal_mutex_release(metal_mutex_t *mutex) +{ + atomic_flag_clear(&mutex->w); +} + +static inline int __metal_mutex_is_acquired(metal_mutex_t *mutex) +{ + return atomic_load(&mutex->v); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_MUTEX__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sleep.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sleep.h new file mode 100644 index 0000000000..aa86df492e --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sleep.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/sleep.h + * @brief Generic sleep primitives for libmetal. + */ + +#ifndef __METAL_SLEEP__H__ +#error "Include metal/sleep.h instead of metal/generic/sleep.h" +#endif + +#ifndef __METAL_GENERIC_SLEEP__H__ +#define __METAL_GENERIC_SLEEP__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int __metal_sleep_usec(unsigned int usec) +{ + metal_unused(usec); + /* Fix me */ + return 0; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_SLEEP__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sys.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sys.h new file mode 100644 index 0000000000..6f6143a4ce --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/system/generic/sys.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/sys.h + * @brief Generic system primitives for libmetal. + */ + +#ifndef __METAL_SYS__H__ +#error "Include metal/sys.h instead of metal/generic/sys.h" +#endif + +#ifndef __METAL_GENERIC_SYS__H__ +#define __METAL_GENERIC_SYS__H__ + +#include +#include +#include +#include +#include +#include + +#include "./cortexm/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef METAL_MAX_DEVICE_REGIONS +#define METAL_MAX_DEVICE_REGIONS 1 +#endif + +/** Structure of generic libmetal runtime state. */ +struct metal_state { + + /** Common (system independent) data. */ + struct metal_common_state common; +}; + +#ifdef METAL_INTERNAL + +/** + * @brief restore interrupts to state before disable_global_interrupt() + */ +void sys_irq_restore_enable(unsigned int flags); + +/** + * @brief disable all interrupts + */ +unsigned int sys_irq_save_disable(void); + +#endif /* METAL_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_SYS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/time.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/time.h new file mode 100644 index 0000000000..0da6821783 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/time.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file time.h + * @brief Time primitives for libmetal. + */ + +#ifndef __METAL_TIME__H__ +#define __METAL_TIME__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup time TIME Interfaces + * @{ */ + +#include +#include + +/** + * @brief get timestamp + * This function returns the timestampe as unsigned long long + * value. + * + * @return timestamp + */ +unsigned long long metal_get_timestamp(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_TIME__H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/utilities.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/utilities.h new file mode 100644 index 0000000000..eb540d2f0a --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/utilities.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file utilities.h + * @brief Utility routines for libmetal. + */ + +#ifndef __METAL_UTILITIES__H__ +#define __METAL_UTILITIES__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup utilities Simple Utilities + * @{ */ + +/** Marker for unused function arguments/variables. */ +#define metal_unused(x) do { (x) = (x); } while (0) + +/** Figure out number of elements in an array. */ +#define metal_dim(x) (sizeof(x) / sizeof(x[0])) + +/** Minimum of two numbers (warning: multiple evaluation!). */ +#define metal_min(x, y) ((x) < (y) ? (x) : (y)) + +/** Maximum of two numbers (warning: multiple evaluation!). */ +#define metal_max(x, y) ((x) > (y) ? (x) : (y)) + +/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!). */ +#define metal_sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) + +/** Align 'size' down to a multiple of 'align' (must be a power of two). */ +#define metal_align_down(size, align) \ + ((size) & ~((align) - 1)) + +/** Align 'size' up to a multiple of 'align' (must be a power of two). */ +#define metal_align_up(size, align) \ + metal_align_down((size) + (align) - 1, align) + +/** Divide (and round down). */ +#define metal_div_round_down(num, den) \ + ((num) / (den)) + +/** Divide (and round up). */ +#define metal_div_round_up(num, den) \ + metal_div_round_down((num) + (den) - 1, (den)) + +/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */ +#define metal_ptr_align_down(ptr, align) \ + (void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align))) + +/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */ +#define metal_ptr_align_up(ptr, align) \ + (void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align))) + +/** Compute offset of a field within a structure. */ +#define metal_offset_of(structure, member) \ + ((uintptr_t) &(((structure *) 0)->member)) + +/** Compute pointer to a structure given a pointer to one of its fields. */ +#define metal_container_of(ptr, structure, member) \ + (void *)((uintptr_t)(ptr) - metal_offset_of(structure, member)) + +#define METAL_BITS_PER_ULONG (8 * sizeof(unsigned long)) + +#define metal_bit(bit) (1UL << (bit)) + +#define metal_bitmap_longs(x) metal_div_round_up((x), METAL_BITS_PER_ULONG) + +static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit / METAL_BITS_PER_ULONG] |= + metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); +} + +static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit) +{ + return bitmap[bit / METAL_BITS_PER_ULONG] & + metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); +} + +static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit / METAL_BITS_PER_ULONG] &= + ~metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); +} + +static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit) +{ + return !metal_bitmap_is_bit_set(bitmap, bit); +} + +static inline unsigned int +metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start, + unsigned int max) +{ + unsigned int bit; + for (bit = start; + bit < max && !metal_bitmap_is_bit_set(bitmap, bit); + bit ++) + ; + return bit; +} + +#define metal_bitmap_for_each_set_bit(bitmap, bit, max) \ + for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max)); \ + (bit) < (max); \ + (bit) = metal_bitmap_next_set_bit((bitmap), (bit), (max))) + +static inline unsigned int +metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start, + unsigned int max) +{ + unsigned int bit; + for (bit = start; + bit < max && !metal_bitmap_is_bit_clear(bitmap, bit); + bit ++) + ; + return bit; +} + +#define metal_bitmap_for_each_clear_bit(bitmap, bit, max) \ + for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max)); \ + (bit) < (max); \ + (bit) = metal_bitmap_next_clear_bit((bitmap), (bit), (max))) + +static inline unsigned long metal_log2(unsigned long in) +{ + unsigned long result; + + metal_assert((in & (in - 1)) == 0); + + for (result = 0; (1UL << result) < in; result ++) + ; + return result; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_UTILITIES__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/version.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/version.h new file mode 100644 index 0000000000..f093c51201 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/include/metal/version.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file version.h + * @brief Library version information for libmetal. + */ + +#ifndef __METAL_VERSION__H__ +#define __METAL_VERSION__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup versions Library Version Interfaces + * @{ */ + +/** + * @brief Library major version number. + * + * Return the major version number of the library linked into the application. + * This is required to match the value of METAL_VER_MAJOR, which is the major + * version of the library that the application was compiled against. + * + * @return Library major version number. + * @see METAL_VER_MAJOR + */ +extern int metal_ver_major(void); + +/** + * @brief Library minor version number. + * + * Return the minor version number of the library linked into the application. + * This could differ from the value of METAL_VER_MINOR, which is the minor + * version of the library that the application was compiled against. + * + * @return Library minor version number. + * @see METAL_VER_MINOR + */ +extern int metal_ver_minor(void); + +/** + * @brief Library patch level. + * + * Return the patch level of the library linked into the application. This + * could differ from the value of METAL_VER_PATCH, which is the patch level of + * the library that the application was compiled against. + * + * @return Library patch level. + * @see METAL_VER_PATCH + */ +extern int metal_ver_patch(void); + +/** + * @brief Library version string. + * + * Return the version string of the library linked into the application. This + * could differ from the value of METAL_VER, which is the version string of + * the library that the application was compiled against. + * + * @return Library version string. + * @see METAL_VER + */ +extern const char *metal_ver(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_VERSION__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/init.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/init.c new file mode 100644 index 0000000000..315217741f --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/init.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +int metal_init(const struct metal_init_params *params) +{ + int error = 0; + + memset(&_metal, 0, sizeof(_metal)); + + _metal.common.log_handler = params->log_handler; + _metal.common.log_level = params->log_level; + + metal_list_init(&_metal.common.bus_list); + metal_list_init(&_metal.common.generic_shmem_list); + metal_list_init(&_metal.common.generic_device_list); + + error = metal_sys_init(params); + if (error) + return error; + + return error; +} + +void metal_finish(void) +{ + metal_sys_finish(); + memset(&_metal, 0, sizeof(_metal)); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/io.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/io.c new file mode 100644 index 0000000000..fccf1100e0 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/io.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +void metal_io_init(struct metal_io_region *io, void *virt, + const metal_phys_addr_t *physmap, size_t size, + unsigned page_shift, unsigned int mem_flags, + const struct metal_io_ops *ops) +{ + const struct metal_io_ops nops = {NULL, NULL, NULL, NULL, NULL, NULL}; + + io->virt = virt; + io->physmap = physmap; + io->size = size; + io->page_shift = page_shift; + if (page_shift >= sizeof(io->page_mask) * CHAR_BIT) + /* avoid overflow */ + io->page_mask = -1UL; + else + io->page_mask = (1UL << page_shift) - 1UL; + io->mem_flags = mem_flags; + io->ops = ops ? *ops : nops; + metal_sys_io_mem_map(io); +} + +int metal_io_block_read(struct metal_io_region *io, unsigned long offset, + void *restrict dst, int len) +{ + unsigned char *ptr = metal_io_virt(io, offset); + unsigned char *dest = dst; + int retlen; + + if (offset > io->size) + return -ERANGE; + if ((offset + len) > io->size) + len = io->size - offset; + retlen = len; + if (io->ops.block_read) { + retlen = (*io->ops.block_read)( + io, offset, dst, memory_order_seq_cst, len); + } else { + atomic_thread_fence(memory_order_seq_cst); + while ( len && ( + ((uintptr_t)dest % sizeof(int)) || + ((uintptr_t)ptr % sizeof(int)))) { + *(unsigned char *)dest = + *(const unsigned char *)ptr; + dest++; + ptr++; + len--; + } + for (; len >= (int)sizeof(int); dest += sizeof(int), + ptr += sizeof(int), + len -= sizeof(int)) + *(unsigned int *)dest = *(const unsigned int *)ptr; + for (; len != 0; dest++, ptr++, len--) + *(unsigned char *)dest = + *(const unsigned char *)ptr; + } + return retlen; +} + +int metal_io_block_write(struct metal_io_region *io, unsigned long offset, + const void *restrict src, int len) +{ + unsigned char *ptr = metal_io_virt(io, offset); + const unsigned char *source = src; + int retlen; + + if (offset > io->size) + return -ERANGE; + if ((offset + len) > io->size) + len = io->size - offset; + retlen = len; + if (io->ops.block_write) { + retlen = (*io->ops.block_write)( + io, offset, src, memory_order_seq_cst, len); + } else { + while ( len && ( + ((uintptr_t)ptr % sizeof(int)) || + ((uintptr_t)source % sizeof(int)))) { + *(unsigned char *)ptr = + *(const unsigned char *)source; + ptr++; + source++; + len--; + } + for (; len >= (int)sizeof(int); ptr += sizeof(int), + source += sizeof(int), + len -= sizeof(int)) + *(unsigned int *)ptr = *(const unsigned int *)source; + for (; len != 0; ptr++, source++, len--) + *(unsigned char *)ptr = + *(const unsigned char *)source; + atomic_thread_fence(memory_order_seq_cst); + } + return retlen; +} + +int metal_io_block_set(struct metal_io_region *io, unsigned long offset, + unsigned char value, int len) +{ + unsigned char *ptr = metal_io_virt(io, offset); + int retlen = len; + + if (offset > io->size) + return -ERANGE; + if ((offset + len) > io->size) + len = io->size - offset; + retlen = len; + if (io->ops.block_set) { + (*io->ops.block_set)( + io, offset, value, memory_order_seq_cst, len); + } else { + unsigned int cint = value; + unsigned int i; + + for (i = 1; i < sizeof(int); i++) + cint |= ((unsigned int)value << (8 * i)); + + for (; len && ((uintptr_t)ptr % sizeof(int)); ptr++, len--) + *(unsigned char *)ptr = (unsigned char) value; + for (; len >= (int)sizeof(int); ptr += sizeof(int), + len -= sizeof(int)) + *(unsigned int *)ptr = cint; + for (; len != 0; ptr++, len--) + *(unsigned char *)ptr = (unsigned char) value; + atomic_thread_fence(memory_order_seq_cst); + } + return retlen; +} + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/log.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/log.c new file mode 100644 index 0000000000..83bec1f6d0 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/log.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include + +void metal_default_log_handler(enum metal_log_level level, + const char *format, ...) +{ +#ifdef DEFAULT_LOGGER_ON + char msg[1024]; + va_list args; + static const char *level_strs[] = { + "metal: emergency: ", + "metal: alert: ", + "metal: critical: ", + "metal: error: ", + "metal: warning: ", + "metal: notice: ", + "metal: info: ", + "metal: debug: ", + }; + + va_start(args, format); + vsnprintf(msg, sizeof(msg), format, args); + va_end(args); + + if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG) + level = METAL_LOG_EMERGENCY; + + fprintf(stderr, "%s%s", level_strs[level], msg); +#else + (void)level; + (void)format; +#endif +} + +void metal_set_log_handler(metal_log_handler handler) +{ + _metal.common.log_handler = handler; +} + +metal_log_handler metal_get_log_handler(void) +{ + return _metal.common.log_handler; +} + +void metal_set_log_level(enum metal_log_level level) +{ + _metal.common.log_level = level; +} + +enum metal_log_level metal_get_log_level(void) +{ + return _metal.common.log_level; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/shmem.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/shmem.c new file mode 100644 index 0000000000..5ead8e755d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/shmem.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/shmem.c + * @brief Generic libmetal shared memory handling. + */ + +#include +#include +#include +#include +#include + +int metal_shmem_register_generic(struct metal_generic_shmem *shmem) +{ + /* Make sure that we can be found. */ + metal_assert(shmem->name && strlen(shmem->name) != 0); + + /* Statically registered shmem regions cannot have a destructor. */ + metal_assert(!shmem->io.ops.close); + + metal_list_add_tail(&_metal.common.generic_shmem_list, + &shmem->node); + return 0; +} + +int metal_shmem_open_generic(const char *name, size_t size, + struct metal_io_region **result) +{ + struct metal_generic_shmem *shmem; + struct metal_list *node; + + metal_list_for_each(&_metal.common.generic_shmem_list, node) { + shmem = metal_container_of(node, struct metal_generic_shmem, node); + if (strcmp(shmem->name, name) != 0) + continue; + if (size > metal_io_region_size(&shmem->io)) + continue; + *result = &shmem->io; + return 0; + } + + return -ENOENT; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/st_device.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/st_device.c new file mode 100644 index 0000000000..a3bc12caf3 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/st_device.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int metal_bus_register(struct metal_bus *bus) +{ + if (!bus || !bus->name || !strlen(bus->name)) + return -EINVAL; + if (metal_bus_find(bus->name, NULL) == 0) + return -EEXIST; + metal_list_init(&bus->devices); + metal_list_add_tail(&_metal.common.bus_list, &bus->node); + metal_log(METAL_LOG_DEBUG, "registered %s bus\n", bus->name); + return 0; +} + +int metal_bus_unregister(struct metal_bus *bus) +{ + metal_list_del(&bus->node); + if (bus->ops.bus_close) + bus->ops.bus_close(bus); + metal_log(METAL_LOG_DEBUG, "unregistered %s bus\n", bus->name); + return 0; +} + +int metal_bus_find(const char *name, struct metal_bus **result) +{ + struct metal_list *node; + struct metal_bus *bus; + + metal_list_for_each(&_metal.common.bus_list, node) { + bus = metal_container_of(node, struct metal_bus, node); + if (strcmp(bus->name, name) != 0) + continue; + if (result) + *result = bus; + return 0; + } + return -ENOENT; +} + +int metal_device_open(const char *bus_name, const char *dev_name, + struct metal_device **device) +{ + struct metal_bus *bus; + int error; + + if (!bus_name || !strlen(bus_name) || + !dev_name || !strlen(dev_name) || + !device) + return -EINVAL; + + error = metal_bus_find(bus_name, &bus); + if (error) + return error; + + if (!bus->ops.dev_open) + return -ENODEV; + + error = (*bus->ops.dev_open)(bus, dev_name, device); + if (error) + return error; + + return 0; +} + +void metal_device_close(struct metal_device *device) +{ + metal_assert(device && device->bus); + if (device->bus->ops.dev_close) + device->bus->ops.dev_close(device->bus, device); +} + +int metal_register_generic_device(struct metal_device *device) +{ + if (!device->name || !strlen(device->name) || + device->num_regions > METAL_MAX_DEVICE_REGIONS) + return -EINVAL; + + device->bus = &metal_generic_bus; + metal_list_add_tail(&_metal.common.generic_device_list, + &device->node); + return 0; +} + +int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name, + struct metal_device **device) +{ + struct metal_list *node; + struct metal_device *dev; + + (void)bus; + + metal_list_for_each(&_metal.common.generic_device_list, node) { + dev = metal_container_of(node, struct metal_device, node); + if (strcmp(dev->name, dev_name) != 0) + continue; + *device = dev; + return metal_generic_dev_sys_open(dev); + } + + return -ENODEV; +} + +int metal_generic_dev_dma_map(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out) +{ + (void)bus; + (void)device; + int i; + + if (sg_out != sg_in) + memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg))); + for (i = 0; i < nents_in; i++) { + if (dir == METAL_DMA_DEV_W) { + metal_cache_flush(sg_out[i].virt, sg_out[i].len); + } + metal_cache_invalidate(sg_out[i].virt, sg_out[i].len); + } + + return nents_in; +} + +void metal_generic_dev_dma_unmap(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg, + int nents) +{ + (void)bus; + (void)device; + (void)dir; + int i; + + for (i = 0; i < nents; i++) { + metal_cache_invalidate(sg[i].virt, sg[i].len); + } +} + +struct metal_bus metal_weak metal_generic_bus = { + .name = "generic", + .ops = { + .bus_close = NULL, + .dev_open = metal_generic_dev_open, + .dev_close = NULL, + .dev_irq_ack = NULL, + .dev_dma_map = metal_generic_dev_dma_map, + .dev_dma_unmap = metal_generic_dev_dma_unmap, + }, +}; diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/alloc.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/alloc.h new file mode 100644 index 0000000000..bcceba61a0 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/alloc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/alloc.c + * @brief generic libmetal memory allocattion definitions. + */ + +#ifndef __METAL_ALLOC__H__ +#error "Include metal/alloc.h instead of metal/generic/alloc.h" +#endif + +#ifndef __METAL_GENERIC_ALLOC__H__ +#define __METAL_GENERIC_ALLOC__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void *metal_allocate_memory(unsigned int size) +{ + return (malloc(size)); +} + +static inline void metal_free_memory(void *ptr) +{ + free(ptr); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_ALLOC__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/assert.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/assert.h new file mode 100644 index 0000000000..97f88ee5a5 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/assert.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file assert.h + * @brief Generic assertion support. + */ + +#ifndef __METAL_ASSERT__H__ +#error "Include metal/assert.h instead of metal/generic/assert.h" +#endif + +#ifndef __METAL_GENERIC_ASSERT__H__ +#define __METAL_GENERIC_ASSERT__H__ + +#include + +/** + * @brief Assertion macro for bare-metal applications. + * @param cond Condition to evaluate. + */ +#define metal_sys_assert(cond) assert(cond) + +#endif /* __METAL_GENERIC_ASSERT__H__ */ + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cache.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cache.h new file mode 100644 index 0000000000..962ffccfa9 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cache.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/cache.h + * @brief generic cache operation primitives for libmetal. + */ + +#ifndef __METAL_CACHE__H__ +#error "Include metal/cache.h instead of metal/generic/cache.h" +#endif + +#ifndef __METAL_GENERIC_CACHE__H__ +#define __METAL_GENERIC_CACHE__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void metal_machine_cache_flush(void *addr, unsigned int len); +extern void metal_machine_cache_invalidate(void *addr, unsigned int len); + +static inline void __metal_cache_flush(void *addr, unsigned int len) +{ + metal_machine_cache_flush(addr, len); +} + +static inline void __metal_cache_invalidate(void *addr, unsigned int len) +{ + metal_machine_cache_invalidate(addr, len); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_CACHE__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.c new file mode 100644 index 0000000000..493af6fc23 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/condition.c + * @brief Generic libmetal condition variable handling. + */ + +#include +#include + +extern void metal_generic_default_poll(void); + +int metal_condition_wait(struct metal_condition *cv, + metal_mutex_t *m) +{ + metal_mutex_t *tmpm = 0; + int v; + unsigned int flags; + + /* Check if the mutex has been acquired */ + if (!cv || !m || !metal_mutex_is_acquired(m)) + return -EINVAL; + + if (!atomic_compare_exchange_strong(&cv->m->v, &tmpm->v, m->v)) { + if (m != tmpm) + return -EINVAL; + } + + v = atomic_load(&cv->v); + + /* Release the mutex first. */ + metal_mutex_release(m); + do { + flags = metal_irq_save_disable(); + if (atomic_load(&cv->v) != v) { + metal_irq_restore_enable(flags); + break; + } + metal_generic_default_poll(); + metal_irq_restore_enable(flags); + } while(1); + /* Acquire the mutex again. */ + metal_mutex_acquire(m); + return 0; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.h new file mode 100644 index 0000000000..abb2e8c73c --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/condition.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/condition.h + * @brief Generic condition variable primitives for libmetal. + */ + +#ifndef __METAL_CONDITION__H__ +#error "Include metal/condition.h instead of metal/generic/condition.h" +#endif + +#ifndef __METAL_GENERIC_CONDITION__H__ +#define __METAL_GENERIC_CONDITION__H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct metal_condition { + metal_mutex_t *m; /**< mutex. + The condition variable is attached to + this mutex when it is waiting. + It is also used to check correctness + in case there are multiple waiters. */ + + atomic_int v; /**< condition variable value. */ +}; + +/** Static metal condition variable initialization. */ +#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0) } + +static inline void metal_condition_init(struct metal_condition *cv) +{ + cv->m = NULL; + atomic_init(&cv->v, 0); +} + +static inline int metal_condition_signal(struct metal_condition *cv) +{ + if (!cv) + return -EINVAL; + + /** wake up waiters if there are any. */ + atomic_fetch_add(&cv->v, 1); + return 0; +} + +static inline int metal_condition_broadcast(struct metal_condition *cv) +{ + return metal_condition_signal(cv); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_CONDITION__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.c new file mode 100644 index 0000000000..7b0b3856fe --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. 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 Xilinx 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 generic/sys.c + * @brief machine specific system primitives implementation. + */ + + +#include "metal/io.h" +#include "metal/sys.h" + +void sys_irq_restore_enable(unsigned int flags) +{ +} + +unsigned int sys_irq_save_disable(void) +{ + return 0; +} + +void metal_machine_cache_flush(void *addr, unsigned int len) +{ + (void)addr; + (void)len; +} + +void metal_machine_cache_invalidate(void *addr, unsigned int len) +{ + (void)addr; + (void)len; +} + +/** + * @brief poll function until some event happens + */ +void __attribute__((weak)) metal_generic_default_poll(void) +{ +} + +void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa, + size_t size, unsigned int flags) +{ + (void)va; + (void)pa; + (void)size; + (void)flags; + + return va; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.h new file mode 100644 index 0000000000..7fd8144cbf --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/cortexm/sys.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. 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 Xilinx 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 generic/mp1_m4/sys.h + * @brief generic mp1_m4 system primitives for libmetal. + */ + +#ifndef __METAL_GENERIC_SYS__H__ +#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" +#endif + +#ifndef __METAL_GENERIC_MP1_M4_SYS__H__ +#define __METAL_GENERIC_MP1_M4_SYS__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MAX_IRQS) +#define MAX_IRQS 8 /**< maximum number of irqs */ +#endif + +static inline void sys_irq_enable(unsigned int vector) +{ + (void)vector; +} + +static inline void sys_irq_disable(unsigned int vector) +{ + (void)vector; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_MP1_M4_SYS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_device.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_device.c new file mode 100644 index 0000000000..d01fd3cd75 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_device.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/device.c + * @brief Generic libmetal device operations. + */ + +#include +#include +#include +#include + +int metal_generic_dev_sys_open(struct metal_device *dev) +{ + struct metal_io_region *io; + unsigned i; + + /* map I/O memory regions */ + for (i = 0; i < dev->num_regions; i++) { + io = &dev->regions[i]; + if (!io->size) + break; + metal_sys_io_mem_map(io); + } + + return 0; +} + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_init.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_init.c new file mode 100644 index 0000000000..833b1cd341 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_init.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/init.c + * @brief Generic libmetal initialization. + */ + +#include +#include +#include + +struct metal_state _metal; + +int metal_sys_init(const struct metal_init_params *params) +{ + metal_unused(params); + metal_bus_register(&metal_generic_bus); + return 0; +} + +void metal_sys_finish(void) +{ + metal_bus_unregister(&metal_generic_bus); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_io.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_io.c new file mode 100644 index 0000000000..670f239d5a --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_io.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/io.c + * @brief Generic libmetal io operations + */ + +#include + +void metal_sys_io_mem_map(struct metal_io_region *io) +{ + unsigned long p; + size_t psize; + size_t *va; + + va = (size_t *)io->virt; + psize = io->size; + if (psize) { + if (psize >> io->page_shift) + psize = (size_t)1 << io->page_shift; + for (p = 0; p <= (io->size >> io->page_shift); p++) { + metal_machine_io_mem_map(va, io->physmap[p], + psize, io->mem_flags); + va += psize; + } + } +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.c new file mode 100644 index 0000000000..e61bc7e836 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/irq.c + * @brief generic libmetal irq definitions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** IRQ handlers descriptor structure */ +struct metal_irq_hddesc { + metal_irq_handler hd; /**< irq handler */ + void *drv_id; /**< id to identify the driver + of the irq handler */ + struct metal_device *dev; /**< device identifier */ + struct metal_list node; /**< node on irq handlers list */ +}; + +/** IRQ descriptor structure */ +struct metal_irq_desc { + int irq; /**< interrupt number */ + struct metal_list hdls; /**< interrupt handlers */ + struct metal_list node; /**< node on irqs list */ +}; + +/** IRQ state structure */ +struct metal_irqs_state { + struct metal_list irqs; /**< interrupt descriptors */ + metal_mutex_t irq_lock; /**< access lock */ +}; + +static struct metal_irqs_state _irqs = { + .irqs = METAL_INIT_LIST(_irqs.irqs), + .irq_lock = METAL_MUTEX_INIT(_irqs.irq_lock), +}; + +int metal_irq_register(int irq, + metal_irq_handler hd, + struct metal_device *dev, + void *drv_id) +{ + struct metal_irq_desc *irq_p = NULL; + struct metal_irq_hddesc *hdl_p; + struct metal_list *node; + unsigned int irq_flags_save; + + if (irq < 0) { + metal_log(METAL_LOG_ERROR, + "%s: irq %d need to be a positive number\n", + __func__, irq); + return -EINVAL; + } + + if ((drv_id == NULL) || (hd == NULL)) { + metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", + __func__, irq); + return -EINVAL; + } + + /* Search for irq in list */ + metal_mutex_acquire(&_irqs.irq_lock); + metal_list_for_each(&_irqs.irqs, node) { + irq_p = metal_container_of(node, struct metal_irq_desc, node); + + if (irq_p->irq == irq) { + struct metal_list *h_node; + + /* Check if drv_id already exist */ + metal_list_for_each(&irq_p->hdls, h_node) { + hdl_p = metal_container_of(h_node, + struct metal_irq_hddesc, + node); + + /* if drv_id already exist reject */ + if ((hdl_p->drv_id == drv_id) && + ((dev == NULL) || (hdl_p->dev == dev))) { + metal_log(METAL_LOG_ERROR, + "%s: irq %d already registered." + "Will not register again.\n", + __func__, irq); + metal_mutex_release(&_irqs.irq_lock); + return -EINVAL; + } + } + /* irq found and drv_id not used, get out of metal_list_for_each */ + break; + } + } + + /* Either need to add handler to an existing list or to a new one */ + hdl_p = metal_allocate_memory(sizeof(struct metal_irq_hddesc)); + if (hdl_p == NULL) { + metal_log(METAL_LOG_ERROR, + "%s: irq %d cannot allocate mem for drv_id %d.\n", + __func__, irq, drv_id); + metal_mutex_release(&_irqs.irq_lock); + return -ENOMEM; + } + hdl_p->hd = hd; + hdl_p->drv_id = drv_id; + hdl_p->dev = dev; + + /* interrupt already registered, add handler to existing list*/ + if ((irq_p != NULL) && (irq_p->irq == irq)) { + irq_flags_save = metal_irq_save_disable(); + metal_list_add_tail(&irq_p->hdls, &hdl_p->node); + metal_irq_restore_enable(irq_flags_save); + + metal_log(METAL_LOG_DEBUG, "%s: success, irq %d add drv_id %p \n", + __func__, irq, drv_id); + metal_mutex_release(&_irqs.irq_lock); + return 0; + } + + /* interrupt was not already registered, add */ + irq_p = metal_allocate_memory(sizeof(struct metal_irq_desc)); + if (irq_p == NULL) { + metal_log(METAL_LOG_ERROR, "%s: irq %d cannot allocate mem.\n", + __func__, irq); + metal_mutex_release(&_irqs.irq_lock); + return -ENOMEM; + } + irq_p->irq = irq; + metal_list_init(&irq_p->hdls); + metal_list_add_tail(&irq_p->hdls, &hdl_p->node); + + irq_flags_save = metal_irq_save_disable(); + metal_list_add_tail(&_irqs.irqs, &irq_p->node); + metal_irq_restore_enable(irq_flags_save); + + metal_log(METAL_LOG_DEBUG, "%s: success, added irq %d\n", __func__, irq); + metal_mutex_release(&_irqs.irq_lock); + return 0; +} + +/* helper function for metal_irq_unregister() */ +static void metal_irq_delete_node(struct metal_list *node, void *p_to_free) +{ + unsigned int irq_flags_save; + + irq_flags_save=metal_irq_save_disable(); + metal_list_del(node); + metal_irq_restore_enable(irq_flags_save); + metal_free_memory(p_to_free); +} + +int metal_irq_unregister(int irq, + metal_irq_handler hd, + struct metal_device *dev, + void *drv_id) +{ + struct metal_irq_desc *irq_p; + struct metal_list *node; + + if (irq < 0) { + metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n", + __func__, irq); + return -EINVAL; + } + + /* Search for irq in list */ + metal_mutex_acquire(&_irqs.irq_lock); + metal_list_for_each(&_irqs.irqs, node) { + + irq_p = metal_container_of(node, struct metal_irq_desc, node); + + if (irq_p->irq == irq) { + struct metal_list *h_node, *h_prenode; + struct metal_irq_hddesc *hdl_p; + unsigned int delete_count = 0; + + metal_log(METAL_LOG_DEBUG, "%s: found irq %d\n", + __func__, irq); + + /* Search through handlers */ + metal_list_for_each(&irq_p->hdls, h_node) { + hdl_p = metal_container_of(h_node, + struct metal_irq_hddesc, + node); + + if (((hd == NULL) || (hdl_p->hd == hd)) && + ((drv_id == NULL) || (hdl_p->drv_id == drv_id)) && + ((dev == NULL) || (hdl_p->dev == dev))) { + metal_log(METAL_LOG_DEBUG, + "%s: unregister hd=%p drv_id=%p dev=%p\n", + __func__, hdl_p->hd, hdl_p->drv_id, hdl_p->dev); + h_prenode = h_node->prev; + metal_irq_delete_node(h_node, hdl_p); + h_node = h_prenode; + delete_count++; + } + } + + /* we did not find any handler to delete */ + if (!delete_count) { + metal_log(METAL_LOG_DEBUG, "%s: No matching entry\n", + __func__); + metal_mutex_release(&_irqs.irq_lock); + return -ENOENT; + + } + + /* if interrupt handlers list is empty, unregister interrupt */ + if (metal_list_is_empty(&irq_p->hdls)) { + metal_log(METAL_LOG_DEBUG, + "%s: handlers list empty, unregister interrupt\n", + __func__); + metal_irq_delete_node(node, irq_p); + } + + metal_log(METAL_LOG_DEBUG, "%s: success\n", __func__); + + metal_mutex_release(&_irqs.irq_lock); + return 0; + } + } + + metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__); + + metal_mutex_release(&_irqs.irq_lock); + return -ENOENT; +} + +unsigned int metal_irq_save_disable(void) +{ + return sys_irq_save_disable(); +} + +void metal_irq_restore_enable(unsigned int flags) +{ + sys_irq_restore_enable(flags); +} + +void metal_irq_enable(unsigned int vector) +{ + sys_irq_enable(vector); +} + +void metal_irq_disable(unsigned int vector) +{ + sys_irq_disable(vector); +} + +/** + * @brief default handler + */ +void metal_irq_isr(unsigned int vector) +{ + struct metal_list *node; + struct metal_irq_desc *irq_p; + + metal_list_for_each(&_irqs.irqs, node) { + irq_p = metal_container_of(node, struct metal_irq_desc, node); + + if ((unsigned int)irq_p->irq == vector) { + struct metal_list *h_node; + struct metal_irq_hddesc *hdl_p; + + metal_list_for_each(&irq_p->hdls, h_node) { + hdl_p = metal_container_of(h_node, + struct metal_irq_hddesc, + node); + + (hdl_p->hd)(vector, hdl_p->drv_id); + } + } + } +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.h new file mode 100644 index 0000000000..5744275dc6 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_irq.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/irq.c + * @brief Generic libmetal irq definitions. + */ + +#ifndef __METAL_IRQ__H__ +#error "Include metal/irq.h instead of metal/generic/irq.h" +#endif + +#ifndef __METAL_GENERIC_IRQ__H__ +#define __METAL_GENERIC_IRQ__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief default interrupt handler + * @param[in] vector interrupt vector + */ +void metal_irq_isr(unsigned int vector); + + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_IRQ__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_shmem.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_shmem.c new file mode 100644 index 0000000000..8a28d8ae19 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_shmem.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/shmem.c + * @brief Generic libmetal shared memory handling. + */ + +#include + +int metal_shmem_open(const char *name, size_t size, + struct metal_io_region **io) +{ + return metal_shmem_open_generic(name, size, io); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_time.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_time.c new file mode 100644 index 0000000000..fff76192aa --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/generic_time.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/time.c + * @brief Generic libmetal time handling. + */ + +#include + +unsigned long long metal_get_timestamp(void) +{ + /* TODO: Implement timestamp for generic system */ + return 0; +} + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/io.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/io.h new file mode 100644 index 0000000000..adbbc44774 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/io.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/io.h + * @brief Generic specific io definitions. + */ + +#ifndef __METAL_IO__H__ +#error "Include metal/io.h instead of metal/generic/io.h" +#endif + +#ifndef __METAL_GENERIC_IO__H__ +#define __METAL_GENERIC_IO__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef METAL_INTERNAL + +/** + * @brief memory mapping for an I/O region + */ +void metal_sys_io_mem_map(struct metal_io_region *io); + +/** + * @brief memory mapping + */ +void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa, + size_t size, unsigned int flags); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_IO__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/log.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/log.h new file mode 100644 index 0000000000..32611288ad --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/log.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * 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 Linaro 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 generic/log.h + * @brief Generic libmetal log handler definition. + */ + +#ifndef __METAL_METAL_LOG__H__ +#error "Include metal/log.h instead of metal/generic/log.h" +#endif + +#ifndef __METAL_GENERIC_LOG__H__ +#define __METAL_GENERIC_LOG__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_LOG__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/mutex.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/mutex.h new file mode 100644 index 0000000000..3613c194d1 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/mutex.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/mutex.h + * @brief Generic mutex primitives for libmetal. + */ + +#ifndef __METAL_MUTEX__H__ +#error "Include metal/mutex.h instead of metal/generic/mutex.h" +#endif + +#ifndef __METAL_GENERIC_MUTEX__H__ +#define __METAL_GENERIC_MUTEX__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + union{ + atomic_int v; + atomic_flag w; + }; +} metal_mutex_t; + +/* + * METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct + * or global + */ +#define METAL_MUTEX_INIT(m) { ATOMIC_VAR_INIT(0) } +/* + * METAL_MUTEX_DEFINE - used for defining and initializing a global or + * static singleton mutex + */ +#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = METAL_MUTEX_INIT(m) + +static inline void __metal_mutex_init(metal_mutex_t *mutex) +{ + atomic_store(&mutex->v, 0); +} + +static inline void __metal_mutex_deinit(metal_mutex_t *mutex) +{ + (void)mutex; +} + +static inline int __metal_mutex_try_acquire(metal_mutex_t *mutex) +{ + return 1 - atomic_flag_test_and_set(&mutex->w); +} + +static inline void __metal_mutex_acquire(metal_mutex_t *mutex) +{ + while (atomic_flag_test_and_set(&mutex->w)) { + ; + } +} + +static inline void __metal_mutex_release(metal_mutex_t *mutex) +{ + atomic_flag_clear(&mutex->w); +} + +static inline int __metal_mutex_is_acquired(metal_mutex_t *mutex) +{ + return atomic_load(&mutex->v); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_MUTEX__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sleep.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sleep.h new file mode 100644 index 0000000000..aa86df492e --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sleep.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/sleep.h + * @brief Generic sleep primitives for libmetal. + */ + +#ifndef __METAL_SLEEP__H__ +#error "Include metal/sleep.h instead of metal/generic/sleep.h" +#endif + +#ifndef __METAL_GENERIC_SLEEP__H__ +#define __METAL_GENERIC_SLEEP__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int __metal_sleep_usec(unsigned int usec) +{ + metal_unused(usec); + /* Fix me */ + return 0; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_SLEEP__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sys.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sys.h new file mode 100644 index 0000000000..320af6b0b7 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/system/generic/sys.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/sys.h + * @brief Generic system primitives for libmetal. + */ + +#ifndef __METAL_SYS__H__ +#error "Include metal/sys.h instead of metal/generic/sys.h" +#endif + +#ifndef __METAL_GENERIC_SYS__H__ +#define __METAL_GENERIC_SYS__H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "./@PROJECT_MACHINE@/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef METAL_MAX_DEVICE_REGIONS +#define METAL_MAX_DEVICE_REGIONS 1 +#endif + +/** Structure of generic libmetal runtime state. */ +struct metal_state { + + /** Common (system independent) data. */ + struct metal_common_state common; +}; + +#ifdef METAL_INTERNAL + +/** + * @brief restore interrupts to state before disable_global_interrupt() + */ +void sys_irq_restore_enable(unsigned int flags); + +/** + * @brief disable all interrupts + */ +unsigned int sys_irq_save_disable(void); + +#endif /* METAL_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_SYS__H__ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/version.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/version.c new file mode 100644 index 0000000000..9595a85f37 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/libmetal/lib/version.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +int metal_ver_major(void) +{ + return METAL_VER_MAJOR; +} + +int metal_ver_minor(void) +{ + return METAL_VER_MINOR; +} + +int metal_ver_patch(void) +{ + return METAL_VER_PATCH; +} + +const char *metal_ver(void) +{ + return METAL_VER; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/compiler.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/compiler.h new file mode 100644 index 0000000000..acb4c9b369 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/compiler.h @@ -0,0 +1,71 @@ +#ifndef _COMPILER_H_ +#define _COMPILER_H_ + +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/************************************************************************** + * FILE NAME + * + * compiler.h + * + * DESCRIPTION + * + * This file defines compiler-specific macros. + * + ***************************************************************************/ +#if defined __cplusplus +extern "C" { +#endif + +/* IAR ARM build tools */ +#if defined(__ICCARM__) + +#ifndef OPENAMP_PACKED_BEGIN +#define OPENAMP_PACKED_BEGIN __packed +#endif + +#ifndef OPENAMP_PACKED_END +#define OPENAMP_PACKED_END +#endif + +/* GNUC */ +#elif defined(__GNUC__) + +#ifndef OPENAMP_PACKED_BEGIN +#define OPENAMP_PACKED_BEGIN +#endif + +#ifndef OPENAMP_PACKED_END +#define OPENAMP_PACKED_END __attribute__((__packed__)) +#endif + +/* ARM GCC */ +#elif defined(__CC_ARM) + +#ifndef OPENAMP_PACKED_BEGIN +#define OPENAMP_PACKED_BEGIN _Pragma("pack(1U)") +#endif + +#ifndef OPENAMP_PACKED_END +#define OPENAMP_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 + +#if defined __cplusplus +} +#endif + +#endif /* _COMPILER_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/elf_loader.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/elf_loader.h new file mode 100644 index 0000000000..3c6ec4af15 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/elf_loader.h @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ELF_LOADER_H_ +#define ELF_LOADER_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* ELF32 base types - 32-bit. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* ELF64 base types - 64-bit. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Size of ELF identifier field in the ELF file header. */ +#define EI_NIDENT 16 + +/* ELF32 file header */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +/* ELF64 file header */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* e_ident */ +#define ET_NONE 0 +#define ET_REL 1 /* Re-locatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOOS 0xfe00 /* Operating system-specific */ +#define ET_HIOS 0xfeff /* Operating system-specific */ +#define ET_LOPROC 0xff00 /* remote_proc-specific */ +#define ET_HIPROC 0xffff /* remote_proc-specific */ + +/* e_machine */ +#define EM_ARM 40 /* ARM/Thumb Architecture */ + +/* e_version */ +#define EV_CURRENT 1 /* Current version */ + +/* e_ident[] Identification Indexes */ +#define EI_MAG0 0 /* File identification */ +#define EI_MAG1 1 /* File identification */ +#define EI_MAG2 2 /* File identification */ +#define EI_MAG3 3 /* File identification */ +#define EI_CLASS 4 /* File class */ +#define EI_DATA 5 /* Data encoding */ +#define EI_VERSION 6 /* File version */ +#define EI_OSABI 7 /* Operating system/ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* Start of padding bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* + * EI_MAG0 to EI_MAG3 - A file's first 4 bytes hold amagic number, identifying + * the file as an ELF object file + */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +/* + * EI_CLASS - The next byte, e_ident[EI_CLASS], identifies the file's class, or + * capacity. + */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +/* + * EI_DATA - Byte e_ident[EI_DATA] specifies the data encoding of the + * remote_proc-specific data in the object file. The following encodings are + * currently defined. + */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* See Data encodings, below */ +#define ELFDATA2MSB 2 /* See Data encodings, below */ + +/* EI_OSABI - We do not define an OS specific ABI */ +#define ELFOSABI_NONE 0 + +/* ELF32 program header */ +typedef struct elf32_phdr{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* ELF64 program header */ +typedef struct elf64_phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +/* segment types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* ELF32 section header. */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +/* ELF64 section header. */ +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* Relocation entry (without addend) */ +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + +} Elf64_Rel; + +/* Relocation entry with addend */ +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; + +} Elf32_Rela; + +typedef struct elf64_rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +/* Macros to extract information from 'r_info' field of relocation entries */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + +/* Symbol table entry */ +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; + +} Elf32_Sym; + +typedef struct elf64_sym { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +/* ARM specific dynamic relocation codes */ +#define R_ARM_GLOB_DAT 21 /* 0x15 */ +#define R_ARM_JUMP_SLOT 22 /* 0x16 */ +#define R_ARM_RELATIVE 23 /* 0x17 */ +#define R_ARM_ABS32 2 /* 0x02 */ + +/* ELF decoding information */ +struct elf32_info { + Elf32_Ehdr ehdr; + unsigned int load_state; + Elf32_Phdr *phdrs; + Elf32_Shdr *shdrs; + void *shstrtab; +}; + +struct elf64_info { + Elf64_Ehdr ehdr; + unsigned int load_state; + Elf64_Phdr *phdrs; + Elf64_Shdr *shdrs; + void *shstrtab; +}; + +#define ELF_STATE_INIT 0x0UL +#define ELF_STATE_WAIT_FOR_PHDRS 0x100UL +#define ELF_STATE_WAIT_FOR_SHDRS 0x200UL +#define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400UL +#define ELF_STATE_HDRS_COMPLETE 0x800UL +#define ELF_STATE_MASK 0xFF00UL +#define ELF_NEXT_SEGMENT_MASK 0x00FFUL + +extern struct loader_ops elf_ops; + +/** + * elf_identify - check if it is an ELF file + * + * It will check if the input image header is an ELF header. + * + * @img_data: firmware private data which will be passed to user defined loader + * operations + * @len: firmware header length + * + * return 0 for success or negative value for failure. + */ +int elf_identify(const void *img_data, size_t len); + +/** + * elf_load_header - Load ELF headers + * + * It will get the ELF header, the program header, and the section header. + * + * @img_data: image data + * @offset: input image data offset to the start of image file + * @len: input image data length + * @img_info: pointer to store image information data + * @last_load_state: last state return by this function + * @noffset: pointer to next offset required by loading ELF header + * @nlen: pointer to next data length required by loading ELF header + * + * return ELF loading header state, or negative value for failure + */ +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen); + +/** + * elf_load - load ELF data + * + * It will parse the ELF image and return the target device address, + * offset to the start of the ELF image of the data to load and the + * length of the data to load. + * + * @rproc: pointer to remoteproc instance + * @img_data: image data which will passed to the function. + * it can be NULL, if image data doesn't need to be handled + * by the load function. E.g. binary data which was + * loaded to the target memory. + * @offset: last loaded image data offset to the start of image file + * @len: last loaded image data length + * @img_info: pointer to store image information data + * @last_load_state: the returned state of the last function call. + * @da: target device address, if the data to load is not for target memory + * the da will be set to ANY. + * @noffset: pointer to next offset required by loading ELF header + * @nlen: pointer to next data length required by loading ELF header + * @padding: value to pad it is possible that a size of a segment in memory + * is larger than what it is in the ELF image. e.g. a segment + * can have stack section .bss. It doesn't need to copy image file + * space, in this case, it will be packed with 0. + * @nmemsize: pointer to next data target memory size. The size of a segment + * in the target memory can be larger than the its size in the + * image file. + * + * return 0 for success, otherwise negative value for failure + */ +int elf_load(struct remoteproc *rproc, const void *img_data, + size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + +/** + * elf_release - Release ELF image information + * + * It will release ELF image information data. + * + * @img_info: pointer to ELF image information + */ +void elf_release(void *img_info); + +/** + * elf_get_entry - Get entry point + * + * It will return entry point specified in the ELF file. + * + * @img_info: pointer to ELF image information + * + * return entry address + */ +metal_phys_addr_t elf_get_entry(void *img_info); + +/** + * elf_locate_rsc_table - locate the resource table information + * + * It will return the length of the resource table, and the device address of + * the resource table. + * + * @img_info: pointer to ELF image information + * @da: pointer to the device address + * @offset: pointer to the offset to in the ELF image of the resource + * table section. + * @size: pointer to the size of the resource table section. + * + * return 0 if successfully locate the resource table, negative value for + * failure. + */ +int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); + +#if defined __cplusplus +} +#endif + +#endif /* ELF_LOADER_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/open_amp.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/open_amp.h new file mode 100644 index 0000000000..1a01688a9f --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/open_amp.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef OPEN_AMP_H_ +#define OPEN_AMP_H_ + +#include +#include +#include +#include + + +#endif /* OPEN_AMP_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc.h new file mode 100644 index 0000000000..90d908729c --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc.h @@ -0,0 +1,871 @@ +/* + * Remoteproc Framework + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef REMOTEPROC_H +#define REMOTEPROC_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define RSC_NOTIFY_ID_ANY 0xFFFFFFFFUL + +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote remote_proc. It may also include configuration entries. + * If needed, the remote remote_proc firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves, + * each of which begins with a resource entry header (as described below). + */ +OPENAMP_PACKED_BEGIN +struct resource_table { + uint32_t ver; + uint32_t num; + uint32_t reserved[2]; + uint32_t offset[0]; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_hdr - firmware resource entry header + * @type: resource type + * @data: resource data + * + * Every resource entry begins with a 'struct fw_rsc_hdr' header providing + * its @type. The content of the entry itself will immediately follow + * this header, and it should be parsed according to the resource type. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_hdr { + uint32_t type; + uint8_t data[0]; +} OPENAMP_PACKED_END; + +/** + * enum fw_resource_type - types of resource entries + * + * @RSC_CARVEOUT: request for allocation of a physically contiguous + * memory region. + * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. + * @RSC_TRACE: announces the availability of a trace buffer into which + * the remote remote_proc will be writing logs. + * @RSC_VDEV: declare support for a virtio device, and serve as its + * virtio header. + * @RSC_VENDOR_START: start of the vendor specific resource types range + * @RSC_VENDOR_END : end of the vendor specific resource types range + * @RSC_LAST: just keep this one at the end + * + * For more details regarding a specific resource type, please see its + * dedicated structure below. + * + * Please note that these values are used as indices to the rproc_handle_rsc + * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to + * check the validity of an index before the lookup table is accessed, so + * please update it as needed. + */ +enum fw_resource_type { + RSC_CARVEOUT = 0, + RSC_DEVMEM = 1, + RSC_TRACE = 2, + RSC_VDEV = 3, + RSC_RPROC_MEM = 4, + RSC_FW_CHKSUM = 5, + RSC_LAST = 6, + RSC_VENDOR_START = 128, + RSC_VENDOR_END = 512, +}; + +#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) +#define FW_RSC_U32_ADDR_ANY (0xFFFFFFFF) + +/** + * struct fw_rsc_carveout - physically contiguous memory request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested memory region + * + * This resource entry requests the host to allocate a physically contiguous + * memory region. + * + * These request entries should precede other firmware resource entries, + * as other entries might request placing other data objects inside + * these memory regions (e.g. data/code segments, trace resource entries, ...). + * + * Allocating memory this way helps utilizing the reserved physical memory + * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries + * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB + * pressure is important; it may have a substantial impact on performance. + * + * If the firmware is compiled with static addresses, then @da should specify + * the expected device address of this memory region. If @da is set to + * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then + * overwrite @da with the dynamically allocated address. + * + * We will always use @da to negotiate the device addresses, even if it + * isn't using an iommu. In that case, though, it will obviously contain + * physical addresses. + * + * Some remote remote_procs needs to know the allocated physical address + * even if they do use an iommu. This is needed, e.g., if they control + * hardware accelerators which access the physical memory directly (this + * is the case with OMAP4 for instance). In that case, the host will + * overwrite @pa with the dynamically allocated physical address. + * Generally we don't want to expose physical addresses if we don't have to + * (remote remote_procs are generally _not_ trusted), so we might want to + * change this to happen _only_ when explicitly required by the hardware. + * + * @flags is used to provide IOMMU protection flags, and @name should + * (optionally) contain a human readable name of this carveout region + * (mainly for debugging purposes). + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_carveout { + uint32_t type; + uint32_t da; + uint32_t pa; + uint32_t len; + uint32_t flags; + uint32_t reserved; + uint8_t name[32]; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_devmem - iommu mapping request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested region to be mapped + * + * This resource entry requests the host to iommu map a physically contiguous + * memory region. This is needed in case the remote remote_proc requires + * access to certain memory-based peripherals; _never_ use it to access + * regular memory. + * + * This is obviously only needed if the remote remote_proc is accessing memory + * via an iommu. + * + * @da should specify the required device address, @pa should specify + * the physical address we want to map, @len should specify the size of + * the mapping and @flags is the IOMMU protection flags. As always, @name may + * (optionally) contain a human readable name of this mapping (mainly for + * debugging purposes). + * + * Note: at this point we just "trust" those devmem entries to contain valid + * physical addresses, but this isn't safe and will be changed: eventually we + * want remoteproc implementations to provide us ranges of physical addresses + * the firmware is allowed to request, and not allow firmwares to request + * access to physical addresses that are outside those ranges. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_devmem { + uint32_t type; + uint32_t da; + uint32_t pa; + uint32_t len; + uint32_t flags; + uint32_t reserved; + uint8_t name[32]; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_trace - trace buffer declaration + * @da: device address + * @len: length (in bytes) + * @reserved: reserved (must be zero) + * @name: human-readable name of the trace buffer + * + * This resource entry provides the host information about a trace buffer + * into which the remote remote_proc will write log messages. + * + * @da specifies the device address of the buffer, @len specifies + * its size, and @name may contain a human readable name of the trace buffer. + * + * After booting the remote remote_proc, the trace buffers are exposed to the + * user via debugfs entries (called trace0, trace1, etc..). + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_trace { + uint32_t type; + uint32_t da; + uint32_t len; + uint32_t reserved; + uint8_t name[32]; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_vdev_vring - vring descriptor entry + * @da: device address + * @align: the alignment between the consumer and producer parts of the vring + * @num: num of buffers supported by this vring (must be power of two) + * @notifyid is a unique rproc-wide notify index for this vring. This notify + * index is used when kicking a remote remote_proc, to let it know that this + * vring is triggered. + * @reserved: reserved (must be zero) + * + * This descriptor is not a resource entry by itself; it is part of the + * vdev resource type (see below). + * + * Note that @da should either contain the device address where + * the remote remote_proc is expecting the vring, or indicate that + * dynamically allocation of the vring's device address is supported. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_vdev_vring { + uint32_t da; + uint32_t align; + uint32_t num; + uint32_t notifyid; + uint32_t reserved; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_vdev - virtio device header + * @id: virtio device id (as in virtio_ids.h) + * @notifyid is a unique rproc-wide notify index for this vdev. This notify + * index is used when kicking a remote remote_proc, to let it know that the + * status/features of this vdev have changes. + * @dfeatures specifies the virtio device features supported by the firmware + * @gfeatures is a place holder used by the host to write back the + * negotiated features that are supported by both sides. + * @config_len is the size of the virtio config space of this vdev. The config + * space lies in the resource table immediate after this vdev header. + * @status is a place holder where the host will indicate its virtio progress. + * @num_of_vrings indicates how many vrings are described in this vdev header + * @reserved: reserved (must be zero) + * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. + * + * This resource is a virtio device header: it provides information about + * the vdev, and is then used by the host and its peer remote remote_procs + * to negotiate and share certain virtio properties. + * + * By providing this resource entry, the firmware essentially asks remoteproc + * to statically allocate a vdev upon registration of the rproc (dynamic vdev + * allocation is not yet supported). + * + * Note: unlike virtualization systems, the term 'host' here means + * the Linux side which is running remoteproc to control the remote + * remote_procs. We use the name 'gfeatures' to comply with virtio's terms, + * though there isn't really any virtualized guest OS here: it's the host + * which is responsible for negotiating the final features. + * Yeah, it's a bit confusing. + * + * Note: immediately following this structure is the virtio config space for + * this vdev (which is specific to the vdev; for more info, read the virtio + * spec). the size of the config space is specified by @config_len. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_vdev { + uint32_t type; + uint32_t id; + uint32_t notifyid; + uint32_t dfeatures; + uint32_t gfeatures; + uint32_t config_len; + uint8_t status; + uint8_t num_of_vrings; + uint8_t reserved[2]; + struct fw_rsc_vdev_vring vring[0]; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_vendor - remote processor vendor specific resource + * @len: length of the resource + * + * This resource entry tells the host the vendor specific resource + * required by the remote. + * + * These request entries should precede other shared resource entries + * such as vdevs, vrings. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_vendor { + uint32_t type; + uint32_t len; +} OPENAMP_PACKED_END; + +/** + * struct fw_rsc_rproc_mem - remote processor memory + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @reserved: reserved (must be zero) + * + * This resource entry tells the host to the remote processor + * memory that the host can be used as shared memory. + * + * These request entries should precede other shared resource entries + * such as vdevs, vrings. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_rproc_mem { + uint32_t type; + uint32_t da; + uint32_t pa; + uint32_t len; + uint32_t reserved; +} OPENAMP_PACKED_END; + +/* + * struct fw_rsc_fw_chksum - firmware checksum + * @algo: algorithm to generate the cheksum + * @chksum: checksum of the firmware loadable sections. + * + * This resource entry provides checksum for the firmware loadable sections. + * It is used to check if the remote already runs with the expected firmware to + * decide if it needs to start the remote if the remote is already running. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_fw_chksum { + uint32_t type; + uint8_t algo[16]; + uint8_t chksum[64]; +} OPENAMP_PACKED_END; + +struct loader_ops; +struct image_store_ops; +struct remoteproc_ops; + +/** + * struct remoteproc_mem + * + * This structure presents the memory used by the remote processor + * + * @da: device memory + * @pa: physical memory + * @size: size of the memory + * @io: pointer to the I/O region + * @node: list node + */ +struct remoteproc_mem { + metal_phys_addr_t da; + metal_phys_addr_t pa; + size_t size; + char name[32]; + struct metal_io_region *io; + struct metal_list node; +}; + +/** + * struct remoteproc + * + * This structure is maintained by the remoteproc to represent the remote + * processor instance. This structure acts as a prime parameter to use + * the remoteproc APIs. + * + * @bootadd: boot address + * @loader: executable loader + * @lock: mutext lock + * @ops: remoteproc operations + * @rsc_table: pointer to resource table + * @rsc_len: length of resource table + * @rsc_io: metal I/O region of resource table + * @mems: remoteproc memories + * @vdevs: remoteproc virtio devices + * @bitmap: bitmap for notify IDs for remoteproc subdevices + * @state: remote processor state + * @priv: private data + */ +struct remoteproc { + metal_mutex_t lock; + void *rsc_table; + size_t rsc_len; + struct metal_io_region *rsc_io; + struct metal_list mems; + struct metal_list vdevs; + unsigned long bitmap; + struct remoteproc_ops *ops; + metal_phys_addr_t bootaddr; + struct loader_ops *loader; + unsigned int state; + void *priv; +}; + +/** + * struct remoteproc_ops + * + * remoteproc operations needs to be implemented by each remoteproc driver + * + * @init: initialize the remoteproc instance + * @remove: remove the remoteproc instance + * @mmap: memory mapped the mempory with physical address or destination + * address as input. + * @handle_rsc: handle the vendor specific resource + * @config: configure the remoteproc to make it ready to load and run + * executable + * @start: kick the remoteproc to run application + * @stop: stop the remoteproc from running application, the resource such as + * memory may not be off. + * @shutdown: shutdown the remoteproc and release its resources. + * @notify: notify the remote + */ +struct remoteproc_ops { + struct remoteproc *(*init)(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *arg); + void (*remove)(struct remoteproc *rproc); + void *(*mmap)(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + int (*handle_rsc)(struct remoteproc *rproc, void *rsc, size_t len); + int (*config)(struct remoteproc *rproc, void *data); + int (*start)(struct remoteproc *rproc); + int (*stop)(struct remoteproc *rproc); + int (*shutdown)(struct remoteproc *rproc); + int (*notify)(struct remoteproc *rproc, uint32_t id); +}; + +/* Remoteproc error codes */ +#define RPROC_EBASE 0 +#define RPROC_ENOMEM (RPROC_EBASE + 1) +#define RPROC_EINVAL (RPROC_EBASE + 2) +#define RPROC_ENODEV (RPROC_EBASE + 3) +#define RPROC_EAGAIN (RPROC_EBASE + 4) +#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_EBASE + 5) +#define RPROC_ERR_RSC_TAB_VER (RPROC_EBASE + 6) +#define RPROC_ERR_RSC_TAB_RSVD (RPROC_EBASE + 7) +#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_EBASE + 9) +#define RPROC_ERR_RSC_TAB_NP (RPROC_EBASE + 10) +#define RPROC_ERR_RSC_TAB_NS (RPROC_EBASE + 11) +#define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12) +#define RPROC_EMAX (RPROC_EBASE + 16) +#define RPROC_EPTR (void *)(-1) +#define RPROC_EOF (void *)(-1) + +static inline long RPROC_PTR_ERR(const void *ptr) +{ + return (long)ptr; +} + +static inline int RPROC_IS_ERR(const void *ptr) +{ + if ((unsigned long)ptr >= (unsigned long)(-RPROC_EMAX)) + return 1; + else + return 0; +} + +static inline void *RPROC_ERR_PTR(long error) +{ + return (void *)error; +} + +/** + * enum rproc_state - remote processor states + * @RPROC_OFFLINE: remote is offline + * @RPROC_READY: remote is ready to start + * @RPROC_RUNNING: remote is up and running + * @RPROC_SUSPENDED: remote is suspended + * @RPROC_ERROR: remote has error; need to recover + * @RPROC_STOPPED: remote is stopped + * @RPROC_LAST: just keep this one at the end + */ +enum remoteproc_state { + RPROC_OFFLINE = 0, + RPROC_CONFIGURED = 1, + RPROC_READY = 2, + RPROC_RUNNING = 3, + RPROC_SUSPENDED = 4, + RPROC_ERROR = 5, + RPROC_STOPPED = 6, + RPROC_LAST = 7, +}; + +/** + * remoteproc_init + * + * Initializes remoteproc resource. + * + * @rproc - pointer to remoteproc instance + * @ops - pointer to remoteproc operations + * @priv - pointer to private data + * + * @returns created remoteproc pointer + */ +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *priv); + +/** + * remoteproc_remove + * + * Remove remoteproc resource + * + * @rproc - pointer to remoteproc instance + * + * returns 0 for success, negative value for failure + */ +int remoteproc_remove(struct remoteproc *rproc); + +/** + * remoteproc_init_mem + * + * Initialize remoteproc memory + * + * @mem - pointer to remoteproc memory + * @char - memory name + * @pa - physcial address + * @da - device address + * @size - memory size + * @io - pointer to the I/O region + */ +static inline void +remoteproc_init_mem(struct remoteproc_mem *mem, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + size_t size, struct metal_io_region *io) +{ + if (!mem) + return; + if (name) + strncpy(mem->name, name, sizeof(mem->name)); + else + mem->name[0] = 0; + mem->pa = pa; + mem->da = da; + mem->io = io; + mem->size = size; +} + +/** + * remoteproc_add_mem + * + * Add remoteproc memory + * + * @rproc - pointer to remoteproc + * @mem - pointer to remoteproc memory + */ +static inline void +remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) +{ + if (!rproc || !mem) + return; + metal_list_add_tail(&rproc->mems, &mem->node); +} + +/** + * remoteproc_get_io_with_name + * + * get remoteproc memory I/O region with name + * + * @rproc - pointer to the remote processor + * @name - name of the shared memory + * @io - pointer to the pointer of the I/O region + * + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name); + +/** + * remoteproc_get_io_with_pa + * + * get remoteproc memory I/O region with physical address + * + * @rproc - pointer to the remote processor + * @pa - physical address + * + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa); + +/** + * remoteproc_get_io_with_da + * + * get remoteproc memory I/O region with device address + * + * @rproc - pointer to the remote processor + * @da - device address + * @offset - I/O region offset of the device address + * + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset); + +/** + * remoteproc_get_io_with_va + * + * get remoteproc memory I/O region with virtual address + * + * @rproc - pointer to the remote processor + * @va - virtual address + * + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, + void *va); + +/** + * remoteproc_mmap + * + * remoteproc mmap memory + * + * @rproc - pointer to the remote processor + * @pa - physical address pointer + * @da - device address pointer + * @size - size of the memory + * @attribute - memory attribute + * @io - pointer to the I/O region + * + * returns pointer to the memory + */ +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + +/** + * remoteproc_parse_rsc_table + * + * Parse resource table of remoteproc + * + * @rproc - pointer to remoteproc instance + * @rsc_table - pointer to resource table + * @rsc_size - resource table size + * + * returns 0 for success and negative value for errors + */ +int remoteproc_parse_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size); + +/** + * remoteproc_set_rsc_table + * + * Parse and set resource table of remoteproc + * + * @rproc - pointer to remoteproc instance + * @rsc_table - pointer to resource table + * @rsc_size - resource table size + * + * returns 0 for success and negative value for errors + */ +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size); + +/** + * remoteproc_config + * + * This function configures the remote processor to get it + * ready to load and run executable. + * + * @rproc - pointer to remoteproc instance to start + * @data - configuration data + * + * returns 0 for success and negative value for errors + */ +int remoteproc_config(struct remoteproc *rproc, void *data); + +/** + * remoteproc_start + * + * This function starts the remote processor. + * It assumes the firmware is already loaded, + * + * @rproc - pointer to remoteproc instance to start + * + * returns 0 for success and negative value for errors + */ +int remoteproc_start(struct remoteproc *rproc); + +/** + * remoteproc_stop + * + * This function stops the remote processor but it + * will not release its resource. + * + * @rproc - pointer to remoteproc instance + * + * returns 0 for success and negative value for errors + */ +int remoteproc_stop(struct remoteproc *rproc); + +/** + * remoteproc_shutdown + * + * This function shutdown the remote processor and + * release its resources. + * + * @rproc - pointer to remoteproc instance + * + * returns 0 for success and negative value for errors + */ +int remoteproc_shutdown(struct remoteproc *rproc); + +/** + * remoteproc_load + * + * load executable, it expects the user application defines how to + * open the executable file and how to get data from the executable file + * and how to load data to the target memory. + * + * @rproc: pointer to the remoteproc instance + * @path: optional path to the image file + * @store: pointer to user defined image store argument + * @store_ops: pointer to image store operations + * @image_info: pointer to memory which stores image information used + * by remoteproc loader + * + * return 0 for success and negative value for failure + */ +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, struct image_store_ops *store_ops, + void **img_info); + +/** + * remoteproc_load_noblock + * + * load executable, it expects the caller has loaded image data to local + * memory and passed to the this function. If the function needs more + * image data it will return the next expected image data offset and + * the next expected image data length. If the function requires the + * caller to download image data to the target memory, it will also + * return the target physical address besides the offset and length. + * This function can be used to load firmware in stream mode. In this + * mode, you cannot do seek to the executable file. If the executable + * is ELF, it cannot get the resource table section before it loads + * the full ELF file. Furthermore, application usually don't store + * the data which is loaded to local memory in streaming mode, and + * thus, in this mode, it will load the binrary to the target memory + * before it gets the resource table. And thus, when calling this funciton + * don't put the target exectuable memory in the resource table, as + * this function will parse the resource table after it loads the binary + * to target memory. + * + * @rproc: pointer to the remoteproc instance + * @img_data: pointer to image data for remoteproc loader to parse + * @offset: image data offset to the beginning of the image file + * @len: image data length + * @image_info: pointer to memory which stores image information used + * by remoteproc loader + * @pa: pointer to the target memory physical address. If the next expected + * data doesn't need to load to the target memory, the function will + * set it to ANY. + * @io: pointer to the target memory physical address. If the next expected + * data doesn't need to load to the target memory, the function will + * set it to ANY. + * @noffset: pointer to the next image data offset to the beginning of + * the image file needs to load to local or to the target + * memory. + * @nlen: pointer to the next image data length needs to load to local + * or to the target memory. + * @nmlen: pointer to the memory size. It is only used when the next + * expected data is going to be loaded to the target memory. E.g. + * in ELF, it is possible that loadable segment in memory is + * larger that the segment data in the ELF file. In this case, + * application will need to pad the rest of the memory with + * padding. + * @padding: pointer to the padding value. It is only used when the next + * expected data is going to be loaded to the target memory. + * and the target memory size is larger than the segment data in + * the executable file. + * + * return 0 for success and negative value for failure + */ +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding); + +/** + * remoteproc_allocate_id + * + * allocate notifyid for resource + * + * @rproc - pointer to the remoteproc instance + * @start - start of the id range + * @end - end of the id range + * + * return allocated notify id + */ +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end); + +/* remoteproc_create_virtio + * + * create virtio device, it returns pointer to the created virtio device. + * + * @rproc: pointer to the remoteproc instance + * @vdev_id: virtio device ID + * @role: virtio device role + * @rst_cb: virtio device reset callback + * + * return pointer to the created virtio device, NULL for failure. + */ +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)); + +/* remoteproc_remove_virtio + * + * Remove virtio device + * + * @rproc: pointer to the remoteproc instance + * @vdev: pointer to the virtio device + * + */ +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev); + +/* remoteproc_get_notification + * + * remoteproc is got notified, it will check its subdevices + * for the notification + * + * @rproc - pointer to the remoteproc instance + * @notifyid - notificatin id + * + * return 0 for succeed, negative value for failure + */ +int remoteproc_get_notification(struct remoteproc *rproc, + uint32_t notifyid); +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_loader.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_loader.h new file mode 100644 index 0000000000..4409a1aa7a --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_loader.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/************************************************************************** + * FILE NAME + * + * remoteproc_loader.h + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * This file provides definitions for remoteproc loader + * + * + **************************************************************************/ +#ifndef REMOTEPROC_LOADER_H_ +#define REMOTEPROC_LOADER_H_ + +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Loader feature macros */ +#define SUPPORT_SEEK 1UL + +/* Remoteproc loader any address */ +#define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1) + +/* Remoteproc loader Exectuable Image Parsing States */ +/* Remoteproc loader parser intial state */ +#define RPROC_LOADER_NOT_READY 0x0UL +/* Remoteproc loader ready to load, even it can be not finish parsing */ +#define RPROC_LOADER_READY_TO_LOAD 0x10000UL +/* Remoteproc loader post data load */ +#define RPROC_LOADER_POST_DATA_LOAD 0x20000UL +/* Remoteproc loader finished loading */ +#define RPROC_LOADER_LOAD_COMPLETE 0x40000UL +/* Remoteproc loader state mask */ +#define RPROC_LOADER_MASK 0x00FF0000UL +/* Remoteproc loader private mask */ +#define RPROC_LOADER_PRIVATE_MASK 0x0000FFFFUL +/* Remoteproc loader reserved mask */ +#define RPROC_LOADER_RESERVED_MASK 0x0F000000UL + +/** + * struct image_store_ops - user defined image store operations + * @open: user defined callback to open the "firmware" to prepare loading + * @close: user defined callback to close the "firmware" to clean up + * after loading + * @load: user defined callback to load the firmware contents to target + * memory or local memory + * @features: loader supported features. e.g. seek + */ +struct image_store_ops { + int (*open)(void *store, const char *path, const void **img_data); + void (*close)(void *store); + int (*load)(void *store, size_t offset, size_t size, + const void **data, + metal_phys_addr_t pa, + struct metal_io_region *io, char is_blocking); + unsigned int features; +}; + +/** + * struct loader_ops - loader oeprations + * @load_header: define how to get the executable headers + * @load_data: define how to load the target data + * @locate_rsc_table: define how to get the resource table target address, + * offset to the ELF image file and size of the resource + * table. + * @release: define how to release the loader + * @get_entry: get entry address + * @get_load_state: get load state from the image information + */ +struct loader_ops { + int (*load_header)(const void *img_data, size_t offset, size_t len, + void **img_info, int last_state, + size_t *noffset, size_t *nlen); + int (*load_data)(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); + void (*release)(void *img_info); + metal_phys_addr_t (*get_entry)(void *img_info); + int (*get_load_state)(void *img_info); +}; + +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_LOADER_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_virtio.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_virtio.h new file mode 100644 index 0000000000..b06b951c4d --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/remoteproc_virtio.h @@ -0,0 +1,150 @@ +/* + * Remoteproc Virtio Framework + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Texas Instruments 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 + * OWNER 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 REMOTEPROC_VIRTIO_H +#define REMOTEPROC_VIRTIO_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* define vdev notification funciton user should implement */ +typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); + +/** + * struct remoteproc_virtio + * @priv pointer to private data + * @notifyid notification id + * @vdev_rsc address of vdev resource + * @vdev_rsc_io metal I/O region of vdev_info, can be NULL + * @notify notification function + * @vdev virtio device + * @node list node + */ +struct remoteproc_virtio { + void *priv; + uint32_t notify_id; + void *vdev_rsc; + struct metal_io_region *vdev_rsc_io; + rpvdev_notify_func notify; + struct virtio_device vdev; + struct metal_list node; +}; + +/** + * rproc_virtio_create_vdev + * + * Create rproc virtio vdev + * + * @role: 0 - virtio master, 1 - virtio slave + * @notifyid: virtio device notification id + * @rsc: pointer to the virtio device resource + * @rsc_io: pointer to the virtio device resource I/O region + * @priv: pointer to the private data + * @notify: vdev and virtqueue notification function + * @rst_cb: reset virtio device callback + * + * return pointer to the created virtio device for success, + * NULL for failure. + */ +struct virtio_device * +rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, + void *rsc, struct metal_io_region *rsc_io, + void *priv, + rpvdev_notify_func notify, + virtio_dev_reset_cb rst_cb); + +/** + * rproc_virtio_remove_vdev + * + * Create rproc virtio vdev + * + * @vdev - pointer to the virtio device + */ +void rproc_virtio_remove_vdev(struct virtio_device *vdev); + +/** + * rproc_virtio_create_vring + * + * Create rproc virtio vring + * + * @vdev: pointer to the virtio device + * @index: vring index in the virtio device + * @notifyid: remoteproc vring notification id + * @va: vring virtual address + * @io: pointer to vring I/O region + * @num_desc: number of descriptors + * @align: vring alignment + * + * return 0 for success, negative value for failure. + */ +int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, + unsigned int notifyid, void *va, + struct metal_io_region *io, + unsigned int num_descs, unsigned int align); + +/** + * rproc_virtio_notified + * + * remoteproc virtio is got notified + * + * @vdev - pointer to the virtio device + * @notifyid - notify id + * + * return 0 for successful, negative value for failure + */ +int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); + +/** + * rproc_virtio_wait_remote_ready + * + * Blocking function, waiting for the remote core is ready to start + * communications. + * + * @vdev - pointer to the virtio device + * + * return true when remote processor is ready. + */ +void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); + +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_VIRTIO_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg.h new file mode 100644 index 0000000000..983dcb094e --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg.h @@ -0,0 +1,358 @@ +/* + * Remote processor messaging + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _RPMSG_H_ +#define _RPMSG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Configurable parameters */ +#define RPMSG_NAME_SIZE (32) +#define RPMSG_ADDR_BMP_SIZE (128) + +#define RPMSG_NS_EPT_ADDR (0x35) +#define RPMSG_ADDR_ANY 0xFFFFFFFF + +/* Error macros. */ +#define RPMSG_SUCCESS 0 +#define RPMSG_ERROR_BASE -2000 +#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1) +#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2) +#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 3) +#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 4) +#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5) +#define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) +#define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) + +struct rpmsg_endpoint; +struct rpmsg_device; + +typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv); +typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept); +typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, + const char *name, uint32_t dest); + +/** + * struct rpmsg_endpoint - binds a local rpmsg address to its user + * @name:name of the service supported + * @rdev: pointer to the rpmsg device + * @addr: local address of the endpoint + * @dest_addr: address of the default remote endpoint binded. + * @cb: user rx callback, return value of this callback is reserved + * for future use, for now, only allow RPMSG_SUCCESS as return value. + * @ns_unbind_cb: end point service service unbind callback, called when remote + * ept is destroyed. + * @node: end point node. + * @addr: local rpmsg address + * @priv: private data for the driver's use + * + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. + */ +struct rpmsg_endpoint { + char name[RPMSG_NAME_SIZE]; + struct rpmsg_device *rdev; + uint32_t addr; + uint32_t dest_addr; + rpmsg_ept_cb cb; + rpmsg_ns_unbind_cb ns_unbind_cb; + struct metal_list node; + void *priv; +}; + +/** + * struct rpmsg_device_ops - RPMsg device operations + * @send_offchannel_raw: send RPMsg data + */ +struct rpmsg_device_ops { + int (*send_offchannel_raw)(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, int size, int wait); +}; + +/** + * struct rpmsg_device - representation of a RPMsg device + * @endpoints: list of endpoints + * @ns_ept: name service endpoint + * @bitmap: table endpoin address allocation. + * @lock: mutex lock for rpmsg management + * @ns_bind_cb: callback handler for name service announcement without local + * endpoints waiting to bind. + * @ops: RPMsg device operations + */ +struct rpmsg_device { + struct metal_list endpoints; + struct rpmsg_endpoint ns_ept; + unsigned long bitmap[metal_bitmap_longs(RPMSG_ADDR_BMP_SIZE)]; + metal_mutex_t lock; + rpmsg_ns_bind_cb ns_bind_cb; + struct rpmsg_device_ops ops; +}; + +/** + * rpmsg_send_offchannel_raw() - send a message across to the remote processor, + * specifying source and destination address. + * @ept: the rpmsg endpoint + * @data: payload of the message + * @len: length of the payload + * + * This function sends @data of length @len to the remote @dst address from + * the source @src address. + * The message will be sent to the remote processor which the channel belongs + * to. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int size, + int wait); + +/** + * rpmsg_send() - send a message across to the remote processor + * @ept: the rpmsg endpoint + * @data: payload of the message + * @len: length of the payload + * + * This function sends @data of length @len based on the @ept. + * The message will be sent to the remote processor which the channel belongs + * to, using @ept's source and destination addresses. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, + int len) +{ + if (ept->dest_addr == RPMSG_ADDR_ANY) + return RPMSG_ERR_ADDR; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, true); +} + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * @dst: destination address + * + * This function sends @data of length @len to the remote @dst address. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source address. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, + int len, uint32_t dst) +{ + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, true); +} + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @ept: the rpmsg endpoint + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len to the remote @dst address, + * and uses @src as the source address. + * The message will be sent to the remote processor which the @ept + * channel belongs to. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, + uint32_t src, uint32_t dst, + const void *data, int len) +{ + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true); +} + +/** + * rpmsg_trysend() - send a message across to the remote processor + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @ept channel. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source and destination addresses. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, + int len) +{ + if (ept->dest_addr == RPMSG_ADDR_ANY) + return RPMSG_ERR_ADDR; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, false); +} + +/** + * rpmsg_trysendto() - send a message across to the remote processor, + * specify dst + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * @dst: destination address + * + * This function sends @data of length @len to the remote @dst address. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source address. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data, + int len, uint32_t dst) +{ + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, false); +} + +/** + * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses + * @ept: the rpmsg endpoint + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len to the remote @dst address, + * and uses @src as the source address. + * The message will be sent to the remote processor which the @ept + * channel belongs to. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Returns number of bytes it has sent or negative error value on failure. + */ +static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, + uint32_t src, uint32_t dst, + const void *data, int len) +{ + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false); +} + +/** + * rpmsg_init_ept - initialize rpmsg endpoint + * + * Initialize an RPMsg endpoint with a name, source address, + * remoteproc address, endpoitn callback, and destroy endpoint callback. + * + * @ept: pointer to rpmsg endpoint + * @name: service name associated to the endpoint + * @src: local address of the endpoint + * @dest: target address of the endpoint + * @cb: endpoint callback + * @ns_unbind_cb: end point service unbind callback, called when remote ept is + * destroyed. + */ +static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept, + const char *name, + uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb ns_unbind_cb) +{ + strncpy(ept->name, name, sizeof(ept->name)); + ept->addr = src; + ept->dest_addr = dest; + ept->cb = cb; + ept->ns_unbind_cb = ns_unbind_cb; +} + +/** + * rpmsg_create_ept - create rpmsg endpoint and register it to rpmsg device + * + * Create a RPMsg endpoint, initialize it with a name, source address, + * remoteproc address, endpoitn callback, and destroy endpoint callback, + * and register it to the RPMsg device. + * + * @ept: pointer to rpmsg endpoint + * @name: service name associated to the endpoint + * @src: local address of the endpoint + * @dest: target address of the endpoint + * @cb: endpoint callback + * @ns_unbind_cb: end point service unbind callback, called when remote ept is + * destroyed. + * + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. + * + * Rpmsg client should create an endpoint to discuss with remote. rpmsg client + * provide at least a channel name, a callback for message notification and by + * default endpoint source address should be set to RPMSG_ADDR_ANY. + * + * As an option Some rpmsg clients can specify an endpoint with a specific + * source address. + */ + +int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, + const char *name, uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb); + +/** + * rpmsg_destroy_ept - destroy rpmsg endpoint and unregister it from rpmsg + * device + * + * @ept: pointer to the rpmsg endpoint + * + * It unregisters the rpmsg endpoint from the rpmsg device and calls the + * destroy endpoint callback if it is provided. + */ +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept); + +/** + * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send + * + * @ept: pointer to rpmsg endpoint + * + * Returns 1 if the rpmsg endpoint has both local addr and destination + * addr set, 0 otherwise + */ +static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept) +{ + return (ept->dest_addr != RPMSG_ADDR_ANY && + ept->addr != RPMSG_ADDR_ANY); +} + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_retarget.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_retarget.h new file mode 100644 index 0000000000..5645e52ed6 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_retarget.h @@ -0,0 +1,119 @@ +#ifndef RPMSG_RETARGET_H +#define RPMSG_RETARGET_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* File Operations System call definitions */ +#define OPEN_SYSCALL_ID 0x1UL +#define CLOSE_SYSCALL_ID 0x2UL +#define WRITE_SYSCALL_ID 0x3UL +#define READ_SYSCALL_ID 0x4UL +#define ACK_STATUS_ID 0x5UL + +#define TERM_SYSCALL_ID 0x6UL + +#define DEFAULT_PROXY_ENDPOINT 0xFFUL + +struct rpmsg_rpc_data; + +typedef int (*rpmsg_rpc_poll)(void *arg); +typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc); + +struct rpmsg_rpc_syscall_header { + int32_t int_field1; + int32_t int_field2; + uint32_t data_len; +}; + +struct rpmsg_rpc_syscall { + uint32_t id; + struct rpmsg_rpc_syscall_header args; +}; + +struct rpmsg_rpc_data { + struct rpmsg_endpoint ept; + int ept_destroyed; + atomic_int nacked; + void *respbuf; + size_t respbuf_len; + rpmsg_rpc_poll poll; + void *poll_arg; + rpmsg_rpc_shutdown_cb shutdown_cb; + metal_mutex_t lock; + struct metal_spinlock buflock; +}; + +/** + * rpmsg_rpc_init - initialize RPMsg remote procedure call + * + * This function is to intialize the remote procedure call + * global data. RPMsg RPC will send request to remote and + * wait for callback. + * + * @rpc: pointer to the global remote procedure call data + * @rdev: pointer to the rpmsg device + * @ept_name: name of the endpoint used by RPC + * @ept_addr: address of the endpoint used by RPC + * @ept_raddr: remote address of the endpoint used by RPC + * @poll_arg: pointer to poll function argument + * @poll: poll function + * @shutdown_cb: shutdown callback function + * + * return 0 for success, and negative value for failure. + */ +int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, + struct rpmsg_device *rdev, + const char *ept_name, uint32_t ept_addr, + uint32_t ept_raddr, + void *poll_arg, rpmsg_rpc_poll poll, + rpmsg_rpc_shutdown_cb shutdown_cb); + +/** + * rpmsg_rpc_release - release RPMsg remote procedure call + * + * This function is to release remoteproc procedure call + * global data. + * + * @rpc: pointer to the globacl remote procedure call + */ +void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc); + +/** + * rpmsg_rpc_send - Request RPMsg RPC call + * + * This function sends RPC request it will return with the length + * of data and the response buffer. + * + * @rpc: pointer to remoteproc procedure call data struct + * @req: pointer to request buffer + * @len: length of the request data + * @resp: pointer to where store the response buffer + * @resp_len: length of the response buffer + * + * return length of the received response, negative value for failure. + */ +int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, + void *req, size_t len, + void *resp, size_t resp_len); + +/** + * rpmsg_set_default_rpc - set default RPMsg RPC data + * + * The default RPC data is used to redirect standard C file operations + * to RPMsg channels. + * + * @rpc: pointer to remoteproc procedure call data struct + */ +void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc); + +#if defined __cplusplus +} +#endif + +#endif /* RPMSG_RETARGET_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_virtio.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_virtio.h new file mode 100644 index 0000000000..b1369cacb4 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rpmsg_virtio.h @@ -0,0 +1,190 @@ +/* + * rpmsg based on virtio + * + * Copyright (C) 2018 Linaro, Inc. + * + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _RPMSG_VIRTIO_H_ +#define _RPMSG_VIRTIO_H_ + +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Configurable parameters */ +#ifndef RPMSG_BUFFER_SIZE +#define RPMSG_BUFFER_SIZE (512) +#endif + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ + +struct rpmsg_virtio_shm_pool; +/** + * struct rpmsg_virtio_shm_pool - shared memory pool used for rpmsg buffers + * @get_buffer: function to get buffer from the pool + * @base: base address of the memory pool + * @avail: available memory size + * @size: total pool size + */ +struct rpmsg_virtio_shm_pool { + void *base; + size_t avail; + size_t size; +}; + +/** + * struct rpmsg_virtio_device - representation of a rpmsg device based on virtio + * @rdev: rpmsg device, first property in the struct + * @vdev: pointer to the virtio device + * @rvq: pointer to receive virtqueue + * @svq: pointer to send virtqueue + * @shbuf_io: pointer to the shared buffer I/O region + * @shpool: pointer to the shared buffers pool + * @endpoints: list of endpoints. + */ +struct rpmsg_virtio_device { + struct rpmsg_device rdev; + struct virtio_device *vdev; + struct virtqueue *rvq; + struct virtqueue *svq; + struct metal_io_region *shbuf_io; + struct rpmsg_virtio_shm_pool *shpool; +}; + +#define RPMSG_REMOTE VIRTIO_DEV_SLAVE +#define RPMSG_MASTER VIRTIO_DEV_MASTER +static inline unsigned int + rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->role; +} + +static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, + uint8_t status) +{ + rvdev->vdev->func->set_status(rvdev->vdev, status); +} + +static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_status(rvdev->vdev); +} + +static inline uint32_t + rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_features(rvdev->vdev); +} + +static inline int + rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, + int flags, unsigned int nvqs, + const char *names[], + vq_callback * callbacks[]) +{ + return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, + callbacks); +} + +/** + * rpmsg_virtio_get_buffer_size - get rpmsg virtio buffer size + * + * @rdev - pointer to the rpmsg device + * + * @return - next available buffer size for text, negative value for failure + */ +int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev); + +/** + * rpmsg_init_vdev - initialize rpmsg virtio device + * Master side: + * Initialize RPMsg virtio queues and shared buffers, the address of shm can be + * ANY. In this case, function will get shared memory from system shared memory + * pools. If the vdev has RPMsg name service feature, this API will create an + * name service endpoint. + * + * Slave side: + * This API will not return until the driver ready is set by the master side. + * + * @param rvdev - pointer to the rpmsg virtio device + * @param vdev - pointer to the virtio device + * @param ns_bind_cb - callback handler for name service announcement without + * local endpoints waiting to bind. + * @param shm_io - pointer to the share memory I/O region. + * @param shpool - pointer to shared memory pool. rpmsg_virtio_init_shm_pool has + * to be called first to fill this structure. + * + * @return - status of function execution + */ +int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool); + +/** + * rpmsg_deinit_vdev - deinitialize rpmsg virtio device + * + * @param rvdev - pointer to the rpmsg virtio device + */ +void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev); + +/** + * rpmsg_virtio_init_shm_pool - initialize default shared buffers pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. This function has to be called before calling rpmsg_init_vdev, + * to initialize the rpmsg_virtio_shm_pool structure. + * + * @param shpool - pointer to the shared buffers pool structure + * @param shbuf - pointer to the beginning of shared buffers + * @param size - shared buffers total size + */ +void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shbuf, size_t size); + +/** + * rpmsg_virtio_get_rpmsg_device - get RPMsg device from RPMsg virtio device + * + * @param rvdev - pointer to RPMsg virtio device + * @return - RPMsg device pointed by RPMsg virtio device + */ +static inline struct rpmsg_device * +rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) +{ + return &rvdev->rdev; +} + +/** + * rpmsg_virtio_shm_pool_get_buffer - get buffer in the shared memory pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. If you prefer to have other shared buffers allocation, + * you can implement your rpmsg_virtio_shm_pool_get_buffer function. + * + * @param shpool - pointer to the shared buffers pool + * @param size - shared buffers total size + * @return - buffer pointer if free buffer is available, NULL otherwise. + */ +metal_weak void * +rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, + size_t size); + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_VIRTIO_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rsc_table_parser.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rsc_table_parser.h new file mode 100644 index 0000000000..b0aa27e2d8 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/rsc_table_parser.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RSC_TABLE_PARSER_H +#define RSC_TABLE_PARSER_H + +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define RSC_TAB_SUPPORTED_VERSION 1 +#define RSC_TAB_HEADER_SIZE 12 +#define RSC_TAB_MAX_VRINGS 2 + +/* Standard control request handling. */ +typedef int (*rsc_handler) (struct remoteproc *rproc, void *rsc); + +/** + * handle_rsc_table + * + * This function parses resource table. + * + * @param rproc - pointer to remote remoteproc + * @param rsc_table - resource table to parse + * @param size - size of rsc table + * @param io - pointer to the resource table I/O region + * It can be NULL if the resource table + * is in the local memory. + * + * @returns - execution status + * + */ +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, int len, + struct metal_io_region *io); +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc); +int handle_trace_rsc(struct remoteproc *rproc, void *rsc); +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc); +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc); + +/** + * find_rsc + * + * find out location of a resource type in the resource table. + * + * @rsc_table - pointer to the resource table + * @rsc_type - type of the resource + * @index - index of the resource of the specified type + * + * return the offset to the resource on success, or 0 on failure + */ +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index); + +#if defined __cplusplus +} +#endif + +#endif /* RSC_TABLE_PARSER_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio.h new file mode 100644 index 0000000000..463079bf37 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio.h @@ -0,0 +1,176 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef _VIRTIO_H_ +#define _VIRTIO_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* TODO: define this as compiler flags */ +#ifndef VIRTIO_MAX_NUM_VRINGS +#define VIRTIO_MAX_NUM_VRINGS 2 +#endif + +/* VirtIO device IDs. */ +#define VIRTIO_ID_NETWORK 0x01UL +#define VIRTIO_ID_BLOCK 0x02UL +#define VIRTIO_ID_CONSOLE 0x03UL +#define VIRTIO_ID_ENTROPY 0x04UL +#define VIRTIO_ID_BALLOON 0x05UL +#define VIRTIO_ID_IOMEMORY 0x06UL +#define VIRTIO_ID_RPMSG 0x07UL /* remote processor messaging */ +#define VIRTIO_ID_SCSI 0x08UL +#define VIRTIO_ID_9P 0x09UL +#define VIRTIO_DEV_ANY_ID (-1)UL + +/* Status byte for guest to report progress. */ +#define VIRTIO_CONFIG_STATUS_ACK 0x01 +#define VIRTIO_CONFIG_STATUS_DRIVER 0x02 +#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_NEEDS_RESET 0x40 +#define VIRTIO_CONFIG_STATUS_FAILED 0x80 + +/* Virtio device role */ +#define VIRTIO_DEV_MASTER 0UL +#define VIRTIO_DEV_SLAVE 1UL + +struct virtio_device_id { + uint32_t device; + uint32_t vendor; +}; + +/* + * Generate interrupt when the virtqueue ring is + * completely used, even if we've suppressed them. + */ +#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24) + +/* + * The guest should never negotiate this feature; it + * is used to detect faulty drivers. + */ +#define VIRTIO_F_BAD_FEATURE (1 << 30) + +/* + * Some VirtIO feature bits (currently bits 28 through 31) are + * reserved for the transport being used (eg. virtio_ring), the + * rest are per-device feature bits. + */ +#define VIRTIO_TRANSPORT_F_START 28 +#define VIRTIO_TRANSPORT_F_END 32 + +typedef void (*virtio_dev_reset_cb)(struct virtio_device *vdev); + +struct virtio_dispatch; + +struct virtio_feature_desc { + uint32_t vfd_val; + const char *vfd_str; +}; + +/** + * struct proc_shm + * + * This structure is maintained by hardware interface layer for + * shared memory information. The shared memory provides buffers + * for use by the vring to exchange messages between the cores. + * + */ +struct virtio_buffer_info { + /* Start address of shared memory used for buffers. */ + void *vaddr; + /* Start physical address of shared memory used for buffers. */ + metal_phys_addr_t paddr; + /* sharmed memory I/O region */ + struct metal_io_region *io; + /* Size of shared memory. */ + unsigned long size; +}; + +/** + * struct remoteproc_vring - remoteproc vring structure + * @vq virtio queue + * @va logical address + * @notifyid vring notify id + * @num_descs number of descriptors + * @align vring alignment + * @io metal I/O region of the vring memory, can be NULL + */ +struct virtio_vring_info { + struct virtqueue *vq; + struct vring_alloc_info info; + uint32_t notifyid; + struct metal_io_region *io; +}; + +/* + * Structure definition for virtio devices for use by the + * applications/drivers + */ + +struct virtio_device { + uint32_t index; /**< unique position on the virtio bus */ + struct virtio_device_id id; /**< the device type identification + * (used to match it with a driver + */ + uint64_t features; /**< the features supported by both ends. */ + unsigned int role; /**< if it is virtio backend or front end. */ + virtio_dev_reset_cb reset_cb; /**< user registered device callback */ + const struct virtio_dispatch *func; /**< Virtio dispatch table */ + void *priv; /**< TODO: remove pointer to virtio_device private data */ + unsigned int vrings_num; /**< number of vrings */ + struct virtio_vring_info *vrings_info; +}; + +/* + * Helper functions. + */ +const char *virtio_dev_name(uint16_t devid); +void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, + struct virtio_feature_desc *feature_desc); + +/* + * Functions for virtio device configuration as defined in Rusty Russell's + * paper. + * Drivers are expected to implement these functions in their respective codes. + */ + +struct virtio_dispatch { + uint8_t (*get_status)(struct virtio_device *dev); + void (*set_status)(struct virtio_device *dev, uint8_t status); + uint32_t (*get_features)(struct virtio_device *dev); + void (*set_features)(struct virtio_device *dev, uint32_t feature); + uint32_t (*negotiate_features)(struct virtio_device *dev, + uint32_t features); + + /* + * Read/write a variable amount from the device specific (ie, network) + * configuration region. This region is encoded in the same endian as + * the guest. + */ + void (*read_config)(struct virtio_device *dev, uint32_t offset, + void *dst, int length); + void (*write_config)(struct virtio_device *dev, uint32_t offset, + void *src, int length); + void (*reset_device)(struct virtio_device *dev); + void (*notify)(struct virtqueue *vq); +}; + +int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback *callbacks[]); + +#if defined __cplusplus +} +#endif + +#endif /* _VIRTIO_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio_ring.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio_ring.h new file mode 100644 index 0000000000..14e7b6b571 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtio_ring.h @@ -0,0 +1,152 @@ +/* + * Copyright Rusty Russell IBM Corporation 2007. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef VIRTIO_RING_H +#define VIRTIO_RING_H + +#if defined __cplusplus +extern "C" { +#endif + +/* 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[0]; +}; + +/* 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[0]; +}; + +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) ((vr)->used->ring[(vr)->num].id & 0xFFFF) + +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] + sizeof(uint16_t) + + 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); +} + +#if defined __cplusplus +} +#endif + +#endif /* VIRTIO_RING_H */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtqueue.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtqueue.h new file mode 100644 index 0000000000..ad24749062 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/include/openamp/virtqueue.h @@ -0,0 +1,236 @@ +#ifndef VIRTQUEUE_H_ +#define VIRTQUEUE_H_ + +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + * + * $FreeBSD$ + */ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +typedef uint8_t boolean; + +#include +#include +#include + +/*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) + +#define VQUEUE_SUCCESS 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 + +/* 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) + +struct virtqueue_buf { + void *buf; + int len; +}; + +struct virtqueue { + struct virtio_device *vq_dev; + const char *vq_name; + uint16_t vq_queue_index; + uint16_t vq_nentries; + uint32_t vq_flags; + void (*callback)(struct virtqueue *vq); + void (*notify)(struct virtqueue *vq); + struct vring vq_ring; + uint16_t vq_free_cnt; + uint16_t vq_queued_cnt; + void *shm_io; /* opaque pointer to data needed to allow v2p & p2v */ + + /* + * 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; + +#ifdef VQUEUE_DEBUG + boolean vq_inuse; +#endif + + /* + * Used by the host side during callback. Cookie + * holds the address of buffer received from other side. + * Other fields in this structure are not used currently. + */ + + struct vq_desc_extra { + void *cookie; + uint16_t ndescs; + } vq_descx[0]; +}; + +/* struct to hold vring specific information */ +struct vring_alloc_info { + void *vaddr; + uint32_t align; + uint16_t num_descs; + uint16_t pad; +}; + +typedef void vq_callback(struct virtqueue *); +typedef void vq_notify(struct virtqueue *); + +#ifdef VQUEUE_DEBUG +#include +#include + +#define VQASSERT(_vq, _exp, _msg) \ + do { \ + if (!(_exp)) { \ + metal_log(METAL_LOG_EMERGENCY, \ + "%s: %s - _msg", __func__, (_vq)->vq_name); \ + metal_assert(_exp); \ + } \ + } while (0) + +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \ + VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index") + +#define VQ_RING_ASSERT_CHAIN_TERM(_vq) \ + VQASSERT((_vq), (_vq)->vq_desc_head_idx == \ + VQ_RING_DESC_CHAIN_END, \ + "full ring terminated incorrectly: invalid head") + +#define VQ_PARAM_CHK(condition, status_var, status_err) \ + do { \ + if (((status_var) == 0) && (condition)) { \ + status_var = status_err; \ + } \ + } while (0) + +#define VQUEUE_BUSY(vq) \ + do { \ + if (!(vq)->vq_inuse) \ + (vq)->vq_inuse = true; \ + else \ + VQASSERT(vq, !(vq)->vq_inuse,\ + "VirtQueue already in use") \ + } while (0) + +#define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) + +#else + +#define KASSERT(cond, str) +#define VQASSERT(_vq, _exp, _msg) +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) +#define VQ_RING_ASSERT_CHAIN_TERM(_vq) +#define VQ_PARAM_CHK(condition, status_var, status_err) +#define VQUEUE_BUSY(vq) +#define VQUEUE_IDLE(vq) + +#endif + +int virtqueue_create(struct virtio_device *device, unsigned short id, + const char *name, struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue *v_queue); + +/* + * virtqueue_set_shmem_io + * + * set virtqueue shared memory I/O region + * + * @vq - virt queue + * @io - pointer to the shared memory I/O region + */ +static inline void virtqueue_set_shmem_io(struct virtqueue *vq, + struct metal_io_region *io) +{ + vq->shm_io = io; +} + +int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, + int readable, int writable, void *cookie); + +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); + +static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) +{ + struct virtqueue *vqs; + uint32_t vq_size = sizeof(struct virtqueue) + + num_desc_extra * sizeof(struct vq_desc_extra); + + vqs = (struct virtqueue *)metal_allocate_memory(vq_size); + + if (vqs) { + memset(vqs, 0x00, vq_size); + } + + return vqs; +} + +void virtqueue_free(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); + +#if defined __cplusplus +} +#endif + +#endif /* VIRTQUEUE_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/elf_loader.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/elf_loader.c new file mode 100644 index 0000000000..e15a7843bb --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/elf_loader.c @@ -0,0 +1,711 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +static int elf_is_64(const void *elf_info) +{ + const unsigned char *tmp = elf_info; + + if (tmp[EI_CLASS] == ELFCLASS64) + return 1; + else + return 0; +} + +static size_t elf_ehdr_size(const void *elf_info) +{ + if (elf_info == NULL) + return sizeof(Elf64_Ehdr); + else if (elf_is_64(elf_info) != 0) + return sizeof(Elf64_Ehdr); + else + return sizeof(Elf32_Ehdr); +} + +static size_t elf_phoff(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phoff; + } +} + +static size_t elf_phentsize(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phentsize; + } +} + +static int elf_phnum(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phnum; + } +} + +static size_t elf_shoff(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shoff; + } +} + +static size_t elf_shentsize(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shentsize; + } +} + +static int elf_shnum(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shnum; + } +} + +static int elf_shstrndx(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shstrndx; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shstrndx; + } +} + +static void *elf_phtable_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return (void *)&einfo->phdrs; + } else { + struct elf64_info *einfo = elf_info; + + return (void *)&einfo->phdrs; + } +} + +static void *elf_shtable_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return (void *)(&einfo->shdrs); + } else { + struct elf64_info *einfo = elf_info; + + return (void *)(&einfo->shdrs); + } +} + +static void **elf_shstrtab_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return &einfo->shstrtab; + } else { + struct elf64_info *einfo = elf_info; + + return &einfo->shstrtab; + } +} + +static unsigned int *elf_load_state(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return &einfo->load_state; + } else { + struct elf64_info *einfo = elf_info; + + return &einfo->load_state; + } +} + +static void elf_parse_segment(void *elf_info, const void *elf_phdr, + unsigned int *p_type, size_t *p_offset, + metal_phys_addr_t *p_vaddr, + metal_phys_addr_t *p_paddr, + size_t *p_filesz, size_t *p_memsz) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Phdr *phdr = elf_phdr; + + if (p_type != NULL) + *p_type = (unsigned int)phdr->p_type; + if (p_offset != NULL) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr != NULL) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr != NULL) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz != NULL) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz != NULL) + *p_memsz = (size_t)phdr->p_memsz; + } else { + const Elf64_Phdr *phdr = elf_phdr; + + if (p_type != NULL) + *p_type = (unsigned int)phdr->p_type; + if (p_offset != NULL) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr != NULL) + if (p_vaddr != NULL) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr != NULL) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz != NULL) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz != NULL) + *p_memsz = (size_t)phdr->p_memsz; + } +} + +static const void *elf_get_segment_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + const struct elf32_info *einfo = elf_info; + const Elf32_Ehdr *ehdr = &einfo->ehdr; + const Elf32_Phdr *phdrs = einfo->phdrs; + + if (phdrs == NULL) + return NULL; + if (index < 0 || index > ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } else { + const struct elf64_info *einfo = elf_info; + const Elf64_Ehdr *ehdr = &einfo->ehdr; + const Elf64_Phdr *phdrs = einfo->phdrs; + + if (phdrs == NULL) + return NULL; + if (index < 0 || index > ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } +} + +static void *elf_get_section_from_name(void *elf_info, const char *name) +{ + unsigned int i; + const char *name_table; + + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (shdr == NULL || name_table == NULL) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (shdr == NULL || name_table == NULL) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } + return NULL; +} + +static void *elf_get_section_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + if (shdr == NULL) + return NULL; + if (index > ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + if (shdr == NULL) + return NULL; + if (index > ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } +} + +static void elf_parse_section(void *elf_info, void *elf_shdr, + unsigned int *sh_type, unsigned int *sh_flags, + metal_phys_addr_t *sh_addr, + size_t *sh_offset, size_t *sh_size, + unsigned int *sh_link, unsigned int *sh_info, + unsigned int *sh_addralign, + size_t *sh_entsize) +{ + if (elf_is_64(elf_info) == 0) { + Elf32_Shdr *shdr = elf_shdr; + + if (sh_type != NULL) + *sh_type = shdr->sh_type; + if (sh_flags != NULL) + *sh_flags = shdr->sh_flags; + if (sh_addr != NULL) + *sh_addr = (metal_phys_addr_t)shdr->sh_addr; + if (sh_offset != NULL) + *sh_offset = shdr->sh_offset; + if (sh_size != NULL) + *sh_size = shdr->sh_size; + if (sh_link != NULL) + *sh_link = shdr->sh_link; + if (sh_info != NULL) + *sh_info = shdr->sh_info; + if (sh_addralign != NULL) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize != NULL) + *sh_entsize = shdr->sh_entsize; + } else { + Elf64_Shdr *shdr = elf_shdr; + + if (sh_type != NULL) + *sh_type = shdr->sh_type; + if (sh_flags != NULL) + *sh_flags = shdr->sh_flags; + if (sh_addr != NULL) + *sh_addr = (metal_phys_addr_t)(shdr->sh_addr & + (metal_phys_addr_t)(-1)); + if (sh_offset != NULL) + *sh_offset = shdr->sh_offset; + if (sh_size != NULL) + *sh_size = shdr->sh_size; + if (sh_link != NULL) + *sh_link = shdr->sh_link; + if (sh_info != NULL) + *sh_info = shdr->sh_info; + if (sh_addralign != NULL) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize != NULL) + *sh_entsize = shdr->sh_entsize; + } +} + +static const void *elf_next_load_segment(void *elf_info, int *nseg, + metal_phys_addr_t *da, + size_t *noffset, size_t *nfsize, + size_t *nmsize) +{ + const void *phdr; + unsigned int p_type = PT_NULL; + + if (elf_info == NULL || nseg == NULL) + return NULL; + while(p_type != PT_LOAD) { + phdr = elf_get_segment_from_index(elf_info, *nseg); + if (phdr == NULL) + return NULL; + elf_parse_segment(elf_info, phdr, &p_type, noffset, + da, NULL, nfsize, nmsize); + *nseg = *nseg + 1; + } + return phdr; +} + +static size_t elf_info_size(const void *img_data) +{ + if (elf_is_64(img_data) == 0) + return sizeof(struct elf32_info); + else + return sizeof(struct elf64_info); +} + +int elf_identify(const void *img_data, size_t len) +{ + if (len < SELFMAG || img_data == NULL) + return -RPROC_EINVAL; + if (memcmp(img_data, ELFMAG, SELFMAG) != 0) + return -RPROC_EINVAL; + else + return 0; +} + +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen) +{ + unsigned int *load_state; + + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + /* Get ELF header */ + if (last_load_state == ELF_STATE_INIT) { + size_t tmpsize; + + metal_log(METAL_LOG_DEBUG, "Loading ELF headering\r\n"); + tmpsize = elf_ehdr_size(img_data); + if (len < tmpsize) { + *noffset = 0; + *nlen = tmpsize; + return ELF_STATE_INIT; + } else { + size_t infosize = elf_info_size(img_data); + + if (*img_info == NULL) { + *img_info = metal_allocate_memory(infosize); + if (*img_info == NULL) + return -ENOMEM; + memset(*img_info, 0, infosize); + } + memcpy(*img_info, img_data, tmpsize); + load_state = elf_load_state(*img_info); + *load_state = ELF_STATE_WAIT_FOR_PHDRS; + last_load_state = ELF_STATE_WAIT_FOR_PHDRS; + } + } + metal_assert(*img_info != NULL); + load_state = elf_load_state(*img_info); + if (last_load_state != (int)*load_state) + return -RPROC_EINVAL; + /* Get ELF program headers */ + if (*load_state == ELF_STATE_WAIT_FOR_PHDRS) { + size_t phdrs_size; + size_t phdrs_offset; + char **phdrs; + const void *img_phdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF program header.\r\n"); + phdrs_offset = elf_phoff(*img_info); + phdrs_size = elf_phnum(*img_info) * elf_phentsize(*img_info); + if (offset > phdrs_offset || + offset + len < phdrs_offset + phdrs_size) { + *noffset = phdrs_offset; + *nlen = phdrs_size; + return (int)*load_state; + } + /* caculate the programs headers offset to the image_data */ + phdrs_offset -= offset; + img_phdrs = (const void *) + ((const char *)img_data + phdrs_offset); + phdrs = (char **)elf_phtable_ptr(*img_info); + (*phdrs) = metal_allocate_memory(phdrs_size); + if (*phdrs == NULL) + return -ENOMEM; + memcpy((void *)(*phdrs), img_phdrs, phdrs_size); + *load_state = ELF_STATE_WAIT_FOR_SHDRS | + RPROC_LOADER_READY_TO_LOAD; + } + /* Get ELF Section Headers */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHDRS) != 0) { + size_t shdrs_size; + size_t shdrs_offset; + char **shdrs; + const void *img_shdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF section header.\r\n"); + shdrs_offset = elf_shoff(*img_info); + if (elf_shnum(*img_info) == 0) { + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return (int)*load_state; + } + shdrs_size = elf_shnum(*img_info) * elf_shentsize(*img_info); + if (offset > shdrs_offset || + offset + len < shdrs_offset + shdrs_size) { + *noffset = shdrs_offset; + *nlen = shdrs_size; + return (int)*load_state; + } + /* caculate the sections headers offset to the image_data */ + shdrs_offset -= offset; + img_shdrs = (const void *) + ((const char *)img_data + shdrs_offset); + shdrs = (char **)elf_shtable_ptr(*img_info); + (*shdrs) = metal_allocate_memory(shdrs_size); + if (*shdrs == NULL) + return -ENOMEM; + memcpy((void *)*shdrs, img_shdrs, shdrs_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_WAIT_FOR_SHSTRTAB; + metal_log(METAL_LOG_DEBUG, + "Loading ELF section header complete.\r\n"); + } + /* Get ELF SHSTRTAB section */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHSTRTAB) != 0) { + size_t shstrtab_size; + size_t shstrtab_offset; + int shstrndx; + void *shdr; + void **shstrtab; + + metal_log(METAL_LOG_DEBUG, "Loading ELF shstrtab.\r\n"); + shstrndx = elf_shstrndx(*img_info); + shdr = elf_get_section_from_index(*img_info, shstrndx); + if (shdr == NULL) + return -RPROC_EINVAL; + elf_parse_section(*img_info, shdr, NULL, NULL, + NULL, &shstrtab_offset, + &shstrtab_size, NULL, NULL, + NULL, NULL); + if (offset > shstrtab_offset || + offset + len < shstrtab_offset + shstrtab_size) { + *noffset = shstrtab_offset; + *nlen = shstrtab_size; + return (int)*load_state; + } + /* Caculate shstrtab section offset to the input image data */ + shstrtab_offset -= offset; + shstrtab = elf_shstrtab_ptr(*img_info); + *shstrtab = metal_allocate_memory(shstrtab_size); + if (*shstrtab == NULL) + return -ENOMEM; + memcpy(*shstrtab, + (const void *)((const char *)img_data + shstrtab_offset), + shstrtab_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return *load_state; + } + return last_load_state; +} + +int elf_load(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize) +{ + unsigned int *load_state; + const void *phdr; + + (void)rproc; + metal_assert(da != NULL); + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + if ((last_load_state & RPROC_LOADER_MASK) == RPROC_LOADER_NOT_READY) { + metal_log(METAL_LOG_DEBUG, + "%s, needs to load header first\r\n"); + last_load_state = elf_load_header(img_data, offset, len, + img_info, last_load_state, + noffset, nlen); + if ((last_load_state & RPROC_LOADER_MASK) == + RPROC_LOADER_NOT_READY) { + *da = RPROC_LOAD_ANYADDR; + return last_load_state; + } + } + metal_assert(img_info != NULL && *img_info != NULL); + load_state = elf_load_state(*img_info); + /* For ELF, segment padding value is 0 */ + if (padding != NULL) + *padding = 0; + if ((*load_state & RPROC_LOADER_READY_TO_LOAD) != 0) { + int nsegment; + size_t nsegmsize = 0; + size_t nsize = 0; + int phnums = 0; + + nsegment = (int)(*load_state & ELF_NEXT_SEGMENT_MASK); + phdr = elf_next_load_segment(*img_info, &nsegment, da, + noffset, &nsize, &nsegmsize); + if (phdr == NULL) { + metal_log(METAL_LOG_DEBUG, "cannot find more segement\r\n"); + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK); + return *load_state; + } + *nlen = nsize; + *nmemsize = nsegmsize; + phnums = elf_phnum(*img_info); + metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n", + nsegment, phnums); + if (nsegment == elf_phnum(*img_info)) { + *load_state = (*load_state & (~RPROC_LOADER_MASK)) | + RPROC_LOADER_POST_DATA_LOAD; + } + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK); + } else if ((*load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) { + last_load_state = elf_load_header(img_data, offset, + len, img_info, + last_load_state, + noffset, nlen); + if (last_load_state < 0) + return last_load_state; + if ((last_load_state & ELF_STATE_HDRS_COMPLETE) != 0) { + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + *nlen = 0; + } + *da = RPROC_LOAD_ANYADDR; + } else { + /* TODO: will handle relocate later */ + *nlen = 0; + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + } + } + return *load_state; +} + +void elf_release(void *img_info) +{ + if (img_info == NULL) + return; + if (elf_is_64(img_info) == 0) { + struct elf32_info *elf_info = img_info; + + if (elf_info->phdrs != NULL) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs != NULL) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab != NULL) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + + } else { + struct elf64_info *elf_info = img_info; + + if (elf_info->phdrs != NULL) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs != NULL) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab != NULL) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + } +} + +metal_phys_addr_t elf_get_entry(void *elf_info) +{ + if (!elf_info) + return METAL_BAD_PHYS; + + if (elf_is_64(elf_info) == 0) { + Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr *)elf_info; + Elf32_Addr e_entry; + + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)e_entry; + } else { + Elf64_Ehdr *elf_ehdr = (Elf64_Ehdr *)elf_info; + Elf64_Addr e_entry; + + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)(e_entry & (metal_phys_addr_t)(-1)); + } +} + +int elf_locate_rsc_table(void *elf_info, metal_phys_addr_t *da, + size_t *offset, size_t *size) +{ + char *sect_name = ".resource_table"; + void *shdr; + unsigned int *load_state; + + if (elf_info == NULL) + return -RPROC_EINVAL; + + load_state = elf_load_state(elf_info); + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) + return -RPROC_ERR_LOADER_STATE; + shdr = elf_get_section_from_name(elf_info, sect_name); + if (shdr == NULL) { + metal_assert(size != NULL); + *size = 0; + return 0; + } + elf_parse_section(elf_info, shdr, NULL, NULL, + da, offset, size, + NULL, NULL, NULL, NULL); + return 0; +} + +int elf_get_load_state(void *img_info) +{ + unsigned int *load_state; + + if (img_info == NULL) + return -RPROC_EINVAL; + load_state = elf_load_state(img_info); + return (int)(*load_state); +} + +struct loader_ops elf_ops = { + .load_header = elf_load_header, + .load_data = elf_load, + .locate_rsc_table = elf_locate_rsc_table, + .release = elf_release, + .get_entry = elf_get_entry, + .get_load_state = elf_get_load_state, +}; diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc.c new file mode 100644 index 0000000000..be9b869362 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2015 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * static functions + *****************************************************************************/ +static struct loader_ops * +remoteproc_check_fw_format(const void *img_data, size_t img_len) +{ + if (img_len <= 0) + return NULL; + else if (elf_identify(img_data, img_len) == 0) + return &elf_ops; + else + return NULL; +} + +static struct remoteproc_mem * +remoteproc_get_mem(struct remoteproc *rproc, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + void *va, size_t size) +{ + struct metal_list *node; + struct remoteproc_mem *mem; + + metal_list_for_each(&rproc->mems, node) { + mem = metal_container_of(node, struct remoteproc_mem, node); + if (name) { + if (!strncmp(name, mem->name, sizeof(mem->name))) + return mem; + } else if (pa != METAL_BAD_PHYS) { + metal_phys_addr_t pa_start, pa_end; + + pa_start = mem->pa; + pa_end = pa_start + mem->size; + if (pa >= pa_start && (pa + size) <= pa_end) + return mem; + } else if (da != METAL_BAD_PHYS) { + metal_phys_addr_t da_start, da_end; + + da_start = mem->da; + da_end = da_start + mem->size; + if (da >= da_start && (da + size) <= da_end) + return mem; + } else if (va) { + if (metal_io_virt_to_offset(mem->io, va) != + METAL_BAD_OFFSET) + return mem; + + } else { + return NULL; + } + } + return NULL; +} + +static metal_phys_addr_t +remoteproc_datopa(struct remoteproc_mem *mem, metal_phys_addr_t da) +{ + metal_phys_addr_t pa; + + pa = mem->pa + da - mem->da; + return pa; +} + +static metal_phys_addr_t +remoteproc_patoda(struct remoteproc_mem *mem, metal_phys_addr_t pa) +{ + metal_phys_addr_t da; + + da = mem->da + pa - mem->pa; + return da; +} + +static void *remoteproc_get_rsc_table(struct remoteproc *rproc, + void *store, + struct image_store_ops *store_ops, + size_t offset, + size_t len) +{ + int ret; + void *rsc_table = NULL; + const void *img_data; + + /* Copy the resource table to local memory, + * the caller should be responsible to release the memory + */ + rsc_table = metal_allocate_memory(len); + if (!rsc_table) { + return RPROC_ERR_PTR(-RPROC_ENOMEM); + } + ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < 0 || ret < (int)len || img_data == NULL) { + metal_log(METAL_LOG_ERROR, + "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len); + rsc_table = RPROC_ERR_PTR(-RPROC_EINVAL); + goto error; + } + memcpy(rsc_table, img_data, len); + + ret = handle_rsc_table(rproc, rsc_table, len, NULL); + if (ret < 0) { + rsc_table = RPROC_ERR_PTR(ret); + goto error; + } + return rsc_table; + +error: + metal_free_memory(rsc_table); + return rsc_table; +} + +int remoteproc_parse_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) +{ + struct metal_io_region *io; + + io = remoteproc_get_io_with_va(rproc, (void *)rsc_table); + return handle_rsc_table(rproc, rsc_table, rsc_size, io); +} + +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) +{ + int ret; + struct metal_io_region *io; + + io = remoteproc_get_io_with_va(rproc, (void *)rsc_table); + if (!io) + return -EINVAL; + ret = remoteproc_parse_rsc_table(rproc, rsc_table, rsc_size); + if (!ret) { + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_size; + rproc->rsc_io = io; + } + return ret; + +} + +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *priv) +{ + if (rproc) { + memset(rproc, 0, sizeof (*rproc)); + rproc->state = RPROC_OFFLINE; + metal_mutex_init(&rproc->lock); + metal_list_init(&rproc->mems); + metal_list_init(&rproc->vdevs); + } + rproc = ops->init(rproc, ops, priv); + return rproc; +} + +int remoteproc_remove(struct remoteproc *rproc) +{ + int ret; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) + rproc->ops->remove(rproc); + else + ret = -EBUSY; + metal_mutex_release(&rproc->lock); + } else { + ret = -EINVAL; + } + return ret; +} + +int remoteproc_config(struct remoteproc *rproc, void *data) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) { + /* configure operation is allowed if the state is + * offline or ready. This function can be called + * mulitple times before start the remote. + */ + if (rproc->ops->config) + ret = rproc->ops->config(rproc, data); + rproc->state = RPROC_READY; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_start(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_READY) { + ret = rproc->ops->start(rproc); + rproc->state = RPROC_RUNNING; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_stop(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_STOPPED && + rproc->state != RPROC_OFFLINE) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + rproc->state = RPROC_STOPPED; + } else { + ret = 0; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_shutdown(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + ret = 0; + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_OFFLINE) { + if (rproc->state != RPROC_STOPPED) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + } + if (!ret) { + if (rproc->ops->shutdown) + ret = rproc->ops->shutdown(rproc); + if (!ret) { + rproc->state = RPROC_OFFLINE; + } + } + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, name, + METAL_BAD_PHYS, METAL_BAD_PHYS, NULL, 0); + if (mem) + return mem->io; + else + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, NULL, pa, METAL_BAD_PHYS, NULL, 0); + if (mem) + return mem->io; + else + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, da, NULL, 0); + if (mem) { + struct metal_io_region *io; + metal_phys_addr_t pa; + + io = mem->io; + pa = remoteproc_datopa(mem, da); + *offset = metal_io_phys_to_offset(io, pa); + return io; + } else { + return NULL; + } +} + +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, void *va) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, METAL_BAD_PHYS, + va, 0); + if (mem) + return mem->io; + else + return NULL; +} + +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io) +{ + void *va = NULL; + metal_phys_addr_t lpa, lda; + struct remoteproc_mem *mem; + + if (!rproc) + return NULL; + else if (!pa && !da) + return NULL; + if (pa) + lpa = *pa; + else + lpa = METAL_BAD_PHYS; + if (da) + lda = *da; + else + lda = METAL_BAD_PHYS; + mem = remoteproc_get_mem(rproc, NULL, lpa, lda, NULL, size); + if (mem) { + if (lpa != METAL_BAD_PHYS) + lda = remoteproc_patoda(mem, lpa); + else if (lda != METAL_BAD_PHYS) + lpa = remoteproc_datopa(mem, lda); + if (io) + *io = mem->io; + va = metal_io_phys_to_virt(mem->io, lpa); + } else if (rproc->ops->mmap) { + va = rproc->ops->mmap(rproc, &lpa, &lda, size, attribute, io); + } + + if (pa) + *pa = lpa; + if (da) + *da = lda; + return va; +} + +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, struct image_store_ops *store_ops, + void **img_info) +{ + int ret; + struct loader_ops *loader; + const void *img_data; + void *limg_info = NULL; + size_t offset, noffset; + size_t len, nlen; + int last_load_state; + metal_phys_addr_t da, rsc_da; + int rsc_len; + size_t rsc_size; + void *rsc_table = NULL; + struct metal_io_region *io = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY && rproc->state != RPROC_CONFIGURED) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + if (!store_ops) { + metal_log(METAL_LOG_ERROR, + "load failure: loader ops is not set.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + /* Open exectuable to get ready to parse */ + metal_log(METAL_LOG_DEBUG, "%s: open exectuable image\r\n", __func__); + ret = store_ops->open(store, path, &img_data); + if (ret <= 0) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to open firmware %d.\n", + ret); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + len = ret; + metal_assert(img_data != NULL); + + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to get store ops.\n"); + ret = -RPROC_EINVAL; + goto error1; + } + rproc->loader = loader; + } + + /* Load exectuable headers */ + metal_log(METAL_LOG_DEBUG, "%s: loading headers\r\n", __func__); + offset = 0; + last_load_state = RPROC_LOADER_NOT_READY; + while(1) { + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + &noffset, &nlen); + last_load_state = (unsigned int)ret; + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, noffset, nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + + goto error2; + } else if ((ret & RPROC_LOADER_READY_TO_LOAD) != 0) { + if (nlen == 0) + break; + else if ((noffset > (offset + len)) && + (store_ops->features & SUPPORT_SEEK) == 0) { + /* Required data is not continued, however + * seek is not supported, stop to load + * headers such as ELF section headers which + * is usually located to the end of image. + * Continue to load binary data to target + * memory. + */ + break; + } + } + /* Continue to load headers image data */ + img_data = NULL; + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error2; + } + offset = noffset; + len = nlen; + } + ret = elf_locate_rsc_table(limg_info, &rsc_da, &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_len = (int)rsc_size; + rsc_table = remoteproc_get_rsc_table(rproc, store, store_ops, + offset, rsc_len); + } else { + rsc_len = ret; + } + + /* load executable data */ + metal_log(METAL_LOG_DEBUG, "%s: load executable data\r\n", __func__); + offset = 0; + len = 0; + ret = -EINVAL; + while(1) { + unsigned char padding; + size_t nmemsize; + metal_phys_addr_t pa; + + da = RPROC_LOAD_ANYADDR; + nlen = 0; + nmemsize = 0; + noffset = 0; + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + &noffset, &nlen, &padding, &nmemsize); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + noffset, nlen); + goto error3; + } + metal_log(METAL_LOG_DEBUG, + "load data: da 0x%lx, offset 0x%lx, len = 0x%lx, memsize = 0x%lx, state 0x%x\r\n", + da, noffset, nlen, nmemsize, ret); + last_load_state = ret; + if (da != RPROC_LOAD_ANYADDR) { + /* Data is supposed to be loaded to target memory */ + img_data = NULL; + /* get the I/O region from remoteproc */ + pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, &pa, &da, nmemsize, 0, &io); + if (pa == METAL_BAD_PHYS || io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error3; + } + if (nlen > 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, pa, io, 1); + if (ret != (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load data failed 0x%lx, 0x%lx, 0x%x\r\n", + pa, noffset, nlen); + ret = -RPROC_EINVAL; + goto error3; + } + } + if (nmemsize > nlen) { + size_t tmpoffset; + + tmpoffset = metal_io_phys_to_offset(io, + pa + nlen); + metal_io_block_set(io, tmpoffset, + padding, (nmemsize - nlen)); + } + } else if (nlen != 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + if ((last_load_state & + RPROC_LOADER_POST_DATA_LOAD) != 0) { + metal_log(METAL_LOG_WARNING, + "not all the headers are loaded\r\n"); + break; + } + metal_log(METAL_LOG_ERROR, + "post-load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error3; + } + offset = noffset; + len = nlen; + } else { + /* (last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0 */ + break; + } + } + + if (rsc_len < 0) { + ret = elf_locate_rsc_table(limg_info, &rsc_da, + &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_len = (int)rsc_size; + rsc_table = remoteproc_get_rsc_table(rproc, store, + store_ops, + offset, + rsc_len); + } + } + + /* Update resource table */ + if (rsc_len && rsc_da != METAL_BAD_PHYS) { + void *rsc_table_cp = rsc_table; + + metal_log(METAL_LOG_DEBUG, + "%s, update resource table\r\n", __func__); + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_len, 0, &io); + if (rsc_table) { + size_t rsc_io_offset; + + /* Update resource table */ + rsc_io_offset = metal_io_virt_to_offset(io, rsc_table); + ret = metal_io_block_write(io, rsc_io_offset, + rsc_table_cp, rsc_len); + if (ret != rsc_len) { + metal_log(METAL_LOG_WARNING, + "load: failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_len; + } else { + metal_log(METAL_LOG_WARNING, + "load: not able to update rsc table.\n"); + } + metal_free_memory(rsc_table_cp); + /* So that the rsc_table will not get released */ + rsc_table = NULL; + } + + metal_log(METAL_LOG_DEBUG, "%s: successfully load firmware\r\n", + __func__); + /* get entry point from the firmware */ + rproc->bootaddr = loader->get_entry(limg_info); + rproc->state = RPROC_READY; + + metal_mutex_release(&rproc->lock); + if (img_info) + *img_info = limg_info; + else + loader->release(limg_info); + store_ops->close(store); + return 0; + +error3: + if (rsc_table) + metal_free_memory(rsc_table); +error2: + loader->release(limg_info); +error1: + store_ops->close(store); + metal_mutex_release(&rproc->lock); + return ret; +} + +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding) +{ + int ret; + struct loader_ops *loader; + void *limg_info = NULL; + int last_load_state; + metal_phys_addr_t da, rsc_da; + size_t rsc_size; + void *rsc_table = NULL, *lrsc_table = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_assert(pa != NULL); + metal_assert(io != NULL); + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + metal_assert(nmlen != NULL); + metal_assert(padding != NULL); + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + if (img_data == NULL || offset != 0 || len == 0) { + metal_log(METAL_LOG_ERROR, + "load failure, invalid inputs, not able to identify image.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to identify image.\n"); + ret = -RPROC_EINVAL; + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + rproc->loader = loader; + } + if (img_info == NULL || *img_info == NULL ) { + last_load_state = 0; + } else { + limg_info = *img_info; + last_load_state = loader->get_load_state(limg_info); + if (last_load_state < 0) { + metal_log(METAL_LOG_ERROR, + "load failure, not able get load state.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + } + da = RPROC_LOAD_ANYADDR; + *nlen = 0; + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0 && + (last_load_state & RPROC_LOADER_LOAD_COMPLETE) == 0) { + /* Get the mandatory executable headers */ + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + noffset, nlen); + last_load_state = (unsigned int)ret; + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + + goto error1; + } + last_load_state = loader->get_load_state(limg_info); + if (*nlen != 0 && + (last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0) + goto out; + } + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) != 0 || + (last_load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + /* Enough information to know which target memory for + * which data. + */ + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + noffset, nlen, padding, nmlen); + metal_log(METAL_LOG_DEBUG, + "%s, load data 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + offset, len); + goto error1; + } + if (da != RPROC_LOAD_ANYADDR) { + /* get the I/O region from remoteproc */ + *pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, pa, &da, *nmlen, 0, io); + if (*pa == METAL_BAD_PHYS || io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error1; + } + } + if (*nlen != 0) + goto out; + else + last_load_state = loader->get_load_state(limg_info); + } + if ((last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0) { + /* Get resource table */ + size_t rsc_offset; + size_t rsc_io_offset; + + ret = elf_locate_rsc_table(limg_info, &rsc_da, + &rsc_offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + lrsc_table = metal_allocate_memory(rsc_size); + if (lrsc_table == NULL) { + ret = -RPROC_ENOMEM; + goto error1; + } + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_size, 0, io); + if (*io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to mmap rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + rsc_io_offset = metal_io_virt_to_offset(*io, rsc_table); + ret = metal_io_block_read(*io, rsc_io_offset, + lrsc_table, (int)rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to get rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* parse resource table */ + ret = remoteproc_parse_rsc_table(rproc, lrsc_table, + rsc_size); + if (ret == (int)rsc_size) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to parse rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* Update resource table */ + ret = metal_io_block_write(*io, rsc_io_offset, + lrsc_table, (int)rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_WARNING, + "load exectuable, failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = (int)rsc_size; + metal_free_memory(lrsc_table); + } + } +out: + if (img_info != NULL) + *img_info = limg_info; + else + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return 0; + +error1: + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return ret; +} + +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end) +{ + unsigned int notifyid; + + if (start == RSC_NOTIFY_ID_ANY) + start = 0; + if (end == RSC_NOTIFY_ID_ANY) + end = METAL_BITS_PER_ULONG; + notifyid = metal_bitmap_next_set_bit(&rproc->bitmap, + start, end); + if (notifyid != end) + metal_bitmap_set_bit(&rproc->bitmap, notifyid); + return notifyid; +} + +static int remoteproc_virtio_notify(void *priv, uint32_t id) +{ + struct remoteproc *rproc = priv; + + return rproc->ops->notify(rproc, id); +} + +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)) +{ + char *rsc_table; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *vdev_rsc_io; + struct virtio_device *vdev; + struct remoteproc_virtio *rpvdev; + size_t vdev_rsc_offset; + unsigned int notifyid; + unsigned int num_vrings, i; + struct metal_list *node; + + metal_assert(rproc); + metal_mutex_acquire(&rproc->lock); + rsc_table = rproc->rsc_table; + vdev_rsc_io = rproc->rsc_io; + vdev_rsc_offset = find_rsc(rsc_table, RSC_VDEV, vdev_id); + if (!vdev_rsc_offset) { + metal_mutex_release(&rproc->lock); + return NULL; + } + vdev_rsc = (struct fw_rsc_vdev *)(rsc_table + vdev_rsc_offset); + notifyid = vdev_rsc->notifyid; + /* Check if the virtio device is already created */ + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + if (rpvdev->vdev.index == notifyid) + return &rpvdev->vdev; + } + vdev = rproc_virtio_create_vdev(role, notifyid, + vdev_rsc, vdev_rsc_io, rproc, + remoteproc_virtio_notify, + rst_cb); + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_add_tail(&rproc->vdevs, &rpvdev->node); + num_vrings = vdev_rsc->num_of_vrings; + /* set the notification id for vrings */ + for (i = 0; i < num_vrings; i++) { + struct fw_rsc_vdev_vring *vring_rsc; + metal_phys_addr_t da; + unsigned int num_descs, align; + struct metal_io_region *io; + void *va; + size_t size; + int ret; + + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + da = vring_rsc->da; + num_descs = vring_rsc->num; + align = vring_rsc->align; + size = vring_size(num_descs, align); + va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io); + if (!va) + goto err1; + ret = rproc_virtio_init_vring(vdev, i, notifyid, + va, io, num_descs, align); + if (ret) + goto err1; + } + metal_mutex_release(&rproc->lock); + return vdev; + +err1: + remoteproc_remove_virtio(rproc, vdev); + metal_mutex_release(&rproc->lock); + return NULL; +} + +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + + (void)rproc; + metal_assert(vdev); + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_del(&rpvdev->node); + rproc_virtio_remove_vdev(&rpvdev->vdev); +} + +int remoteproc_get_notification(struct remoteproc *rproc, uint32_t notifyid) +{ + struct remoteproc_virtio *rpvdev; + struct metal_list *node; + int ret; + + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + ret = rproc_virtio_notified(&rpvdev->vdev, notifyid); + if (ret) + return ret; + } + return 0; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc_virtio.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc_virtio.c new file mode 100644 index 0000000000..0059718dc1 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/remoteproc_virtio.c @@ -0,0 +1,330 @@ +/* + * Remoteproc Virtio Framework Implementation + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Texas Instruments 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 + * OWNER 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 +#include + +static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) +{ + struct remoteproc_virtio *rpvdev; + struct virtio_vring_info *vring_info; + struct virtio_device *vdev; + unsigned int vq_id = vq->vq_queue_index; + + vdev = vq->vq_dev; + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_assert(vq_id <= vdev->vrings_num); + vring_info = &vdev->vrings_info[vq_id]; + rpvdev->notify(rpvdev->priv, vring_info->notifyid); +} + +static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + char status; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + status = metal_io_read8(io, + metal_io_virt_to_offset(io, &vdev_rsc->status)); + return status; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_set_status(struct virtio_device *vdev, + unsigned char status) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + metal_io_write8(io, + metal_io_virt_to_offset(io, &vdev_rsc->status), + status); + rpvdev->notify(rpvdev->priv, vdev->index); +} +#endif + +static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + uint32_t features; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + /* TODO: shall we get features based on the role ? */ + features = metal_io_read32(io, + metal_io_virt_to_offset(io, &vdev_rsc->dfeatures)); + + return features; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_set_features(struct virtio_device *vdev, + uint32_t features) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + /* TODO: shall we set features based on the role ? */ + metal_io_write32(io, + metal_io_virt_to_offset(io, &vdev_rsc->dfeatures), + features); + rpvdev->notify(rpvdev->priv, vdev->index); +} +#endif + +static uint32_t rproc_virtio_negotiate_features(struct virtio_device *vdev, + uint32_t features) +{ + (void)vdev; + (void)features; + + return 0; +} + +static void rproc_virtio_read_config(struct virtio_device *vdev, + uint32_t offset, void *dst, int length) +{ + (void)vdev; + (void)offset; + (void)dst; + (void)length; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_write_config(struct virtio_device *vdev, + uint32_t offset, void *src, int length) +{ + (void)vdev; + (void)offset; + (void)src; + (void)length; +} + +static void rproc_virtio_reset_device(struct virtio_device *vdev) +{ + if (vdev->role == VIRTIO_DEV_MASTER) + rproc_virtio_set_status(vdev, + VIRTIO_CONFIG_STATUS_NEEDS_RESET); +} +#endif + +const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { + .get_status = rproc_virtio_get_status, + .get_features = rproc_virtio_get_features, + .read_config = rproc_virtio_read_config, + .notify = rproc_virtio_virtqueue_notify, + .negotiate_features = rproc_virtio_negotiate_features, +#ifndef VIRTIO_SLAVE_ONLY + /* + * We suppose here that the vdev is in a shared memory so that can + * be access only by one core: the master. In this case salve core has + * only read access right. + */ + .set_status = rproc_virtio_set_status, + .set_features = rproc_virtio_set_features, + .write_config = rproc_virtio_write_config, + .reset_device = rproc_virtio_reset_device, +#endif +}; + +struct virtio_device * +rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, + void *rsc, struct metal_io_region *rsc_io, + void *priv, + rpvdev_notify_func notify, + virtio_dev_reset_cb rst_cb) +{ + struct remoteproc_virtio *rpvdev; + struct virtio_vring_info *vrings_info; + struct fw_rsc_vdev *vdev_rsc = rsc; + struct virtio_device *vdev; + unsigned int num_vrings = vdev_rsc->num_of_vrings; + unsigned int i; + + rpvdev = metal_allocate_memory(sizeof(*rpvdev)); + if (!rpvdev) + return NULL; + vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings); + if (!vrings_info) + goto err0; + memset(rpvdev, 0, sizeof(*rpvdev)); + memset(vrings_info, 0, sizeof(*vrings_info)); + vdev = &rpvdev->vdev; + + for (i = 0; i < num_vrings; i++) { + struct virtqueue *vq; + struct fw_rsc_vdev_vring *vring_rsc; + unsigned int num_extra_desc = 0; + + vring_rsc = &vdev_rsc->vring[i]; + if (role == VIRTIO_DEV_MASTER) { + num_extra_desc = vring_rsc->num; + } + vq = virtqueue_allocate(num_extra_desc); + if (!vq) + goto err1; + vrings_info[i].vq = vq; + } + + /* FIXME commended as seems not nedded, already stored in vdev */ + //rpvdev->notifyid = notifyid; + rpvdev->notify = notify; + rpvdev->priv = priv; + vdev->vrings_info = vrings_info; + /* Assuming the shared memory has been mapped and registered if + * necessary + */ + rpvdev->vdev_rsc = vdev_rsc; + rpvdev->vdev_rsc_io = rsc_io; + + vdev->index = notifyid; + vdev->role = role; + vdev->reset_cb = rst_cb; + vdev->vrings_num = num_vrings; + vdev->func = &remoteproc_virtio_dispatch_funcs; + /* TODO: Shall we set features here ? */ + + return &rpvdev->vdev; + +err1: + for (i = 0; i < num_vrings; i++) { + if (vrings_info[i].vq) + metal_free_memory(vrings_info[i].vq); + } + metal_free_memory(vrings_info); +err0: + metal_free_memory(rpvdev); + return NULL; +} + +void rproc_virtio_remove_vdev(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + unsigned int i; + + if (!vdev) + return; + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + for (i = 0; i < vdev->vrings_num; i++) { + struct virtqueue *vq; + + vq = vdev->vrings_info[i].vq; + if (vq) + metal_free_memory(vq); + } + metal_free_memory(vdev->vrings_info); + metal_free_memory(rpvdev); +} + +int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, + unsigned int notifyid, void *va, + struct metal_io_region *io, + unsigned int num_descs, unsigned int align) +{ + struct virtio_vring_info *vring_info; + unsigned int num_vrings; + + num_vrings = vdev->vrings_num; + if (index >= num_vrings) + return -RPROC_EINVAL; + vring_info = &vdev->vrings_info[index]; + vring_info->io = io; + vring_info->notifyid = notifyid; + vring_info->info.vaddr = va; + vring_info->info.num_descs = num_descs; + vring_info->info.align = align; + + return 0; +} + +int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid) +{ + unsigned int num_vrings, i; + struct virtio_vring_info *vring_info; + struct virtqueue *vq; + + if (!vdev) + return -EINVAL; + /* We do nothing for vdev notification in this implementation */ + if (vdev->index == notifyid) + return 0; + num_vrings = vdev->vrings_num; + for (i = 0; i < num_vrings; i++) { + vring_info = &vdev->vrings_info[i]; + if (vring_info->notifyid == notifyid || + notifyid == RSC_NOTIFY_ID_ANY) { + vq = vring_info->vq; + virtqueue_notification(vq); + } + } + return 0; +} + +void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) +{ + uint8_t status; + + /* + * No status available for slave. As Master has not to wait + * slave action, we can return. Behavior should be updated + * in future if a slave status is added. + */ + if (vdev->role == VIRTIO_DEV_MASTER) + return; + + while (1) { + status = rproc_virtio_get_status(vdev); + if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) + return; + } +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/rsc_table_parser.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/rsc_table_parser.c new file mode 100644 index 0000000000..37c6478011 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/remoteproc/rsc_table_parser.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2018, Xilinx Inc. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc); + +/* Resources handler */ +rsc_handler rsc_handler_table[] = { + handle_carve_out_rsc, /**< carved out resource */ + handle_dummy_rsc, /**< IOMMU dev mem resource */ + handle_trace_rsc, /**< trace buffer resource */ + handle_vdev_rsc, /**< virtio resource */ + handle_dummy_rsc, /**< rproc shared memory resource */ + handle_dummy_rsc, /**< firmware checksum resource */ +}; + +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, int size, + struct metal_io_region *io) +{ + char *rsc_start; + unsigned int rsc_type; + unsigned int idx, offset; + int status = 0; + + /* Validate rsc table header fields */ + + /* Minimum rsc table size */ + if (sizeof(struct resource_table) > (unsigned int)size) { + return -RPROC_ERR_RSC_TAB_TRUNC; + } + + /* Supported version */ + if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) { + return -RPROC_ERR_RSC_TAB_VER; + } + + /* Offset array */ + offset = sizeof(struct resource_table) + + rsc_table->num * sizeof(rsc_table->offset[0]); + + if (offset > (unsigned int)size) { + return -RPROC_ERR_RSC_TAB_TRUNC; + } + + /* Reserved fields - must be zero */ + if ((rsc_table->reserved[0] != 0 || rsc_table->reserved[1]) != 0) { + return -RPROC_ERR_RSC_TAB_RSVD; + } + + /* Loop through the offset array and parse each resource entry */ + for (idx = 0; idx < rsc_table->num; idx++) { + rsc_start = (char *)rsc_table; + rsc_start += rsc_table->offset[idx]; + if (io && + metal_io_virt_to_offset(io, rsc_start) == METAL_BAD_OFFSET) + return -RPROC_ERR_RSC_TAB_TRUNC; + rsc_type = *((uint32_t *)rsc_start); + if (rsc_type < RSC_LAST) + status = rsc_handler_table[rsc_type](rproc, + rsc_start); + else if (rsc_type >= RSC_VENDOR_START && + rsc_type <= RSC_VENDOR_END) + status = handle_vendor_rsc(rproc, rsc_start); + if (status == -RPROC_ERR_RSC_TAB_NS) { + status = 0; + continue; + } + else if (status) + break; + } + + return status; +} + +/** + * handle_carve_out_rsc + * + * Carveout resource handler. + * + * @param rproc - pointer to remote remoteproc + * @param rsc - pointer to carveout resource + * + * @returns - 0 for success, or negative value for failure + * + */ +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_carveout *carve_rsc = (struct fw_rsc_carveout *)rsc; + metal_phys_addr_t da; + metal_phys_addr_t pa; + size_t size; + unsigned int attribute; + + /* Validate resource fields */ + if (!carve_rsc) { + return -RPROC_ERR_RSC_TAB_NP; + } + + if (carve_rsc->reserved) { + return -RPROC_ERR_RSC_TAB_RSVD; + } + pa = carve_rsc->pa; + da = carve_rsc->da; + size = carve_rsc->len; + attribute = carve_rsc->flags; + if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL)) + return 0; + else + return -RPROC_EINVAL; +} + +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) +{ + if (rproc && rproc->ops->handle_rsc) { + struct fw_rsc_vendor *vend_rsc = rsc; + size_t len = vend_rsc->len; + + return rproc->ops->handle_rsc(rproc, rsc, len); + } + return -RPROC_ERR_RSC_TAB_NS; +} + +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_vdev *vdev_rsc = (struct fw_rsc_vdev *)rsc; + unsigned int notifyid, i, num_vrings; + + /* only assign notification IDs but do not initialize vdev */ + notifyid = vdev_rsc->notifyid; + if (notifyid == RSC_NOTIFY_ID_ANY) { + notifyid = remoteproc_allocate_id(rproc, + notifyid, notifyid + 1); + vdev_rsc->notifyid = notifyid; + } + + num_vrings = vdev_rsc->num_of_vrings; + for (i = 0; i < num_vrings; i++) { + struct fw_rsc_vdev_vring *vring_rsc; + + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + if (notifyid == RSC_NOTIFY_ID_ANY) { + notifyid = remoteproc_allocate_id(rproc, + notifyid, + notifyid + 1); + vdev_rsc->notifyid = notifyid; + } + } + + return 0; +} + +/** + * handle_trace_rsc + * + * trace resource handler. + * + * @param rproc - pointer to remote remoteproc + * @param rsc - pointer to trace resource + * + * @returns - no service error + * + */ +int handle_trace_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_trace *vdev_rsc = (struct fw_rsc_trace *)rsc; + (void)rproc; + + if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) + return 0; + /* FIXME: master should allocated a memory used by slave */ + + return -RPROC_ERR_RSC_TAB_NS; +} + +/** + * handle_dummy_rsc + * + * dummy resource handler. + * + * @param rproc - pointer to remote remoteproc + * @param rsc - pointer to trace resource + * + * @returns - no service error + * + */ +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc) +{ + (void)rproc; + (void)rsc; + + return -RPROC_ERR_RSC_TAB_NS; +} + +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index) +{ + struct resource_table *r_table = rsc_table; + unsigned int i, rsc_index; + unsigned int lrsc_type; + char *rsc_start; + + metal_assert(r_table); + /* Loop through the offset array and parse each resource entry */ + rsc_index = 0; + for (i = 0; i < r_table->num; i++) { + rsc_start = (char *)r_table; + rsc_start += r_table->offset[i]; + lrsc_type = *((uint32_t *)rsc_start); + if (lrsc_type == rsc_type) { + if (rsc_index++ == index) + return r_table->offset[i]; + } + } + return 0; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/CMakeLists.txt b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/CMakeLists.txt new file mode 100644 index 0000000000..e2bd8d8051 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/CMakeLists.txt @@ -0,0 +1,2 @@ +collect (PROJECT_LIB_SOURCES rpmsg.c) +collect (PROJECT_LIB_SOURCES rpmsg_virtio.c) diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg.c new file mode 100644 index 0000000000..0638a4f2e3 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (c) 2018 Linaro, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "rpmsg_internal.h" + +/** + * rpmsg_get_address + * + * This function provides unique 32 bit address. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * + * return - a unique address + */ +static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) +{ + unsigned int addr = RPMSG_ADDR_ANY; + unsigned int nextbit; + + nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size); + if (nextbit < (uint32_t)size) { + addr = nextbit; + metal_bitmap_set_bit(bitmap, nextbit); + } + + return addr; +} + +/** + * rpmsg_release_address + * + * Frees the given address. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free + */ +static void rpmsg_release_address(unsigned long *bitmap, int size, + int addr) +{ + if (addr < size) + metal_bitmap_clear_bit(bitmap, addr); +} + +/** + * rpmsg_is_address_set + * + * Checks whether address is used or free. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free + * + * return - TRUE/FALSE + */ +static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr) +{ + if (addr < size) + return metal_bitmap_is_bit_set(bitmap, addr); + else + return RPMSG_ERR_PARAM; +} + +/** + * rpmsg_set_address + * + * Marks the address as consumed. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free + * + * return - none + */ +static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) +{ + if (addr < size) { + metal_bitmap_set_bit(bitmap, addr); + return RPMSG_SUCCESS; + } else { + return RPMSG_ERR_PARAM; + } +} + +/** + * This function sends rpmsg "message" to remote device. + * + * @param ept - pointer to end point + * @param src - source address of channel + * @param dst - destination address of channel + * @param data - data to transmit + * @param size - size of data + * @param wait - boolean, wait or not for buffer to become + * available + * + * @return - size of data sent or negative value for failure. + * + */ +int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int size, + int wait) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY) + return RPMSG_ERR_PARAM; + + rdev = ept->rdev; + + if (rdev->ops.send_offchannel_raw) + return rdev->ops.send_offchannel_raw(rdev, src, dst, data, + size, wait); + + return RPMSG_ERR_PARAM; +} + +int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags) +{ + struct rpmsg_ns_msg ns_msg; + int ret; + + ns_msg.flags = flags; + ns_msg.addr = ept->addr; + strncpy(ns_msg.name, ept->name, sizeof(ns_msg.name)); + ret = rpmsg_send_offchannel_raw(ept, ept->addr, + RPMSG_NS_EPT_ADDR, + &ns_msg, sizeof(ns_msg), true); + if (ret < 0) + return ret; + else + return RPMSG_SUCCESS; +} + +struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, + const char *name, uint32_t addr, + uint32_t dest_addr) +{ + struct metal_list *node; + struct rpmsg_endpoint *ept; + + metal_list_for_each(&rdev->endpoints, node) { + int name_match = 0; + + ept = metal_container_of(node, struct rpmsg_endpoint, node); + /* try to get by local address only */ + if (addr != RPMSG_ADDR_ANY && ept->addr == addr) + return ept; + /* try to find match on local end remote address */ + if (addr == ept->addr && dest_addr == ept->dest_addr) + return ept; + /* else use name service and destination address */ + if (name) + name_match = !strncmp(ept->name, name, + sizeof(ept->name)); + if (!name || !name_match) + continue; + /* destination address is known, equal to ept remote address*/ + if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr) + return ept; + /* ept is registered but not associated to remote ept*/ + if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY) + return ept; + } + return NULL; +} + +static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept) +{ + struct rpmsg_device *rdev; + + if (!ept) + return; + + rdev = ept->rdev; + + if (ept->addr != RPMSG_ADDR_ANY) + rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, + ept->addr); + metal_list_del(&ept->node); +} + +int rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept) +{ + ept->rdev = rdev; + + metal_list_add_tail(&rdev->endpoints, &ept->node); + return RPMSG_SUCCESS; +} + +int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, + const char *name, uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb) +{ + int status; + uint32_t addr = src; + + if (!ept) + return RPMSG_ERR_PARAM; + + metal_mutex_acquire(&rdev->lock); + if (src != RPMSG_ADDR_ANY) { + status = rpmsg_is_address_set(rdev->bitmap, + RPMSG_ADDR_BMP_SIZE, src); + if (!status) { + /* Mark the address as used in the address bitmap. */ + rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, + src); + } else if (status > 0) { + status = RPMSG_SUCCESS; + goto ret_status; + } else { + goto ret_status; + } + } else { + addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); + } + + rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb); + + status = rpmsg_register_endpoint(rdev, ept); + if (status < 0) + rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr); + + if (!status && ept->dest_addr == RPMSG_ADDR_ANY) { + /* Send NS announcement to remote processor */ + metal_mutex_release(&rdev->lock); + status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE); + metal_mutex_acquire(&rdev->lock); + if (status) + rpmsg_unregister_endpoint(ept); + } + +ret_status: + metal_mutex_release(&rdev->lock); + return status; +} + +/** + * rpmsg_destroy_ept + * + * This function deletes rpmsg endpoint and performs cleanup. + * + * @param ept - pointer to endpoint to destroy + * + */ +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) +{ + struct rpmsg_device *rdev; + + if (!ept) + return; + + rdev = ept->rdev; + if (ept->addr != RPMSG_NS_EPT_ADDR) + (void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY); + metal_mutex_acquire(&rdev->lock); + rpmsg_unregister_endpoint(ept); + metal_mutex_release(&rdev->lock); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_internal.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_internal.h new file mode 100644 index 0000000000..e1b82086c9 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_internal.h @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef _RPMSG_INTERNAL_H_ +#define _RPMSG_INTERNAL_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#ifdef RPMSG_DEBUG +#define RPMSG_ASSERT(_exp, _msg) do { \ + if (!(_exp)) { \ + openamp_print("FATAL: %s - _msg", __func__); \ + while (1) { \ + ; \ + } \ + } \ + } while (0) +#else +#define RPMSG_ASSERT(_exp, _msg) do { \ + if (!(_exp)) \ + while (1) { \ + ; \ + } \ + } while (0) +#endif + +#define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr)) +/** + * enum rpmsg_ns_flags - dynamic name service announcement flags + * + * @RPMSG_NS_CREATE: a new remote service was just created + * @RPMSG_NS_DESTROY: a known remote service was just destroyed + * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting + * acknowledgment. + */ +enum rpmsg_ns_flags { + RPMSG_NS_CREATE = 0, + RPMSG_NS_DESTROY = 1, +}; + +/** + * struct rpmsg_hdr - common header for all rpmsg messages + * @src: source address + * @dst: destination address + * @reserved: reserved for future use + * @len: length of payload (in bytes) + * @flags: message flags + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +OPENAMP_PACKED_BEGIN +struct rpmsg_hdr { + uint32_t src; + uint32_t dst; + uint32_t reserved; + uint16_t len; + uint16_t flags; +} OPENAMP_PACKED_END; + +/** + * 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). + */ +OPENAMP_PACKED_BEGIN +struct rpmsg_ns_msg { + char name[RPMSG_NAME_SIZE]; + uint32_t addr; + uint32_t flags; +} OPENAMP_PACKED_END; + +int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags); + +struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev, + const char *name, uint32_t addr, + uint32_t dest_addr); +int rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept); + +static inline struct rpmsg_endpoint * +rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) +{ + return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); +} + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_INTERNAL_H_ */ diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_virtio.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_virtio.c new file mode 100644 index 0000000000..8ae41089fe --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/rpmsg/rpmsg_virtio.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (c) 2018 Linaro, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +#define RPMSG_NUM_VRINGS (2) + +/* Total tick count for 15secs - 1msec tick. */ +#define RPMSG_TICK_COUNT 15000 + +/* Time to wait - In multiple of 10 msecs. */ +#define RPMSG_TICKS_PER_INTERVAL 10 + +#define WORD_SIZE sizeof(unsigned long) +#define WORD_ALIGN(a) ((((a) & (WORD_SIZE - 1)) != 0) ? \ + (((a) & (~(WORD_SIZE - 1))) + WORD_SIZE) : (a)) + +#ifndef VIRTIO_SLAVE_ONLY +metal_weak void * +rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, + size_t size) +{ + void *buffer; + + if (shpool->avail < size) + return NULL; + buffer = (void *)((char *)shpool->base + shpool->size - shpool->avail); + shpool->avail -= size; + + return buffer; +} +#endif /*!VIRTIO_SLAVE_ONLY*/ + +void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shb, size_t size) +{ + if (!shpool) + return; + shpool->base = shb; + shpool->size = WORD_ALIGN(size); + shpool->avail = WORD_ALIGN(size); +} + +/** + * rpmsg_virtio_return_buffer + * + * Places the used buffer back on the virtqueue. + * + * @param rvdev - pointer to remote core + * @param buffer - buffer pointer + * @param len - buffer length + * @param idx - buffer index + * + */ +static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev, + void *buffer, unsigned long len, + unsigned short idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + + (void)idx; + /* Initialize buffer node */ + vqbuf.buf = buffer; + vqbuf.len = len; + virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); + } +#endif /*VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + (void)buffer; + virtqueue_add_consumed_buffer(rvdev->rvq, idx, len); + } +#endif /*VIRTIO_MASTER_ONLY*/ +} + +/** + * rpmsg_virtio_enqueue_buffer + * + * Places buffer on the virtqueue for consumption by the other side. + * + * @param rvdev - pointer to rpmsg virtio + * @param buffer - buffer pointer + * @param len - buffer length + * @param idx - buffer index + * + * @return - status of function execution + */ +static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, + void *buffer, unsigned long len, + unsigned short idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + (void)idx; + + /* Initialize buffer node */ + vqbuf.buf = buffer; + vqbuf.len = len; + return virtqueue_add_buffer(rvdev->svq, &vqbuf, 0, 1, buffer); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + (void)buffer; + return virtqueue_add_consumed_buffer(rvdev->svq, idx, len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + return 0; +} + +/** + * rpmsg_virtio_get_tx_buffer + * + * Provides buffer to transmit messages. + * + * @param rvdev - pointer to rpmsg device + * @param len - length of returned buffer + * @param idx - buffer index + * + * return - pointer to buffer. + */ +static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, + unsigned long *len, + unsigned short *idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + void *data = NULL; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + data = virtqueue_get_buffer(rvdev->svq, (uint32_t *)len, idx); + if (data == NULL) { + data = rpmsg_virtio_shm_pool_get_buffer(rvdev->shpool, + RPMSG_BUFFER_SIZE); + *len = RPMSG_BUFFER_SIZE; + } + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + data = virtqueue_get_available_buffer(rvdev->svq, idx, + (uint32_t *)len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + return data; +} + +/** + * rpmsg_virtio_get_rx_buffer + * + * Retrieves the received buffer from the virtqueue. + * + * @param rvdev - pointer to rpmsg device + * @param len - size of received buffer + * @param idx - index of buffer + * + * @return - pointer to received buffer + * + */ +static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev, + unsigned long *len, + unsigned short *idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + void *data = NULL; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + data = virtqueue_get_buffer(rvdev->rvq, (uint32_t *)len, idx); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + data = + virtqueue_get_available_buffer(rvdev->rvq, idx, + (uint32_t *)len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + if (data) { + /* FIX ME: library should not worry about if it needs + * to flush/invalidate cache, it is shared memory. + * The shared memory should be mapped properly before + * using it. + */ + metal_cache_invalidate(data, (unsigned int)(*len)); + } + + return data; +} + +#ifndef VIRTIO_MASTER_ONLY +/** + * check if the remote is ready to start RPMsg communication + */ +static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev) +{ + uint8_t status; + + while (1) { + status = rpmsg_virtio_get_status(rvdev); + /* Busy wait until the remote is ready */ + if (status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) { + rpmsg_virtio_set_status(rvdev, 0); + /* TODO notify remote processor */ + } else if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) { + return true; + } + /* TODO: clarify metal_cpu_yield usage*/ + metal_cpu_yield(); + } + + return false; +} +#endif /*!VIRTIO_MASTER_ONLY*/ + +/** + * _rpmsg_virtio_get_buffer_size + * + * Returns buffer size available for sending messages. + * + * @param channel - pointer to rpmsg channel + * + * @return - buffer size + * + */ +static int _rpmsg_virtio_get_buffer_size(struct rpmsg_virtio_device *rvdev) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + int length = 0; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + /* + * If device role is Remote then buffers are provided by us + * (RPMSG Master), so just provide the macro. + */ + length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + /* + * If other core is Master then buffers are provided by it, + * so get the buffer size from the virtqueue. + */ + length = + (int)virtqueue_get_desc_size(rvdev->svq) - + sizeof(struct rpmsg_hdr); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + return length; +} + +/** + * This function sends rpmsg "message" to remote device. + * + * @param rdev - pointer to rpmsg device + * @param src - source address of channel + * @param dst - destination address of channel + * @param data - data to transmit + * @param size - size of data + * @param wait - boolean, wait or not for buffer to become + * available + * + * @return - size of data sent or negative value for failure. + * + */ +static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, + int size, int wait) +{ + struct rpmsg_virtio_device *rvdev; + struct rpmsg_hdr rp_hdr; + void *buffer = NULL; + unsigned short idx; + int tick_count = 0; + unsigned long buff_len; + int status; + struct metal_io_region *io; + + /* Get the associated remote device for channel. */ + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + + status = rpmsg_virtio_get_status(rvdev); + /* Validate device state */ + if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) { + return RPMSG_ERR_DEV_STATE; + } + + if (wait) + tick_count = RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL; + else + tick_count = 0; + + while (1) { + int avail_size; + + /* Lock the device to enable exclusive access to virtqueues */ + metal_mutex_acquire(&rdev->lock); + avail_size = _rpmsg_virtio_get_buffer_size(rvdev); + if (size <= avail_size) + buffer = rpmsg_virtio_get_tx_buffer(rvdev, &buff_len, + &idx); + metal_mutex_release(&rdev->lock); + if (buffer || !tick_count) + break; + if (avail_size != 0) + return RPMSG_ERR_BUFF_SIZE; + metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); + tick_count--; + } + if (!buffer) + return RPMSG_ERR_NO_BUFF; + + /* Initialize RPMSG header. */ + rp_hdr.dst = dst; + rp_hdr.src = src; + rp_hdr.len = size; + rp_hdr.reserved = 0; + + /* Copy data to rpmsg buffer. */ + io = rvdev->shbuf_io; + status = metal_io_block_write(io, metal_io_virt_to_offset(io, buffer), + &rp_hdr, sizeof(rp_hdr)); + RPMSG_ASSERT(status == sizeof(rp_hdr), "failed to write header\n"); + + status = metal_io_block_write(io, + metal_io_virt_to_offset(io, + RPMSG_LOCATE_DATA(buffer)), + data, size); + RPMSG_ASSERT(status == size, "failed to write buffer\n"); + metal_mutex_acquire(&rdev->lock); + + /* Enqueue buffer on virtqueue. */ + status = rpmsg_virtio_enqueue_buffer(rvdev, buffer, buff_len, idx); + RPMSG_ASSERT(status == VQUEUE_SUCCESS, "failed to enqueue buffer\n"); + /* Let the other side know that there is a job to process. */ + virtqueue_kick(rvdev->svq); + + metal_mutex_release(&rdev->lock); + + return size; +} + +/** + * rpmsg_virtio_tx_callback + * + * Tx callback function. + * + * @param vq - pointer to virtqueue on which Tx is has been + * completed. + * + */ +static void rpmsg_virtio_tx_callback(struct virtqueue *vq) +{ + (void)vq; +} + +/** + * rpmsg_virtio_rx_callback + * + * Rx callback function. + * + * @param vq - pointer to virtqueue on which messages is received + * + */ +static void rpmsg_virtio_rx_callback(struct virtqueue *vq) +{ + struct virtio_device *vdev = vq->vq_dev; + struct rpmsg_virtio_device *rvdev = vdev->priv; + struct rpmsg_device *rdev = &rvdev->rdev; + struct rpmsg_endpoint *ept; + struct rpmsg_hdr *rp_hdr; + unsigned long len; + unsigned short idx; + int status; + + metal_mutex_acquire(&rdev->lock); + + /* Process the received data from remote node */ + rp_hdr = (struct rpmsg_hdr *)rpmsg_virtio_get_rx_buffer(rvdev, + &len, &idx); + + metal_mutex_release(&rdev->lock); + + while (rp_hdr) { + /* Get the channel node from the remote device channels list. */ + metal_mutex_acquire(&rdev->lock); + ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst); + metal_mutex_release(&rdev->lock); + + if (!ept) + /* Fatal error no endpoint for the given dst addr. */ + return; + + if (ept->dest_addr == RPMSG_ADDR_ANY) { + /* + * First message received from the remote side, + * update channel destination address + */ + ept->dest_addr = rp_hdr->src; + } + status = ept->cb(ept, (void *)RPMSG_LOCATE_DATA(rp_hdr), + rp_hdr->len, ept->addr, ept->priv); + + RPMSG_ASSERT(status == RPMSG_SUCCESS, + "unexpected callback status\n"); + metal_mutex_acquire(&rdev->lock); + + /* Return used buffers. */ + rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + + rp_hdr = (struct rpmsg_hdr *) + rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + metal_mutex_release(&rdev->lock); + } +} + +/** + * rpmsg_virtio_ns_callback + * + * This callback handles name service announcement from the remote device + * and creates/deletes rpmsg channels. + * + * @param server_chnl - pointer to server channel control block. + * @param data - pointer to received messages + * @param len - length of received data + * @param priv - any private data + * @param src - source address + * + * @return - rpmag endpoint callback handled + */ + +#if defined (__GNUC__) && ! defined (__CC_ARM) +#pragma GCC push_options +#pragma GCC optimize ("O0") +#elif defined (__CC_ARM) +#pragma push +#pragma O0 +#endif +static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv) +{ + struct rpmsg_device *rdev = ept->rdev; + struct rpmsg_virtio_device *rvdev = (struct rpmsg_virtio_device *)rdev; + struct metal_io_region *io = rvdev->shbuf_io; + struct rpmsg_endpoint *_ept; + struct rpmsg_ns_msg *ns_msg; + uint32_t dest; + char name[RPMSG_NAME_SIZE]; + + (void)priv; + (void)src; + + ns_msg = (struct rpmsg_ns_msg *)data; + if (len != sizeof(*ns_msg)) + /* Returns as the message is corrupted */ + return RPMSG_SUCCESS; + metal_io_block_read(io, + metal_io_virt_to_offset(io, ns_msg->name), + &name, sizeof(name)); + dest = ns_msg->addr; + + /* check if a Ept has been locally registered */ + metal_mutex_acquire(&rdev->lock); + _ept = rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest); + + if (ns_msg->flags & RPMSG_NS_DESTROY) { + if (_ept) + _ept->dest_addr = RPMSG_ADDR_ANY; + metal_mutex_release(&rdev->lock); + if (_ept && _ept->ns_unbind_cb) + _ept->ns_unbind_cb(ept); + } else { + if (!_ept) { + /* + * send callback to application, that can + * - create the associated endpoints. + * - store information for future use. + * - just ignore the request as service not supported. + */ + metal_mutex_release(&rdev->lock); + if (rdev->ns_bind_cb) + rdev->ns_bind_cb(rdev, name, dest); + } else { + _ept->dest_addr = dest; + metal_mutex_release(&rdev->lock); + } + } + + return RPMSG_SUCCESS; +} +#if defined (__GNUC__) && ! defined (__CC_ARM) +#pragma GCC pop_options +#elif defined (__CC_ARM) +#pragma pop +#endif + +int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) +{ + int size; + struct rpmsg_virtio_device *rvdev; + + if (!rdev) + return RPMSG_ERR_PARAM; + metal_mutex_acquire(&rdev->lock); + rvdev = (struct rpmsg_virtio_device *)rdev; + size = _rpmsg_virtio_get_buffer_size(rvdev); + metal_mutex_release(&rdev->lock); + return size; +} + +int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool) +{ + struct rpmsg_device *rdev; + const char *vq_names[RPMSG_NUM_VRINGS]; + typedef void (*vqcallback)(struct virtqueue *vq); + vqcallback callback[RPMSG_NUM_VRINGS]; + unsigned long dev_features; + int status; + unsigned int i, role; + + rdev = &rvdev->rdev; + memset(rdev, 0, sizeof(*rdev)); + metal_mutex_init(&rdev->lock); + rvdev->vdev = vdev; + rdev->ns_bind_cb = ns_bind_cb; + vdev->priv = rvdev; + rdev->ops.send_offchannel_raw = rpmsg_virtio_send_offchannel_raw; + role = rpmsg_virtio_get_role(rvdev); + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + /* + * Since device is RPMSG Remote so we need to manage the + * shared buffers. Create shared memory pool to handle buffers. + */ + if (!shpool) + return RPMSG_ERR_PARAM; + if (!shpool->size) + return RPMSG_ERR_NO_BUFF; + rvdev->shpool = shpool; + + vq_names[0] = "rx_vq"; + vq_names[1] = "tx_vq"; + callback[0] = rpmsg_virtio_rx_callback; + callback[1] = rpmsg_virtio_tx_callback; + rvdev->rvq = vdev->vrings_info[0].vq; + rvdev->svq = vdev->vrings_info[1].vq; + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + (void)shpool; + if (role == RPMSG_REMOTE) { + vq_names[0] = "tx_vq"; + vq_names[1] = "rx_vq"; + callback[0] = rpmsg_virtio_tx_callback; + callback[1] = rpmsg_virtio_rx_callback; + rvdev->rvq = vdev->vrings_info[1].vq; + rvdev->svq = vdev->vrings_info[0].vq; + } +#endif /*!VIRTIO_MASTER_ONLY*/ + rvdev->shbuf_io = shm_io; + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + /* wait synchro with the master */ + rpmsg_virtio_wait_remote_ready(rvdev); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + /* Create virtqueues for remote device */ + status = rpmsg_virtio_create_virtqueues(rvdev, 0, RPMSG_NUM_VRINGS, + vq_names, callback); + if (status != RPMSG_SUCCESS) + return status; + + /* TODO: can have a virtio function to set the shared memory I/O */ + for (i = 0; i < RPMSG_NUM_VRINGS; i++) { + struct virtqueue *vq; + + vq = vdev->vrings_info[i].vq; + vq->shm_io = shm_io; + } + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + unsigned int idx; + void *buffer; + + vqbuf.len = RPMSG_BUFFER_SIZE; + for (idx = 0; idx < rvdev->rvq->vq_nentries; idx++) { + /* Initialize TX virtqueue buffers for remote device */ + buffer = rpmsg_virtio_shm_pool_get_buffer(shpool, + RPMSG_BUFFER_SIZE); + + if (!buffer) { + return RPMSG_ERR_NO_BUFF; + } + + vqbuf.buf = buffer; + + metal_io_block_set(shm_io, + metal_io_virt_to_offset(shm_io, + buffer), + 0x00, RPMSG_BUFFER_SIZE); + status = + virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, + buffer); + + if (status != RPMSG_SUCCESS) { + return status; + } + } + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + + /* Initialize channels and endpoints list */ + metal_list_init(&rdev->endpoints); + + dev_features = rpmsg_virtio_get_features(rvdev); + + /* + * Create name service announcement endpoint if device supports name + * service announcement feature. + */ + if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) { + rpmsg_init_ept(&rdev->ns_ept, "NS", + RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR, + rpmsg_virtio_ns_callback, NULL); + (void)rpmsg_register_endpoint(rdev, &rdev->ns_ept); + } + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) + rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); +#endif /*!VIRTIO_SLAVE_ONLY*/ + + return status; +} + +void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) +{ + struct metal_list *node; + struct rpmsg_device *rdev; + struct rpmsg_endpoint *ept; + + rdev = &rvdev->rdev; + while (!metal_list_is_empty(&rdev->endpoints)) { + node = rdev->endpoints.next; + ept = metal_container_of(node, struct rpmsg_endpoint, node); + rpmsg_destroy_ept(ept); + } + + rvdev->rvq = 0; + rvdev->svq = 0; + + metal_mutex_deinit(&rdev->lock); +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtio.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtio.c new file mode 100644 index 0000000000..5cf87222b6 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtio.c @@ -0,0 +1,121 @@ +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include + +static const char *virtio_feature_name(unsigned long feature, + const struct virtio_feature_desc *); + +//TODO : This structure may change depending on the types of devices we support. +static const struct virtio_ident { + unsigned short devid; + const char *name; +} virtio_ident_table[] = { + { + VIRTIO_ID_NETWORK, "Network"}, { + VIRTIO_ID_BLOCK, "Block"}, { + VIRTIO_ID_CONSOLE, "Console"}, { + VIRTIO_ID_ENTROPY, "Entropy"}, { + VIRTIO_ID_BALLOON, "Balloon"}, { + VIRTIO_ID_IOMEMORY, "IOMemory"}, { + VIRTIO_ID_SCSI, "SCSI"}, { + VIRTIO_ID_9P, "9P Transport"}, { + 0, NULL} +}; + +/* Device independent features. */ +static const struct virtio_feature_desc virtio_common_feature_desc[] = { + {VIRTIO_F_NOTIFY_ON_EMPTY, "NotifyOnEmpty"}, + {VIRTIO_RING_F_INDIRECT_DESC, "RingIndirect"}, + {VIRTIO_RING_F_EVENT_IDX, "EventIdx"}, + {VIRTIO_F_BAD_FEATURE, "BadFeature"}, + + {0, NULL} +}; + +const char *virtio_dev_name(unsigned short devid) +{ + const struct virtio_ident *ident; + + for (ident = virtio_ident_table; ident->name != NULL; ident++) { + if (ident->devid == devid) + return (ident->name); + } + + return (NULL); +} + +static const char *virtio_feature_name(unsigned long val, + const struct virtio_feature_desc *desc) +{ + int i, j; + const struct virtio_feature_desc *descs[2] = { desc, + virtio_common_feature_desc + }; + + for (i = 0; i < 2; i++) { + if (!descs[i]) + continue; + + for (j = 0; descs[i][j].vfd_val != 0; j++) { + if (val == descs[i][j].vfd_val) + return (descs[i][j].vfd_str); + } + } + + return (NULL); +} + +void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, struct virtio_feature_desc *desc) +{ + (void)dev; + (void)msg; + (void)features; + + // TODO: Not used currently - keeping it for future use + virtio_feature_name(0, desc); +} + +int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback *callbacks[]) +{ + struct virtio_vring_info *vring_info; + struct vring_alloc_info *vring_alloc; + unsigned int num_vrings, i; + int ret; + (void)flags; + + num_vrings = vdev->vrings_num; + if (nvqs > num_vrings) + return -ERROR_VQUEUE_INVLD_PARAM; + /* Initialize virtqueue for each vring */ + for (i = 0; i < nvqs; i++) { + vring_info = &vdev->vrings_info[i]; + + vring_alloc = &vring_info->info; +#ifndef VIRTIO_SLAVE_ONLY + if (vdev->role == VIRTIO_DEV_MASTER) { + size_t offset; + struct metal_io_region *io = vring_info->io; + + offset = metal_io_virt_to_offset(io, + vring_alloc->vaddr); + metal_io_block_set(io, offset, 0, + vring_size(vring_alloc->num_descs, + vring_alloc->align)); + } +#endif + ret = virtqueue_create(vdev, i, names[i], vring_alloc, + callbacks[i], vdev->func->notify, + vring_info->vq); + if (ret) + return ret; + } + return 0; +} + diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtqueue.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtqueue.c new file mode 100644 index 0000000000..e90a6940b0 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/open-amp/lib/virtio/virtqueue.c @@ -0,0 +1,618 @@ +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +/* Prototype for internal functions. */ +static void vq_ring_init(struct virtqueue *, void *, int); +static void vq_ring_update_avail(struct virtqueue *, uint16_t); +static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *, + uint16_t, struct virtqueue_buf *, int, int); +static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); +static void vq_ring_free_chain(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); + +/* Default implementation of P2V based on libmetal */ +static inline void *virtqueue_phys_to_virt(struct virtqueue *vq, + metal_phys_addr_t phys) +{ + struct metal_io_region *io = vq->shm_io; + + return metal_io_phys_to_virt(io, phys); +} + +/* Default implementation of V2P based on libmetal */ +static inline metal_phys_addr_t virtqueue_virt_to_phys(struct virtqueue *vq, + void *buf) +{ + struct metal_io_region *io = vq->shm_io; + + return metal_io_virt_to_phys(io, buf); +} + +/** + * virtqueue_create - Creates new VirtIO queue + * + * @param device - Pointer to VirtIO device + * @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 vq - Created VirtIO queue. + * + * @return - Function status + */ +int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, + const char *name, struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue *vq) +{ + int status = VQUEUE_SUCCESS; + + VQ_PARAM_CHK(ring == 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); + VQ_PARAM_CHK(vq == NULL, status, ERROR_NO_MEM); + + if (status == VQUEUE_SUCCESS) { + vq->vq_dev = virt_dev; + vq->vq_name = name; + vq->vq_queue_index = id; + vq->vq_nentries = ring->num_descs; + vq->vq_free_cnt = vq->vq_nentries; + vq->callback = callback; + vq->notify = notify; + + /* Initialize vring control block in virtqueue. */ + vq_ring_init(vq, (void *)ring->vaddr, ring->align); + + /* Disable callbacks - will be enabled by the application + * once initialization is completed. + */ + virtqueue_disable_cb(vq); + } + + return (status); +} + +/** + * virtqueue_add_buffer() - Enqueues new buffer in vring for consumption + * by other side. Readable buffers are always + * inserted before writable buffers + * + * @param vq - Pointer to VirtIO queue control block. + * @param buf_list - Pointer to a list of virtqueue buffers. + * @param readable - Number of readable buffers + * @param writable - Number of writable buffers + * @param cookie - Pointer to hold call back data + * + * @return - Function status + */ +int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, + int readable, int writable, void *cookie) +{ + struct vq_desc_extra *dxp = NULL; + int status = VQUEUE_SUCCESS; + uint16_t head_idx; + uint16_t idx; + int needed; + + needed = readable + writable; + + VQ_PARAM_CHK(vq == NULL, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(needed < 1, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL); + + VQUEUE_BUSY(vq); + + if (status == VQUEUE_SUCCESS) { + VQASSERT(vq, cookie != NULL, "enqueuing with no cookie"); + + head_idx = vq->vq_desc_head_idx; + VQ_RING_ASSERT_VALID_IDX(vq, head_idx); + dxp = &vq->vq_descx[head_idx]; + + VQASSERT(vq, dxp->cookie == NULL, + "cookie already exists for index"); + + dxp->cookie = cookie; + dxp->ndescs = needed; + + /* Enqueue buffer onto the ring. */ + idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, + buf_list, readable, writable); + + vq->vq_desc_head_idx = idx; + vq->vq_free_cnt -= needed; + + if (vq->vq_free_cnt == 0) { + VQ_RING_ASSERT_CHAIN_TERM(vq); + } else { + VQ_RING_ASSERT_VALID_IDX(vq, 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); + + 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 of the buffer + * + * @return - Pointer to used buffer + */ +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) +{ + struct vring_used_elem *uep; + void *cookie; + uint16_t used_idx, desc_idx; + + if (!vq || vq->vq_used_cons_idx == vq->vq_ring.used->idx) + return (NULL); + + VQUEUE_BUSY(vq); + + used_idx = vq->vq_used_cons_idx++ & (vq->vq_nentries - 1); + uep = &vq->vq_ring.used->ring[used_idx]; + + atomic_thread_fence(memory_order_seq_cst); + + desc_idx = (uint16_t)uep->id; + if (len) + *len = uep->len; + + vq_ring_free_chain(vq, desc_idx); + + cookie = vq->vq_descx[desc_idx].cookie; + vq->vq_descx[desc_idx].cookie = NULL; + + if (idx) + *idx = used_idx; + VQUEUE_IDLE(vq); + + return cookie; +} + +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) { + if (vq->vq_free_cnt != vq->vq_nentries) { + metal_log(METAL_LOG_WARNING, + "%s: freeing non-empty virtqueue\r\n", + vq->vq_name); + } + + metal_free_memory(vq); + } +} + +/** + * 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; + + atomic_thread_fence(memory_order_seq_cst); + if (vq->vq_available_idx == vq->vq_ring.avail->idx) { + return NULL; + } + + VQUEUE_BUSY(vq); + + head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1); + *avail_idx = vq->vq_ring.avail->ring[head_idx]; + + buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[*avail_idx].addr); + *len = vq->vq_ring.desc[*avail_idx].len; + + VQUEUE_IDLE(vq); + + 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) +{ + struct vring_used_elem *used_desc = NULL; + uint16_t used_idx; + + if (head_idx > vq->vq_nentries) { + return ERROR_VRING_NO_BUFF; + } + + VQUEUE_BUSY(vq); + + 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; + + atomic_thread_fence(memory_order_seq_cst); + + vq->vq_ring.used->idx++; + + VQUEUE_IDLE(vq); + + 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); + + 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); +} + +/** + * 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); + + /* Ensure updated avail->idx is visible to host. */ + atomic_thread_fence(memory_order_seq_cst); + + if (vq_ring_must_notify_host(vq)) + vq_ring_notify_host(vq); + + vq->vq_queued_cnt = 0; + + VQUEUE_IDLE(vq); +} + +/** + * 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) + return; + + metal_log(METAL_LOG_DEBUG, + "VQ: %s - size=%d; free=%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, vq->vq_free_cnt, + 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; + } + + VQUEUE_BUSY(vq); + + 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; + + VQUEUE_IDLE(vq); + + 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, + struct virtqueue_buf *buf_list, int readable, + int writable) +{ + struct vring_desc *dp; + int i, needed; + uint16_t idx; + + (void)vq; + + needed = readable + writable; + + for (i = 0, idx = head_idx; i < needed; i++, idx = dp->next) { + VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END, + "premature end of free desc chain"); + + dp = &desc[idx]; + dp->addr = virtqueue_virt_to_phys(vq, buf_list[i].buf); + dp->len = buf_list[i].len; + dp->flags = 0; + + if (i < needed - 1) + dp->flags |= VRING_DESC_F_NEXT; + + /* + * Readable buffers are inserted into vring before the + * writable buffers. + */ + if (i >= readable) + dp->flags |= VRING_DESC_F_WRITE; + } + + return (idx); +} + +/** + * + * vq_ring_free_chain + * + */ +static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) +{ + struct vring_desc *dp; + struct vq_desc_extra *dxp; + + VQ_RING_ASSERT_VALID_IDX(vq, desc_idx); + dp = &vq->vq_ring.desc[desc_idx]; + dxp = &vq->vq_descx[desc_idx]; + + if (vq->vq_free_cnt == 0) { + VQ_RING_ASSERT_CHAIN_TERM(vq); + } + + vq->vq_free_cnt += dxp->ndescs; + dxp->ndescs--; + + if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) { + while (dp->flags & VRING_DESC_F_NEXT) { + VQ_RING_ASSERT_VALID_IDX(vq, dp->next); + dp = &vq->vq_ring.desc[dp->next]; + dxp->ndescs--; + } + } + + VQASSERT(vq, (dxp->ndescs == 0), + "failed to free entire desc chain, remaining"); + + /* + * We must append the existing free chain, if any, to the end of + * newly freed chain. If the virtqueue was completely used, then + * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above). + */ + dp->next = vq->vq_desc_head_idx; + vq->vq_desc_head_idx = desc_idx; +} + +/** + * + * vq_ring_init + * + */ +static void vq_ring_init(struct virtqueue *vq, void *ring_mem, int alignment) +{ + struct vring *vr; + int i, size; + + size = vq->vq_nentries; + vr = &vq->vq_ring; + + vring_init(vr, size, (unsigned char *)ring_mem, alignment); + + 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; + + atomic_thread_fence(memory_order_seq_cst); + + vq->vq_ring.avail->idx++; + + /* Keep pending count until virtqueue_notify(). */ + vq->vq_queued_cnt++; +} + +/** + * + * 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; + } + + atomic_thread_fence(memory_order_seq_cst); + + /* + * 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) +{ + atomic_thread_fence(memory_order_seq_cst); + if (vq->callback) + vq->callback(vq); +} + +/** + * + * vq_ring_must_notify_host + * + */ +static int vq_ring_must_notify_host(struct virtqueue *vq) +{ + uint16_t new_idx, prev_idx, 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->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/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.c b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.c new file mode 100644 index 0000000000..d50aeac63b --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.c @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * @file virt_uart.c + * @author MCD Application Team + * @brief UART HAL module driver. + * This file provides firmware functions to manage an rpmsg endpoint + * from user application + * + * + @verbatim + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + The VIRTUAL UART driver can be used as follows: + (#) Initialize the Virtual UART by calling the VIRT_UART_Init() API. + (++) create an endpoint. listener on the OpenAMP-rpmsg channel is now enabled. + Receive data is now possible if user registers a callback to this VIRTUAL UART instance + by calling in providing a callback function when a message is received from + remote processor (VIRT_UART_read_cb) + OpenAMP MW deals with memory allocation/free and signal events + (#) Transmit data on the created rpmsg channel by calling the VIRT_UART_Transmit() + (#) Receive data in calling VIRT_UART_RegisterCallback to register user callback + + + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "virt_uart.h" +#include "metal/utilities.h" + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* this string will be sent to remote processor */ +#define RPMSG_SERVICE_NAME "rpmsg-tty-channel" + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +static int VIRT_UART_read_cb(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv) +{ + VIRT_UART_HandleTypeDef *huart = metal_container_of(ept, VIRT_UART_HandleTypeDef, ept); + (void)src; + + huart->pRxBuffPtr = data; + huart->RxXferSize = len; + if (huart->RxCpltCallback != NULL) { + huart->RxCpltCallback(huart); + } + + return 0; +} + +VIRT_UART_StatusTypeDef VIRT_UART_Init(VIRT_UART_HandleTypeDef *huart) +{ + + int status; + + /* Create a endpoint for rmpsg communication */ + + status = OPENAMP_create_endpoint(&huart->ept, RPMSG_SERVICE_NAME, RPMSG_ADDR_ANY, + VIRT_UART_read_cb, NULL); + + if(status < 0) { + return VIRT_UART_ERROR; + } + + return VIRT_UART_OK; +} + +VIRT_UART_StatusTypeDef VIRT_UART_DeInit (VIRT_UART_HandleTypeDef *huart) +{ + OPENAMP_destroy_ept(&huart->ept); + + return VIRT_UART_OK; +} + +VIRT_UART_StatusTypeDef VIRT_UART_RegisterCallback(VIRT_UART_HandleTypeDef *huart, + VIRT_UART_CallbackIDTypeDef CallbackID, + void (* pCallback)(VIRT_UART_HandleTypeDef *_huart)) +{ + VIRT_UART_StatusTypeDef status = VIRT_UART_OK; + + switch (CallbackID) + { + case VIRT_UART_RXCPLT_CB_ID : + huart->RxCpltCallback = pCallback; + break; + + default : + /* Return error status */ + status = VIRT_UART_ERROR; + break; + } + return status; +} + +VIRT_UART_StatusTypeDef VIRT_UART_Transmit(VIRT_UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) +{ + int res; + + if (Size > (RPMSG_BUFFER_SIZE-16)) + return VIRT_UART_ERROR; + + res = OPENAMP_send(&huart->ept, pData, Size); + if (res <0) { + return VIRT_UART_ERROR; + } + + return VIRT_UART_OK; +} diff --git a/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.h b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.h new file mode 100644 index 0000000000..c368bfdbe9 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/board/ports/OpenAMP/virtual_driver/virt_uart.h @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * @file virt_uart.h + * @author MCD Application Team + * @brief Header file of UART VIRT module. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __VIRT_UART_H +#define __VIRT_UART_H + + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "openamp.h" + +/* Exported structures --------------------------------------------------------*/ +typedef struct __VIRT_UART_HandleTypeDef +{ + struct rpmsg_endpoint ept; /*!< rpmsg endpoint */ + struct rpmsg_virtio_device *rvdev; /*< pointer to the rpmsg virtio device */ + uint8_t *pRxBuffPtr; /*!< Pointer to VIRTUAL UART Rx transfer Buffer */ + uint16_t RxXferSize; /*!< VIRTUAL UART Rx Transfer size */ + void (* RxCpltCallback)( struct __VIRT_UART_HandleTypeDef * hppp); /*!< RX CPLT callback */ +}VIRT_UART_HandleTypeDef; + + +typedef enum +{ + VIRT_UART_OK = 0x00U, + VIRT_UART_ERROR = 0x01U, + VIRT_UART_BUSY = 0x02U, + VIRT_UART_TIMEOUT = 0x03U +} VIRT_UART_StatusTypeDef; + + +typedef enum +{ + VIRT_UART_RXCPLT_CB_ID = 0x00U, /*!< PPP event 1 callback ID */ +}VIRT_UART_CallbackIDTypeDef; + + +/* Exported functions --------------------------------------------------------*/ +/* Initialization and de-initialization functions ****************************/ +VIRT_UART_StatusTypeDef VIRT_UART_Init(VIRT_UART_HandleTypeDef *huart); +VIRT_UART_StatusTypeDef VIRT_UART_DeInit (VIRT_UART_HandleTypeDef *huart); +VIRT_UART_StatusTypeDef VIRT_UART_RegisterCallback(VIRT_UART_HandleTypeDef *huart, + VIRT_UART_CallbackIDTypeDef CallbackID, + void (* pCallback)(VIRT_UART_HandleTypeDef *_huart)); + +/* IO operation functions *****************************************************/ +VIRT_UART_StatusTypeDef VIRT_UART_Transmit(VIRT_UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); + + +#ifdef __cplusplus +} +#endif + +#endif /* __VIRT_UART_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32/stm32mp157a-st-ev1/project.ewp b/bsp/stm32/stm32mp157a-st-ev1/project.ewp index 6b140f0c65..2bb85bc33c 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/project.ewp +++ b/bsp/stm32/stm32mp157a-st-ev1/project.ewp @@ -226,8 +226,12 @@ RT_USING_DLIBC CORE_CM4 + NO_ATOMIC_64_SUPPORT + METAL_INTERNAL + METAL_MAX_DEVICE_REGIONS=2 + VIRTIO_SLAVE_ONLY STM32MP157Axx - USE_HAL_DRIVER + __LOG_TRACE_IO_ USE_HAL_DRIVER @@ -1300,8 +1304,12 @@ RT_USING_DLIBC CORE_CM4 + NO_ATOMIC_64_SUPPORT + METAL_INTERNAL + METAL_MAX_DEVICE_REGIONS=2 + VIRTIO_SLAVE_ONLY STM32MP157Axx - USE_HAL_DRIVER + __LOG_TRACE_IO_ USE_HAL_DRIVER diff --git a/bsp/stm32/stm32mp157a-st-ev1/template.uvprojx b/bsp/stm32/stm32mp157a-st-ev1/template.uvprojx index 67a2556f75..fc88195dc1 100644 --- a/bsp/stm32/stm32mp157a-st-ev1/template.uvprojx +++ b/bsp/stm32/stm32mp157a-st-ev1/template.uvprojx @@ -326,7 +326,7 @@ 0 0 1 - 1 + 0 0 1 1 diff --git a/bsp/stm32/stm32mp157a-st-ev1/tools/rt-thread-shell.py b/bsp/stm32/stm32mp157a-st-ev1/tools/rt-thread-shell.py new file mode 100644 index 0000000000..b245d17c69 --- /dev/null +++ b/bsp/stm32/stm32mp157a-st-ev1/tools/rt-thread-shell.py @@ -0,0 +1,26 @@ +import os +import time + +def main(): + if (os.path.exists("/tmp/RT-Thread-STM32MP1_CM4.elf")): + os.system("mv /tmp/RT-Thread-STM32MP1_CM4.elf /lib/firmware/") + os.system("echo stop > /sys/class/remoteproc/remoteproc0/state") + os.system("echo RT-Thread-STM32MP1_CM4.elf > /sys/class/remoteproc/remoteproc0/firmware") + os.system("echo start > /sys/class/remoteproc/remoteproc0/state") + os.system("stty -onlcr -echo -F /dev/ttyRPMSG0") + os.system("cat /dev/ttyRPMSG0 &") + time.sleep(1) + print("\nYou can input \"exit\" to quit rt-thread shell!\n") + os.system("echo version >/dev/ttyRPMSG0") + + while True: + a = input() + if a == "exit": + os.system("echo stop > /sys/class/remoteproc/remoteproc0/state") + return + + os.system("echo {0} >/dev/ttyRPMSG0".format(a)) + + +if __name__ == "__main__": + main()