diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index dd1f5aa7c6ca..96abb11bff43 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -172,7 +172,8 @@ SRC_HAL_IMX_C += \ $(MCU_DIR)/drivers/fsl_common_arm.c \ $(MCU_DIR)/drivers/fsl_anatop_ai.c \ $(MCU_DIR)/drivers/fsl_caam.c \ - $(MCU_DIR)/drivers/fsl_lpadc.c + $(MCU_DIR)/drivers/fsl_lpadc.c \ + $(MCU_DIR)/drivers/fsl_mu.c else SRC_HAL_IMX_C += \ $(MCU_DIR)/drivers/fsl_adc.c \ @@ -267,6 +268,17 @@ ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) SRC_C += mpnimbleport.c endif +# Add mimxrt-specific implementation of libmetal (and optionally OpenAMP's rproc). +# Note: libmetal code is generated via a pre-processor so ensure that runs first. +ifeq ($(MICROPY_PY_OPENAMP),1) +SRC_C += mpmetalport.c +$(BUILD)/mpmetalport.o: $(BUILD)/openamp/metal/config.h +ifeq ($(MICROPY_PY_OPENAMP_REMOTEPROC),1) +SRC_C += mpremoteprocport.c +$(BUILD)/mpremoteprocport.o: $(BUILD)/openamp/metal/config.h +endif +endif + # Math library source files ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(SRC_LIB_LIBM_DBL_C) diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk index 1488730f7c7c..6e5ee56aa108 100644 --- a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk @@ -13,6 +13,8 @@ MICROPY_HW_SDRAM_SIZE = 0x4000000 # 64MB MICROPY_PY_LWIP = 1 MICROPY_PY_SSL = 1 MICROPY_SSL_MBEDTLS = 1 +MICROPY_PY_OPENAMP = 1 +MICROPY_PY_OPENAMP_REMOTEPROC = 1 FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py diff --git a/ports/mimxrt/boards/MIMXRT1176.ld b/ports/mimxrt/boards/MIMXRT1176.ld index d66c86a04602..4d114ef96fa4 100644 --- a/ports/mimxrt/boards/MIMXRT1176.ld +++ b/ports/mimxrt/boards/MIMXRT1176.ld @@ -57,3 +57,7 @@ _gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); _gc_heap_start = ORIGIN(m_ocrm); _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); #endif + +/* CM4 DTCM */ +_openamp_shm_region_start = 0x20220000; +_openamp_shm_region_end = 0x20230000; diff --git a/ports/mimxrt/mpmetalport.c b/ports/mimxrt/mpmetalport.c new file mode 100644 index 000000000000..ca0c30fb2a56 --- /dev/null +++ b/ports/mimxrt/mpmetalport.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Arduino SA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * libmetal mimxrt port. + */ + +#include "py/mperrno.h" +#include "py/mphal.h" + +#include "fsl_common.h" +#include "fsl_mu.h" +#include CPU_HEADER_H + +#include "metal/sys.h" +#include "metal/utilities.h" +#include "metal/device.h" + +struct metal_state _metal; +static mp_sched_node_t rproc_notify_node; + +#define IRQ_PRI_MU NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 10, 0) + +int metal_sys_init(const struct metal_init_params *params) { + metal_unused(params); + + // Init MU. + MU_Init(MUA); + + // Configure and enable MU IRQs. + MU_ClearStatusFlags(MUA, kMU_GenInt0Flag); + NVIC_SetPriority(MUA_IRQn, IRQ_PRI_MU); + NVIC_EnableIRQ(MUA_IRQn); + MU_EnableInterrupts(MUA, kMU_GenInt0InterruptEnable); + + #ifndef VIRTIO_USE_DCACHE + // If cache management is not enabled, configure the MPU to disable caching + // for the entire shared memory region. + ARM_MPU_Disable(); + MPU->RBAR = ARM_MPU_RBAR(10, METAL_MPU_REGION_BASE); + // Normal type, not shareable, non-cacheable + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, METAL_MPU_REGION_SIZE); + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk); + #endif + + metal_bus_register(&metal_generic_bus); + return 0; +} + +void metal_sys_finish(void) { + NVIC_DisableIRQ(MUA_IRQn); + metal_bus_unregister(&metal_generic_bus); +} + +unsigned int sys_irq_save_disable(void) { + return disable_irq(); +} + +void sys_irq_restore_enable(unsigned int state) { + enable_irq(state); +} + +void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa, + size_t size, unsigned int flags) { + metal_unused(pa); + metal_unused(size); + metal_unused(flags); + return va; +} + +void metal_machine_cache_flush(void *addr, unsigned int len) { + SCB_CleanDCache_by_Addr(addr, len); +} + +void metal_machine_cache_invalidate(void *addr, unsigned int len) { + SCB_InvalidateDCache_by_Addr(addr, len); +} + +int metal_rproc_notify(void *priv, uint32_t id) { + MU_TriggerInterrupts(MUA, kMU_GenInt0InterruptTrigger); + return 0; +} + +void MUA_IRQHandler(void) { + if (MU_GetStatusFlags(MUA) & kMU_GenInt0Flag) { + MU_ClearStatusFlags(MUA, kMU_GenInt0Flag); + mp_sched_schedule_node(&rproc_notify_node, openamp_remoteproc_notified); + } + __DSB(); +} diff --git a/ports/mimxrt/mpmetalport.h b/ports/mimxrt/mpmetalport.h new file mode 100644 index 000000000000..994d57cc39fb --- /dev/null +++ b/ports/mimxrt/mpmetalport.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Arduino SA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * libmetal mimxrt port. + */ +#ifndef MICROPY_INCLUDED_MIMXRT_MPMETALPORT_H +#define MICROPY_INCLUDED_MIMXRT_MPMETALPORT_H + +#include +#include "py/mphal.h" +#include "py/runtime.h" + +#define METAL_HAVE_STDATOMIC_H 0 +#define METAL_HAVE_FUTEX_H 0 + +#define METAL_MAX_DEVICE_REGIONS 2 + +// Set to 1 to enable the default log handler. +#define METAL_LOG_HANDLER_ENABLE 0 + +#define metal_cpu_yield() + +// Shared memory config +#define METAL_SHM_NAME "OPENAMP_SHM" +// Note 1K must be reserved at the start of the openamp +// shared memory region, for the shared resource table. +#define METAL_RSC_ADDR ((void *)_openamp_shm_region_start) +#define METAL_RSC_SIZE (1024) + +#define METAL_SHM_ADDR ((metal_phys_addr_t)(_openamp_shm_region_start + METAL_RSC_SIZE)) +#define METAL_SHM_SIZE ((size_t)(_openamp_shm_region_end - _openamp_shm_region_start - METAL_RSC_SIZE)) + +#define METAL_MPU_REGION_BASE ((uint32_t)_openamp_shm_region_start) +#define METAL_MPU_REGION_SIZE (ARM_MPU_REGION_SIZE_64KB) + +extern const char _openamp_shm_region_start[]; +extern const char _openamp_shm_region_end[]; + +int metal_rproc_notify(void *priv, uint32_t id); +extern void openamp_remoteproc_notified(mp_sched_node_t *node); + +static inline int __metal_sleep_usec(unsigned int usec) { + mp_hal_delay_us(usec); + return 0; +} + +static inline void metal_generic_default_poll(void) { + MICROPY_EVENT_POLL_HOOK +} + +#endif // MICROPY_INCLUDED_MIMXRT_METAL_PORT_H diff --git a/ports/mimxrt/mpremoteprocport.c b/ports/mimxrt/mpremoteprocport.c new file mode 100644 index 000000000000..1e2cefc7ea69 --- /dev/null +++ b/ports/mimxrt/mpremoteprocport.c @@ -0,0 +1,161 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Arduino SA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * modremoteproc mimxrt port. + */ + +#include "py/obj.h" +#include "py/runtime.h" + +#include "fsl_common.h" +#include "fsl_mu.h" + +#include "metal/alloc.h" +#include "metal/errno.h" +#include "metal/io.h" +#include "metal/sys.h" +#include "metal/device.h" +#include "metal/utilities.h" +#include "extmod/modopenamp_remoteproc.h" + +struct remoteproc *mp_openamp_remoteproc_init(struct remoteproc *rproc, + const struct remoteproc_ops *ops, void *arg) { + metal_log(METAL_LOG_DEBUG, "rproc_init()\n"); + + rproc->ops = ops; + rproc->state = RPROC_OFFLINE; + // Allocate the image store and save it in private data. + rproc->priv = mp_openamp_remoteproc_store_alloc(); + return rproc; +} + +void *mp_openamp_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) { + metal_log(METAL_LOG_DEBUG, "rproc_mmap(): pa 0x%p da 0x%p io 0x%p size %u\n", *pa, *da, *io, size); + + struct remoteproc_mem *mem; + metal_phys_addr_t lpa = *pa; + metal_phys_addr_t lda = *da; + + if (lda == METAL_BAD_PHYS) { + return NULL; + } + + if (lpa == METAL_BAD_PHYS) { + lpa = lda; + } + + if (lpa >= 0x1FFE0000 && lpa < 0x1FFFFFFF) { + // Map CM4 ITCM to CM7 address space. + lpa = 0x20200000 | (((uint32_t)lpa) & 0x1FFFF); + metal_log(METAL_LOG_DEBUG, "rproc_mmap(): remap 0x%p -> 0x%p\n", lda, lpa); + } else if (lpa >= 0x20000000 && lpa < 0x20020000) { + // Map CM4 DTCM to CM7 address space. + lpa = 0x20220000 | (((uint32_t)lpa) & 0x1FFFF); + metal_log(METAL_LOG_DEBUG, "rproc_mmap(): remap 0x%p -> 0x%p\n", lda, lpa); + } + + mem = metal_allocate_memory(sizeof(*mem)); + if (!mem) { + return NULL; + } + + *io = metal_allocate_memory(sizeof(struct metal_io_region)); + if (!*io) { + metal_free_memory(mem); + return NULL; + } + + remoteproc_init_mem(mem, NULL, lpa, lda, size, *io); + + metal_io_init(*io, (void *)lpa, &mem->pa, size, + sizeof(metal_phys_addr_t) << 3, attribute, NULL); + + remoteproc_add_mem(rproc, mem); + *pa = lpa; + *da = lda; + return metal_io_phys_to_virt(*io, mem->pa); +} + +int mp_openamp_remoteproc_start(struct remoteproc *rproc) { + metal_log(METAL_LOG_DEBUG, "rproc_start()\n"); + if (SRC->SCR & SRC_SCR_BT_RELEASE_M4_MASK) { + // The CM4 core is already running. + metal_log(METAL_LOG_DEBUG, "rproc_start(): CM4 core is already booted.\n"); + return -1; + } + + // Flush M7 cache. + struct metal_list *node; + metal_list_for_each(&rproc->mems, node) { + struct remoteproc_mem *mem; + mem = metal_container_of(node, struct remoteproc_mem, node); + metal_log(METAL_LOG_DEBUG, "rproc_start() clean: pa 0x%p size %u\n", (uint32_t *)mem->pa, mem->size); + SCB_CleanDCache_by_Addr((uint32_t *)mem->pa, mem->size); + } + + unsigned long offset = 0; + struct metal_io_region *io = remoteproc_get_io_with_da(rproc, rproc->bootaddr, &offset); + if (!io) { + return -1; + } + + IOMUXC_LPSR_GPR->GPR0 = IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(((uint32_t)io->virt) >> 3); + (void)IOMUXC_LPSR_GPR->GPR0; + IOMUXC_LPSR_GPR->GPR1 = IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(((uint32_t)io->virt) >> 16); + (void)IOMUXC_LPSR_GPR->GPR1; + + SRC->CTRL_M4CORE = SRC_CTRL_M4CORE_SW_RESET_MASK; + SRC->SCR |= SRC_SCR_BT_RELEASE_M4_MASK; + return 0; +} + +int mp_openamp_remoteproc_stop(struct remoteproc *rproc) { + metal_log(METAL_LOG_DEBUG, "rproc_stop()\n"); + if (rproc->state == RPROC_RUNNING) { + NVIC_SystemReset(); + } + return 0; +} + +int mp_openamp_remoteproc_config(struct remoteproc *rproc, void *data) { + metal_log(METAL_LOG_DEBUG, "rproc_config()\n"); + (void)rproc; + return 0; +} + +void mp_openamp_remoteproc_remove(struct remoteproc *rproc) { + metal_log(METAL_LOG_DEBUG, "rproc_remove()\n"); + (void)rproc; +} + +int mp_openamp_remoteproc_shutdown(struct remoteproc *rproc) { + metal_log(METAL_LOG_DEBUG, "rproc_shutdown()\n"); + if (rproc->state == RPROC_RUNNING) { + NVIC_SystemReset(); + } + return 0; +}