alif: Implement Open-AMP port backend.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
iabdalkader 2024-07-17 17:45:08 +03:00 committed by Damien George
parent 6b4d46569b
commit 4f6f283abb
8 changed files with 403 additions and 2 deletions

View file

@ -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 \

View file

@ -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)

View file

@ -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

View file

@ -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__ = .;

View file

@ -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"

119
ports/alif/mpmetalport.c Normal file
View file

@ -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);
}

89
ports/alif/mpmetalport.h Normal file
View file

@ -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

View file

@ -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;
}