summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriabdalkader <i.abdalkader@gmail.com>2024-07-17 17:45:08 +0300
committerDamien George <damien@micropython.org>2025-04-09 00:22:32 +1000
commit4f6f283abbdcbdec5cb2144a74fdd2937540ac71 (patch)
treedb29a0baffc472a8359a4230c9952709d8264892
parent6b4d46569bf87673521645b3340e25a3336c8d40 (diff)
alif: Implement Open-AMP port backend.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
-rw-r--r--ports/alif/Makefile4
-rw-r--r--ports/alif/alif.mk11
-rw-r--r--ports/alif/irq.h1
-rw-r--r--ports/alif/mcu/ensemble.ld.S8
-rw-r--r--ports/alif/mpconfigport.h1
-rw-r--r--ports/alif/mpmetalport.c119
-rw-r--r--ports/alif/mpmetalport.h89
-rw-r--r--ports/alif/mpremoteprocport.c172
8 files changed, 403 insertions, 2 deletions
diff --git a/ports/alif/Makefile b/ports/alif/Makefile
index 5cc334a7c..7d6731dac 100644
--- a/ports/alif/Makefile
+++ b/ports/alif/Makefile
@@ -76,10 +76,10 @@ $(BUILD):
$(MKDIR) -p $@
$(BUILD)/M55_HP/firmware.bin:
- make -f alif.mk MCU_CORE=M55_HP
+ make -f alif.mk MCU_CORE=M55_HP MICROPY_PY_OPENAMP_MODE=0
$(BUILD)/M55_HE/firmware.bin:
- make -f alif.mk MCU_CORE=M55_HE
+ make -f alif.mk MCU_CORE=M55_HE MICROPY_PY_OPENAMP_MODE=1
$(BUILD)/firmware.toc.bin: $(ALIF_TOC_APPS)
$(Q)python $(ALIF_TOOLS)/app-gen-toc.py \
diff --git a/ports/alif/alif.mk b/ports/alif/alif.mk
index ad69499ec..c68fc66d4 100644
--- a/ports/alif/alif.mk
+++ b/ports/alif/alif.mk
@@ -203,6 +203,17 @@ $(BUILD)/tinyusb_port/tusb_alif_dcd.o: CFLAGS += -Wno-unused-variable -DTUSB_ALI
$(BUILD)/$(ALIF_DFP_REL_TOP)/se_services/source/services_host_boot.o: CFLAGS += -Wno-stringop-truncation
$(BUILD)/$(ALIF_DFP_REL_TOP)/se_services/source/services_host_system.o: CFLAGS += -Wno-maybe-uninitialized
+# Add Alif-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
+
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SHARED_SRC_C) $(GEN_PINS_SRC)
diff --git a/ports/alif/irq.h b/ports/alif/irq.h
index a20ff7aeb..de6d07ab6 100644
--- a/ports/alif/irq.h
+++ b/ports/alif/irq.h
@@ -45,6 +45,7 @@
#define IRQ_PRI_UART_REPL NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 1, 0)
#define IRQ_PRI_ADC NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 3, 0)
#define IRQ_PRI_USB NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 5, 0)
+#define IRQ_PRI_HWSEM NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 8, 0)
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 127, 0)
// these states correspond to values from query_irq, enable_irq and disable_irq
diff --git a/ports/alif/mcu/ensemble.ld.S b/ports/alif/mcu/ensemble.ld.S
index 8129a749e..aeefdb7ea 100644
--- a/ports/alif/mcu/ensemble.ld.S
+++ b/ports/alif/mcu/ensemble.ld.S
@@ -114,6 +114,14 @@ SECTIONS
* (.bss.sram0*)
} > SRAM0
+ /* Open-AMP Shared Memory Region */
+ .openamp_memory (NOLOAD) : ALIGN(32)
+ {
+ _openamp_shm_region_start = .;
+ . = . + 64K;
+ _openamp_shm_region_end = .;
+ } >SRAM6_A
+
.bss : ALIGN(4)
{
__bss_start__ = .;
diff --git a/ports/alif/mpconfigport.h b/ports/alif/mpconfigport.h
index df33b9220..dfe1ec256 100644
--- a/ports/alif/mpconfigport.h
+++ b/ports/alif/mpconfigport.h
@@ -91,6 +91,7 @@
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_SCHEDULER_STATIC_NODES (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
+#define MICROPY_TRACKED_ALLOC (MICROPY_PY_OPENAMP)
// Fine control over Python builtins, classes, modules, etc
#define MICROPY_PY_SYS_PLATFORM "alif"
diff --git a/ports/alif/mpmetalport.c b/ports/alif/mpmetalport.c
new file mode 100644
index 000000000..f80d039c2
--- /dev/null
+++ b/ports/alif/mpmetalport.c
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 OpenMV LLC.
+ *
+ * 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 Alif port.
+ */
+
+#include ALIF_CMSIS_H
+#include "hwsem.h"
+
+#include "py/mperrno.h"
+#include "py/mphal.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;
+
+int metal_sys_init(const struct metal_init_params *params) {
+ metal_unused(params);
+
+ // Reset the hardware semaphore.
+ hwsem_reset(METAL_HSEM_DEVICE);
+ #if MICROPY_PY_OPENAMP_HOST
+ hwsem_reset(METAL_HSEM_REMOTE);
+ #endif
+
+ // Enable the hardware semaphore IRQ.
+ NVIC_ClearPendingIRQ(METAL_HSEM_IRQn);
+ NVIC_SetPriority(METAL_HSEM_IRQn, IRQ_PRI_HWSEM);
+ NVIC_EnableIRQ(METAL_HSEM_IRQn);
+
+ // If cache management is not enabled, configure the MPU to disable
+ // caching for the entire Open-AMP shared memory region.
+ #ifndef VIRTIO_USE_DCACHE
+ ARM_MPU_Disable();
+ // NOTE: The startup code uses the first 4 attributes.
+ #define MEMATTR_IDX_NORMAL_NON_CACHEABLE 4
+ ARM_MPU_SetMemAttr(MEMATTR_IDX_NORMAL_NON_CACHEABLE, ARM_MPU_ATTR(
+ ARM_MPU_ATTR_NON_CACHEABLE,
+ ARM_MPU_ATTR_NON_CACHEABLE));
+ MPU->RNR = METAL_MPU_REGION_ID;
+ MPU->RBAR = ARM_MPU_RBAR(METAL_MPU_REGION_BASE, ARM_MPU_SH_NON, 0, 1, 0); // RO-0, NP-1, XN-0
+ MPU->RLAR = ARM_MPU_RLAR(METAL_MPU_REGION_BASE + METAL_MPU_REGION_SIZE - 1, MEMATTR_IDX_NORMAL_NON_CACHEABLE);
+ 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(METAL_HSEM_IRQn);
+ NVIC_ClearPendingIRQ(METAL_HSEM_IRQn);
+ hwsem_reset(METAL_HSEM_DEVICE);
+ 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) {
+ // Release the HW semaphore to notify the other core.
+ hwsem_release(METAL_HSEM_REMOTE, HWSEM_MASTERID);
+ return 0;
+}
+
+void METAL_HSEM_IRQ_HANDLER(void) {
+ // Schedule the node only if the other core released the Semaphore.
+ if (METAL_HSEM_DEVICE->HWSEM_REL_REG == 0) {
+ mp_sched_schedule_node(&rproc_notify_node, openamp_remoteproc_notified);
+ }
+ hwsem_request(METAL_HSEM_DEVICE, METAL_HSEM_REMOTE_ID);
+}
diff --git a/ports/alif/mpmetalport.h b/ports/alif/mpmetalport.h
new file mode 100644
index 000000000..5cd697c0e
--- /dev/null
+++ b/ports/alif/mpmetalport.h
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 OpenMV LLC.
+ *
+ * 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 alif port.
+ */
+#ifndef MICROPY_INCLUDED_ALIF_MPMETALPORT_H
+#define MICROPY_INCLUDED_ALIF_MPMETALPORT_H
+
+#include <stdlib.h>
+#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
+
+#if MICROPY_PY_OPENAMP_HOST
+#define METAL_HSEM_DEVICE ((HWSEM_Type *)HWSEM14_BASE)
+#define METAL_HSEM_REMOTE ((HWSEM_Type *)HWSEM15_BASE)
+#define METAL_HSEM_REMOTE_ID (0x410FD222U)
+#define METAL_HSEM_IRQn HWSEM_IRQ14_IRQn
+#define METAL_HSEM_IRQ_HANDLER HWSEM_IRQ14Handler
+#else
+#define METAL_HSEM_DEVICE ((HWSEM_Type *)HWSEM15_BASE)
+#define METAL_HSEM_REMOTE ((HWSEM_Type *)HWSEM14_BASE)
+#define METAL_HSEM_REMOTE_ID (0x410FD221U)
+#define METAL_HSEM_IRQn HWSEM_IRQ15_IRQn
+#define METAL_HSEM_IRQ_HANDLER HWSEM_IRQ15Handler
+#endif
+
+// Set to 1 to enable log output.
+#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_ID (9) // NOTE: The startup code uses the first 9 regions.
+#define METAL_MPU_REGION_BASE ((uint32_t)_openamp_shm_region_start)
+#define METAL_MPU_REGION_SIZE (0x00010000U)
+
+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) {
+ mp_event_handle_nowait();
+ __WFI();
+}
+
+#endif // MICROPY_INCLUDED_ALIF_METAL_PORT_H
diff --git a/ports/alif/mpremoteprocport.c b/ports/alif/mpremoteprocport.c
new file mode 100644
index 000000000..27210a824
--- /dev/null
+++ b/ports/alif/mpremoteprocport.c
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 OpenMV LLC.
+ *
+ * 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 alif port.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.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"
+#include "se_services.h"
+
+typedef struct mmap {
+ uintptr_t base;
+ uintptr_t limit;
+} mmap_t;
+
+static const mmap_t mmap_nocache[] = {
+ { .base = ITCM_BASE, .limit = ITCM_BASE + ITCM_SIZE },
+ { .base = DTCM_BASE, .limit = DTCM_BASE + ITCM_SIZE },
+ { .base = MRAM_BASE, .limit = MRAM_BASE + MRAM_SIZE }
+};
+
+static bool is_cacheable(const void *p, size_t bytes) {
+ uintptr_t base = (uintptr_t)p;
+ if (bytes == 0) {
+ return false;
+ }
+ uintptr_t limit = base + bytes;
+ for (unsigned int i = 0; i < sizeof(mmap_nocache) / sizeof(mmap_nocache[0]); i++) {
+ if (base >= mmap_nocache[i].base && limit < mmap_nocache[i].limit) {
+ return false;
+ }
+ }
+ return true;
+}
+
+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();
+
+ // Reset the remote core.
+ se_services_boot_reset_cpu(EXTSYS_1);
+ 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;
+ }
+
+ // Currently this port doesn't support loading firmware to flash,
+ // only SD/SRAM images are supported. Check of load address is in
+ // the flash region, and if so return NULL.
+ if (lda >= MRAM_BASE && lda < (MRAM_BASE + MRAM_SIZE)) {
+ return NULL;
+ }
+
+ 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 *)mem->da, &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");
+
+ // Flush cached areas for the remote core.
+ struct metal_list *node;
+ metal_list_for_each(&rproc->mems, node) {
+ struct remoteproc_mem *mem;
+ mem = metal_container_of(node, struct remoteproc_mem, node);
+ if (is_cacheable((uint32_t *)mem->pa, mem->size)) {
+ SCB_CleanDCache_by_Addr((uint32_t *)mem->pa, mem->size);
+ }
+ }
+
+ se_services_boot_reset_cpu(EXTSYS_1);
+ se_services_boot_cpu(EXTSYS_1, (uint32_t)rproc->bootaddr); // GlobalToLocal
+ return 0;
+}
+
+int mp_openamp_remoteproc_stop(struct remoteproc *rproc) {
+ metal_log(METAL_LOG_DEBUG, "rproc_stop()\n");
+ if (rproc->state == RPROC_RUNNING) {
+ se_services_boot_reset_cpu(EXTSYS_1);
+ }
+ 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) {
+ se_services_boot_reset_cpu(EXTSYS_1);
+ }
+ return 0;
+}