mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
bootloader: Add Alif port.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
f5dd7de21a
commit
a90be859a5
164
src/boot/src/ports/alif/alif.ld.S
Normal file
164
src/boot/src/ports/alif/alif.ld.S
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Entry Point
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH_TEXT (rx) : ORIGIN = OMV_FLASH_ORIGIN, LENGTH = OMV_FLASH_LENGTH
|
||||||
|
ITCM (rx) : ORIGIN = OMV_ITCM_ORIGIN, LENGTH = OMV_ITCM_LENGTH
|
||||||
|
DTCM (rw) : ORIGIN = OMV_DTCM_ORIGIN, LENGTH = OMV_DTCM_LENGTH
|
||||||
|
#if defined(OMV_SRAM0_ORIGIN)
|
||||||
|
SRAM0 (rw) : ORIGIN = OMV_SRAM0_ORIGIN, LENGTH = OMV_SRAM0_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM1_ORIGIN)
|
||||||
|
SRAM1 (rw) : ORIGIN = OMV_SRAM1_ORIGIN, LENGTH = OMV_SRAM1_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM6_A_ORIGIN)
|
||||||
|
SRAM6_A (rw) : ORIGIN = OMV_SRAM6_A_ORIGIN, LENGTH = OMV_SRAM6_A_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM6_B_ORIGIN)
|
||||||
|
SRAM6_B (rw) : ORIGIN = OMV_SRAM6_B_ORIGIN, LENGTH = OMV_SRAM6_B_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM7_ORIGIN)
|
||||||
|
SRAM7 (rw) : ORIGIN = OMV_SRAM7_ORIGIN, LENGTH = OMV_SRAM7_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM8_ORIGIN)
|
||||||
|
SRAM8 (rw) : ORIGIN = OMV_SRAM8_ORIGIN, LENGTH = OMV_SRAM8_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM9_A_ORIGIN)
|
||||||
|
SRAM9_A (rw) : ORIGIN = OMV_SRAM9_A_ORIGIN, LENGTH = OMV_SRAM9_A_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_SRAM9_B_ORIGIN)
|
||||||
|
SRAM9_B (rw) : ORIGIN = OMV_SRAM9_B_ORIGIN, LENGTH = OMV_SRAM9_B_LENGTH
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text : ALIGN(16)
|
||||||
|
{
|
||||||
|
KEEP(*(.vectors))
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.rodata*)
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
.copy.table : ALIGN(4)
|
||||||
|
{
|
||||||
|
__copy_table_start__ = .;
|
||||||
|
LONG ( LOADADDR(.data) )
|
||||||
|
LONG ( ADDR(.data) )
|
||||||
|
LONG ( SIZEOF(.data)/4 )
|
||||||
|
__copy_table_end__ = .;
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
.zero.table : ALIGN(4)
|
||||||
|
{
|
||||||
|
__zero_table_start__ = .;
|
||||||
|
LONG (ADDR(.bss))
|
||||||
|
LONG (SIZEOF(.bss)/4)
|
||||||
|
LONG (ADDR(.bss.sram))
|
||||||
|
LONG (SIZEOF(.bss.sram)/4)
|
||||||
|
__zero_table_end__ = .;
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
.data : ALIGN(8)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
. = ALIGN(8);
|
||||||
|
*(.data.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > OMV_MAIN_MEMORY AT > FLASH_TEXT
|
||||||
|
|
||||||
|
/* Peripherals in expansion master 0 (such as USB, Ethernet, SD/MMC)
|
||||||
|
are by default configured as non-secure, so they don't have access
|
||||||
|
to DTCMs. This can be fixed in the ToC by allowing access to DTCMs
|
||||||
|
to all bus masters, for now these peripherals should place buffers
|
||||||
|
in regular SRAM */
|
||||||
|
.bss.sram (NOLOAD) : ALIGN(16)
|
||||||
|
{
|
||||||
|
*(.bss.sram*)
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > SRAM1
|
||||||
|
|
||||||
|
.bss : ALIGN(4)
|
||||||
|
{
|
||||||
|
__bss_start__ = .;
|
||||||
|
*(.bss)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.bss.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__bss_end__ = .;
|
||||||
|
} > OMV_MAIN_MEMORY
|
||||||
|
|
||||||
|
.init_fini_arrays : ALIGN(16)
|
||||||
|
{
|
||||||
|
KEEP(*(.init))
|
||||||
|
KEEP(*(.fini))
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* preinit data */
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP(*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* init data */
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP(*(SORT(.init_array.*)))
|
||||||
|
KEEP(*(.init_array))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* finit data */
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP(*(SORT(.fini_array.*)))
|
||||||
|
KEEP(*(.fini_array))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
|
||||||
|
KEEP(*(.eh_frame*))
|
||||||
|
. = ALIGN(16);
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
#include "common.ld.S"
|
||||||
|
}
|
||||||
67
src/boot/src/ports/alif/alif_flash.c
Normal file
67
src/boot/src/ports/alif/alif_flash.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* Alif Flash driver.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include ALIF_CMSIS_H
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "omv_bootconfig.h"
|
||||||
|
#include "mram.h"
|
||||||
|
|
||||||
|
#if OMV_BOOT_AXI_FLASH_ENABLE
|
||||||
|
|
||||||
|
int axi_flash_read(uint32_t addr, uint8_t *buf, size_t size) {
|
||||||
|
memcpy(buf, (void *) addr, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int axi_flash_write(uint32_t addr, const uint8_t *buf, size_t size) {
|
||||||
|
// Note TinyUSB buffers are aligned to a multiple of the MRAM sector size.
|
||||||
|
if ((addr % MRAM_SECTOR_SIZE) || ((uint32_t) buf % MRAM_SECTOR_SIZE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round up to multiple of the MRAM sector size.
|
||||||
|
// Note TinyUSB buffers are much bigger than the MRAM sector size, so the
|
||||||
|
// writes can be rounded up, and we can read more than the specified size.
|
||||||
|
if (size % MRAM_SECTOR_SIZE) {
|
||||||
|
size = (size + (MRAM_SECTOR_SIZE - 1)) & ~(MRAM_SECTOR_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note writes must be 16 bytes aligned and a multiple of 16 bytes.
|
||||||
|
for (size_t i = 0; i < size / sizeof(uint64_t); i += 2) {
|
||||||
|
((volatile uint64_t *) addr)[i + 0] = ((volatile uint64_t *) buf)[i + 0];
|
||||||
|
((volatile uint64_t *) addr)[i + 1] = ((volatile uint64_t *) buf)[i + 1];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // OMV_BOOT_AXI_FLASH_ENABLE
|
||||||
524
src/boot/src/ports/alif/alif_ospi.c
Normal file
524
src/boot/src/ports/alif/alif_ospi.c
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* ALif OSPI driver.
|
||||||
|
* Note this driver uses SPI mode, and should support any standard flash.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include ALIF_CMSIS_H
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "omv_bootconfig.h"
|
||||||
|
|
||||||
|
#if OMV_BOOT_SPI_FLASH_ENABLE
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "pinconf.h"
|
||||||
|
#include "ospi_private.h"
|
||||||
|
|
||||||
|
#define OSPI_INST_0BIT (0x00U)
|
||||||
|
#define OSPI_INST_4BIT (0x01U)
|
||||||
|
#define OSPI_INST_8BIT (0x02U)
|
||||||
|
#define OSPI_INST_16BIT (0x03U)
|
||||||
|
|
||||||
|
#define OSPI_DFS_8BIT (0x07U)
|
||||||
|
#define OSPI_DFS_16BIT (0x0FU)
|
||||||
|
#define OSPI_DFS_32BIT (0x1FU)
|
||||||
|
|
||||||
|
#define OSPI_FRF_SINGLE (0x00U)
|
||||||
|
#define OSPI_FRF_DUAL (0x01U)
|
||||||
|
#define OSPI_FRF_QUAD (0x02U)
|
||||||
|
#define OSPI_FRF_OCTAL (0x03U)
|
||||||
|
|
||||||
|
#define OSPI_ADDR_0BIT (0x00U)
|
||||||
|
#define OSPI_ADDR_24BIT (0x06U)
|
||||||
|
#define OSPI_ADDR_32BIT (0x08U)
|
||||||
|
|
||||||
|
#define OSPI_FIFO_SIZE (128) // 256 words
|
||||||
|
#define OSPI_PAGE_SIZE (128)
|
||||||
|
#define OSPI_SECTOR_SIZE (4096)
|
||||||
|
#define OSPI_POLL_TIMEOUT (1000000)
|
||||||
|
|
||||||
|
#define OSPI_WRSR_COMMAND (0x01)
|
||||||
|
#define OSPI_RDSR_COMMAND (0x05)
|
||||||
|
#define OSPI_RDSR_DCYCLES (0)
|
||||||
|
|
||||||
|
#define OSPI_WRVL_COMMAND (0x81)
|
||||||
|
#define OSPI_RDVL_COMMAND (0x85)
|
||||||
|
|
||||||
|
#define OSPI_WRNV_COMMAND (0xB1)
|
||||||
|
#define OSPI_RDNV_COMMAND (0xB5)
|
||||||
|
|
||||||
|
#define OSPI_RDID_COMMAND (0x9F)
|
||||||
|
#define OSPI_RDID_DCYCLES (0)
|
||||||
|
|
||||||
|
#define OSPI_READ_COMMAND (0x13)
|
||||||
|
#define OSPI_READ_DCYCLES (0)
|
||||||
|
|
||||||
|
#define OSPI_WREN_COMMAND (0x06)
|
||||||
|
#define OSPI_WRITE_COMMAND (0x12)
|
||||||
|
|
||||||
|
#define OSPI_ERASE_COMMAND (0x21)
|
||||||
|
#define OSPI_ERASE_CHIP_COMMAND (0xC7)
|
||||||
|
|
||||||
|
typedef struct ospi_flash {
|
||||||
|
uint8_t ddr_mode;
|
||||||
|
uint8_t spi_mode;
|
||||||
|
ssi_regs_t *regs;
|
||||||
|
aes_regs_t *aes_regs;
|
||||||
|
volatile void *xip_base;
|
||||||
|
uint8_t initialized;
|
||||||
|
bool bswap16;
|
||||||
|
bool recovered;
|
||||||
|
} ospi_flash_t;
|
||||||
|
|
||||||
|
static ospi_flash_t ospi = { 0 };
|
||||||
|
|
||||||
|
static void port_delay_ns(uint32_t ns) {
|
||||||
|
for (size_t i = 0; i < (ns / 2.5); i++) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ospi_setup(ospi_flash_t *ospi, uint32_t addr_len, uint32_t ndf, uint32_t wait_cycles) {
|
||||||
|
ospi_writel(ospi, ser, 0);
|
||||||
|
spi_disable(ospi);
|
||||||
|
|
||||||
|
uint32_t val = CTRLR0_IS_MST
|
||||||
|
| (OSPI_DFS_8BIT << CTRLR0_DFS_OFFSET)
|
||||||
|
| (OSPI_FRF_SINGLE << CTRLR0_SPI_FRF_OFFSET)
|
||||||
|
| ((ndf ? SPI_TMOD_TR : TMOD_TO) << CTRLR0_TMOD_OFFSET);
|
||||||
|
|
||||||
|
ospi_writel(ospi, ctrlr0, val);
|
||||||
|
ospi_writel(ospi, ctrlr1, (ndf ? (ndf - 1) : 0));
|
||||||
|
|
||||||
|
val = TRANS_TYPE_FRF_DEFINED
|
||||||
|
| (1 << CTRLR0_SPI_RXDS_EN_OFFSET)
|
||||||
|
| (addr_len << CTRLR0_ADDR_L_OFFSET)
|
||||||
|
| (OSPI_INST_8BIT << CTRLR0_INST_L_OFFSET)
|
||||||
|
| (wait_cycles << CTRLR0_WAIT_CYCLES_OFFSET);
|
||||||
|
|
||||||
|
ospi_writel(ospi, spi_ctrlr0, val);
|
||||||
|
spi_enable(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ospi_push(ospi_flash_t *ospi, uint32_t data) {
|
||||||
|
ospi_writel(ospi, data_reg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_wait_busy(ospi_flash_t *ospi) {
|
||||||
|
uint32_t timeout = OSPI_POLL_TIMEOUT;
|
||||||
|
while ((ospi_readl(ospi, sr) & (SR_TF_EMPTY | SR_BUSY)) != SR_TF_EMPTY) {
|
||||||
|
if (--timeout == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_send(ospi_flash_t *ospi, uint32_t cmd, uint32_t addr_len,
|
||||||
|
uint32_t addr, uint32_t data_len, const uint8_t *data) {
|
||||||
|
ospi_setup(ospi, addr_len, 0, 0);
|
||||||
|
ospi_push(ospi, cmd);
|
||||||
|
|
||||||
|
// Push the address (0, 24, or 32 bits).
|
||||||
|
for (size_t i = 0; i < addr_len / 2; i++) {
|
||||||
|
ospi_push(ospi, addr >> ((addr_len / 2 - 1) * 8 - i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data_len; i++) {
|
||||||
|
ospi_push(ospi, data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ospi_writel(ospi, ser, OMV_BOOT_OSPI_SER);
|
||||||
|
return ospi_flash_wait_busy(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_recv(ospi_flash_t *ospi, uint32_t cmd, uint32_t addr_len,
|
||||||
|
uint32_t addr, size_t data_len, uint8_t *data, uint32_t dcycles) {
|
||||||
|
|
||||||
|
ospi_setup(ospi, addr_len, data_len, dcycles);
|
||||||
|
ospi_push(ospi, cmd);
|
||||||
|
|
||||||
|
// Push the address (0, 24, or 32 bits).
|
||||||
|
for (size_t i = 0; i < addr_len / 2; i++) {
|
||||||
|
ospi_push(ospi, addr >> ((addr_len / 2 - 1) * 8 - i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push dummy bytes as many as the data size.
|
||||||
|
for (size_t i = 0; i < data_len; i++) {
|
||||||
|
ospi_push(ospi, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
ospi_writel(ospi, ser, OMV_BOOT_OSPI_SER);
|
||||||
|
|
||||||
|
// Skip the command and address high-z bytes.
|
||||||
|
uint32_t skip_len = addr_len / 2 + 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < skip_len + data_len; i++) {
|
||||||
|
unsigned int timeout = 100000;
|
||||||
|
|
||||||
|
while (ospi_readl(ospi, rxflr) == 0) {
|
||||||
|
if (--timeout == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < skip_len) {
|
||||||
|
(void) ospi_readl(ospi, data_reg);
|
||||||
|
} else {
|
||||||
|
data[i - skip_len] = ospi_readl(ospi, data_reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_wait_sr(ospi_flash_t *ospi, uint8_t mask, uint8_t val, uint32_t timeout) {
|
||||||
|
do {
|
||||||
|
uint8_t sr;
|
||||||
|
if (ospi_recv(ospi, OSPI_RDSR_COMMAND, OSPI_ADDR_0BIT, 0, 1, &sr, OSPI_RDSR_DCYCLES) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((sr & mask) == val) {
|
||||||
|
return 0; // success
|
||||||
|
}
|
||||||
|
} while (timeout--);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_wait_wel1(ospi_flash_t *ospi) {
|
||||||
|
return ospi_flash_wait_sr(ospi, 2, 2, OSPI_POLL_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_wait_wip0(ospi_flash_t *ospi) {
|
||||||
|
return ospi_flash_wait_sr(ospi, 1, 0, OSPI_POLL_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_write_enable(ospi_flash_t *ospi) {
|
||||||
|
ospi_send(ospi, OSPI_WREN_COMMAND, OSPI_ADDR_0BIT, 0, 0, NULL);
|
||||||
|
return ospi_flash_wait_wel1(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ospi_flash_read_reg(ospi_flash_t *ospi, uint32_t cmd, uint32_t addr_len, uint32_t addr) {
|
||||||
|
uint8_t buf;
|
||||||
|
if (ospi_recv(ospi, cmd, addr_len, addr, 1, &buf, 0) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ospi_flash_write_reg(ospi_flash_t *ospi, uint32_t cmd, uint32_t addr_len, uint32_t addr, uint8_t buf) {
|
||||||
|
if (ospi_flash_write_enable(ospi) != 0 ||
|
||||||
|
ospi_send(ospi, cmd, addr_len, addr, 1, &buf) != 0 ||
|
||||||
|
ospi_flash_wait_wip0(ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_chip_erase(ospi_flash_t *ospi, uint32_t value) {
|
||||||
|
// Configure erase value
|
||||||
|
uint32_t nv_reg = 0x7F | ((value & 1) << 7);
|
||||||
|
if (ospi_flash_write_reg(ospi, OSPI_WRVL_COMMAND, OSPI_ADDR_24BIT, 0x08, nv_reg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ospi_flash_write_enable(ospi) != 0 ||
|
||||||
|
ospi_send(ospi, OSPI_ERASE_CHIP_COMMAND, OSPI_ADDR_0BIT, 0, 0, NULL) != 0 ||
|
||||||
|
ospi_flash_wait_sr(ospi, 1, 0, 400000) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_reset(ospi_flash_t *ospi) {
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_RST_PIN, 0);
|
||||||
|
port_delay_ms(1);
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_RST_PIN, 1);
|
||||||
|
port_delay_ms(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_init(ospi_flash_t *ospi) {
|
||||||
|
if (ospi->initialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset flash.
|
||||||
|
ospi_flash_reset(ospi);
|
||||||
|
|
||||||
|
// Use SPI mode for initialization.
|
||||||
|
ospi->spi_mode = true;
|
||||||
|
ospi->regs = (ssi_regs_t *) OMV_BOOT_OSPI_SSI_BASE;
|
||||||
|
ospi->aes_regs = (aes_regs_t *) OMV_BOOT_OSPI_AES_BASE;
|
||||||
|
ospi->xip_base = (volatile void *) OMV_BOOT_OSPI_XIP_BASE;
|
||||||
|
|
||||||
|
// Initialize OSPI.
|
||||||
|
spi_disable(ospi);
|
||||||
|
ospi_writel(ospi, ser, 0);
|
||||||
|
ospi_writel(ospi, rx_sample_dly, OMV_BOOT_OSPI_RX_DELAY);
|
||||||
|
ospi_writel(ospi, txd_drive_edge, OMV_BOOT_OSPI_DDR_EDGE);
|
||||||
|
ospi->aes_regs->aes_control &= ~AES_CONTROL_XIP_EN;
|
||||||
|
ospi->aes_regs->aes_rxds_delay = OMV_BOOT_OSPI_RXDS_DELAY;
|
||||||
|
spi_set_clk(ospi, (GetSystemAXIClock() / OMV_BOOT_OSPI_CLOCK));
|
||||||
|
spi_enable(ospi);
|
||||||
|
|
||||||
|
// Detect onboard flash based on ID.
|
||||||
|
uint8_t id[3] = { 0 };
|
||||||
|
ospi_recv(ospi, OSPI_RDID_COMMAND, OSPI_ADDR_0BIT, 0, 3, id, OSPI_RDID_DCYCLES);
|
||||||
|
// The byte order of 16-bit words is swapped when written in 1-1-1 and read back
|
||||||
|
// in 8D-8D-8D. The MX chips seems to be the only one that doesn't swap 16-bit words.
|
||||||
|
ospi->bswap16 = id[0] != 0xC2;
|
||||||
|
ospi->initialized = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_deinit(ospi_flash_t *ospi) {
|
||||||
|
if (ospi->regs) {
|
||||||
|
spi_disable(ospi);
|
||||||
|
spi_set_clk(ospi, 0);
|
||||||
|
}
|
||||||
|
ospi->initialized = false;
|
||||||
|
|
||||||
|
// Reset flash.
|
||||||
|
return ospi_flash_reset(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_erase(ospi_flash_t *ospi, uint32_t addr) {
|
||||||
|
if (ospi_flash_write_enable(ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ospi_send(ospi, OSPI_ERASE_COMMAND, OSPI_ADDR_32BIT, addr, 0, NULL) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ospi_flash_wait_wip0(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_read_page(ospi_flash_t *ospi, uint32_t addr, uint8_t *buf, uint32_t size) {
|
||||||
|
return ospi_recv(ospi, OSPI_READ_COMMAND, OSPI_ADDR_32BIT, addr, size, buf, OSPI_READ_DCYCLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospi_flash_write_page(ospi_flash_t *ospi, uint32_t addr, const uint8_t *buf, uint32_t size) {
|
||||||
|
if (ospi_flash_write_enable(ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ospi_send(ospi, OSPI_WRITE_COMMAND, OSPI_ADDR_32BIT, addr, size, buf) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ospi_flash_wait_wip0(ospi);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_flash_read(uint32_t addr, uint8_t *buf, uint32_t size) {
|
||||||
|
if (ospi_flash_init(&ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size / OSPI_FIFO_SIZE; i++) {
|
||||||
|
if (ospi_flash_read_page(&ospi, addr, buf, OSPI_FIFO_SIZE) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf += OSPI_FIFO_SIZE;
|
||||||
|
addr += OSPI_FIFO_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size % OSPI_FIFO_SIZE)) {
|
||||||
|
return ospi_flash_read_page(&ospi, addr, buf, (size % OSPI_FIFO_SIZE));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_flash_write(uint32_t addr, const uint8_t *buf, uint32_t size) {
|
||||||
|
if (ospi_flash_init(&ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((addr % OSPI_SECTOR_SIZE) == 0) {
|
||||||
|
if (ospi_flash_erase(&ospi, addr) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ospi.bswap16) {
|
||||||
|
uint16_t *buf16 = (uint16_t *) buf;
|
||||||
|
for (size_t i = 0; i < size / 2; i++) {
|
||||||
|
buf16[i] = __REV16(buf16[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size / OSPI_PAGE_SIZE; i++) {
|
||||||
|
if (ospi_flash_write_page(&ospi, addr, buf, OSPI_PAGE_SIZE) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf += OSPI_PAGE_SIZE;
|
||||||
|
addr += OSPI_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size % OSPI_PAGE_SIZE)) {
|
||||||
|
return ospi_flash_write_page(&ospi, addr, buf, (size % OSPI_PAGE_SIZE));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_flash_recovery(uint32_t addr, const uint8_t *buf, uint32_t size) {
|
||||||
|
static const uint8_t key[] = {
|
||||||
|
0x15, 0x9e, 0x7d, 0x42, 0x96, 0x1a, 0x71, 0xeb,
|
||||||
|
0x73, 0xa3, 0x26, 0x29, 0x2b, 0x08, 0x09, 0x0e,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ospi.recovered) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check recovery key.
|
||||||
|
if (size < 16 || memcmp(buf, key, sizeof(key))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init flash.
|
||||||
|
if (ospi_flash_init(&ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Perform JESD reset
|
||||||
|
const pin_t *cs = &omv_boot_pins[OMV_BOOT_OSPI_CS_PIN];
|
||||||
|
pinconf_set(cs->port, cs->pin, OMV_BOOT_ALT_GPIO, cs->pad);
|
||||||
|
port_pin_mode(OMV_BOOT_OSPI_CS_PIN, PIN_MODE_OUTPUT);
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_CS_PIN, 1);
|
||||||
|
|
||||||
|
const pin_t *d0 = &omv_boot_pins[OMV_BOOT_OSPI_D0_PIN];
|
||||||
|
pinconf_set(d0->port, d0->pin, OMV_BOOT_ALT_GPIO, d0->pad);
|
||||||
|
port_pin_mode(OMV_BOOT_OSPI_D0_PIN, PIN_MODE_OUTPUT);
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_D0_PIN, 0);
|
||||||
|
|
||||||
|
// Clock out 0, 1, 0, 1
|
||||||
|
for (size_t i = 0, v = 1; i < 4; v ^= 1, i++) {
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_CS_PIN, 0);
|
||||||
|
port_delay_ns(500);
|
||||||
|
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_D0_PIN, v);
|
||||||
|
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_CS_PIN, 1);
|
||||||
|
port_delay_ns(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert pin state.
|
||||||
|
pinconf_set(d0->port, d0->pin, d0->alt, d0->pad);
|
||||||
|
pinconf_set(cs->port, cs->pin, cs->alt, cs->pad);
|
||||||
|
|
||||||
|
// 2.Write Enable. Write Opcode 0x06 to set WEL bit to 1
|
||||||
|
if (ospi_flash_write_enable(&ospi) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. DFIM entry
|
||||||
|
if (ospi_flash_write_reg(&ospi, OSPI_WRVL_COMMAND, OSPI_ADDR_24BIT, 0x1E, 0x6B) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ospi_flash_read_reg(&ospi, OSPI_RDVL_COMMAND, OSPI_ADDR_24BIT, 0x1E) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
// 5.a Initialize status register to 0xFF
|
||||||
|
if (ospi_flash_write_reg(&ospi, OSPI_WRSR_COMMAND, OSPI_ADDR_0BIT, 0x00, 0xFF) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5.c Initialize status register to 0x00
|
||||||
|
if (ospi_flash_write_reg(&ospi, OSPI_WRSR_COMMAND, OSPI_ADDR_0BIT, 0x00, 0x00) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.a Initialize NCRs (Command=0xB1; Addr=0x00 to 0x0C; Data=0x00)
|
||||||
|
for (size_t addr = 0x00; addr <= 0x0C; addr++) {
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0xB1, OSPI_ADDR_24BIT, addr, 0x00) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.c Initialize NCRs (Command=0xB1; Addr=0x00 to 0x0C; Data=0x00)
|
||||||
|
for (size_t addr = 0x00; addr <= 0x0C; addr++) {
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0xB1, OSPI_ADDR_24BIT, addr, 0xFF) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
// 7.a Disable lock: Command=0x81; Addr=0x08; Data=0xF9
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0x81, OSPI_ADDR_24BIT, 0x08, 0xF9) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.b Write 13: Command=0x42; Addr=0x00 to end (n=257); Data=0xFF
|
||||||
|
for (size_t addr = 0; addr < 256; addr++) {
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0x42, OSPI_ADDR_24BIT, addr, 0xFF) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8.a Disable lock: Command=0x81; Addr=0x08; Data=0xF9
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0x81, OSPI_ADDR_24BIT, 0x08, 0xF9) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8.b Write 03: Command=0x42; Addr=0x00 to end (n=257); Data=0x00
|
||||||
|
for (size_t addr = 0; addr < 256; addr++) {
|
||||||
|
if (ospi_flash_write_reg(&ospi, 0x42, OSPI_ADDR_24BIT, addr, 0x00) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
// 9, 11 Write entire Device to 0
|
||||||
|
if (ospi_flash_chip_erase(&ospi, 0) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10, 12 Write entire Device to 1
|
||||||
|
if (ospi_flash_chip_erase(&ospi, 1) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DFIM exit
|
||||||
|
if (ospi_flash_write_reg(&ospi, OSPI_WRVL_COMMAND, OSPI_ADDR_24BIT, 0x1E, 0) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ospi.recovered = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_flash_deinit() {
|
||||||
|
return ospi_flash_deinit(&ospi);
|
||||||
|
}
|
||||||
|
#endif // OMV_BOOT_SPI_FLASH_ENABLE
|
||||||
208
src/boot/src/ports/alif/alif_port.c
Normal file
208
src/boot/src/ports/alif/alif_port.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* DFU bootloader Alif port.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include ALIF_CMSIS_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "pinconf.h"
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "omv_bootconfig.h"
|
||||||
|
#include "flash.h"
|
||||||
|
#include "alif_services.h"
|
||||||
|
|
||||||
|
static volatile uint32_t ticks_ms;
|
||||||
|
|
||||||
|
void SysTick_Handler(void) {
|
||||||
|
ticks_ms += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port_init(void) {
|
||||||
|
// Initialize the MPU and configure
|
||||||
|
// the default attributes and regions.
|
||||||
|
port_mpu_init();
|
||||||
|
|
||||||
|
// Initialize the services API.
|
||||||
|
alif_services_init();
|
||||||
|
|
||||||
|
// Initialize and configure SysTick.
|
||||||
|
SysTick_Config(SystemCoreClock / 1000);
|
||||||
|
|
||||||
|
// Configure pin mux.
|
||||||
|
for (size_t i = 0; i < OMV_BOOT_PINS_COUNT; i++) {
|
||||||
|
const pin_t *pin = &omv_boot_pins[i];
|
||||||
|
pinconf_set(pin->port, pin->pin, pin->alt, pin->pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure USB MUX GPIO.
|
||||||
|
port_pin_mode(OMV_BOOT_MUX_PIN, PIN_MODE_OUTPUT);
|
||||||
|
port_pin_write(OMV_BOOT_MUX_PIN, 1);
|
||||||
|
|
||||||
|
// Configure LED GPIO.
|
||||||
|
port_pin_mode(OMV_BOOT_LED_PIN, PIN_MODE_OUTPUT);
|
||||||
|
port_pin_write(OMV_BOOT_LED_PIN, 1);
|
||||||
|
|
||||||
|
// Configure OSPI reset GPIO.
|
||||||
|
port_pin_mode(OMV_BOOT_OSPI_RST_PIN, PIN_MODE_OUTPUT);
|
||||||
|
port_pin_write(OMV_BOOT_OSPI_RST_PIN, 0);
|
||||||
|
|
||||||
|
// Configure and enable USB IRQs.
|
||||||
|
NVIC_ClearPendingIRQ(USB_IRQ_IRQn);
|
||||||
|
NVIC_SetPriority(USB_IRQ_IRQn, OMV_BOOT_USB_IRQ_PRI);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port_deinit(void) {
|
||||||
|
// Deinit DCD and disable USB IRQs.
|
||||||
|
extern void dcd_uninit(void);
|
||||||
|
dcd_uninit();
|
||||||
|
|
||||||
|
// Deinit services API.
|
||||||
|
alif_services_deinit();
|
||||||
|
|
||||||
|
// Deinitialize SPI Flash.
|
||||||
|
#if OMV_BOOT_SPI_FLASH_ENABLE
|
||||||
|
spi_flash_deinit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Disable SysTick and its IRQ.
|
||||||
|
NVIC_DisableIRQ(SysTick_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(SysTick_IRQn);
|
||||||
|
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
|
||||||
|
|
||||||
|
// Clean/invalidate any cached lines.
|
||||||
|
SCB_CleanInvalidateDCache();
|
||||||
|
|
||||||
|
// Clear default regions and configure XIP regions (if any).
|
||||||
|
port_mpu_deinit();
|
||||||
|
|
||||||
|
// Turn off LED.
|
||||||
|
gpio_set_value_high(omv_boot_pins[OMV_BOOT_LED_PIN].gpio, omv_boot_pins[OMV_BOOT_LED_PIN].pin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port_get_uid(uint8_t *buf) {
|
||||||
|
alif_services_get_unique_id(buf, 12);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_mpu_protect(const partition_t *p, bool enable) {
|
||||||
|
if (p->region != -1) {
|
||||||
|
ARM_MPU_Disable();
|
||||||
|
MPU->RNR = p->region;
|
||||||
|
MPU->RBAR = ARM_MPU_RBAR(p->start, ARM_MPU_SH_NON, enable & 1, 1, 0); // RO/NP/XN.
|
||||||
|
MPU->RLAR = ARM_MPU_RLAR(p->limit - 1, p->attr);
|
||||||
|
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t port_ticks_ms() {
|
||||||
|
return ticks_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_delay_ms(uint32_t ms) {
|
||||||
|
uint32_t start_ms = port_ticks_ms();
|
||||||
|
while ((port_ticks_ms() - start_ms) < ms) {
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_pin_mode(uint32_t pin, uint32_t mode) {
|
||||||
|
if (mode == PIN_MODE_OUTPUT) {
|
||||||
|
gpio_set_direction_output(omv_boot_pins[pin].gpio, omv_boot_pins[pin].pin);
|
||||||
|
} else {
|
||||||
|
gpio_set_direction_input(omv_boot_pins[pin].gpio, omv_boot_pins[pin].pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_pin_write(uint32_t pin, uint32_t state) {
|
||||||
|
if (state) {
|
||||||
|
gpio_set_value_high(omv_boot_pins[pin].gpio, omv_boot_pins[pin].pin);
|
||||||
|
} else {
|
||||||
|
gpio_set_value_low(omv_boot_pins[pin].gpio, omv_boot_pins[pin].pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_led_blink(uint32_t interval_ms) {
|
||||||
|
static uint32_t start_ms = 0;
|
||||||
|
static uint32_t led_state = 0;
|
||||||
|
|
||||||
|
if ((port_ticks_ms() - start_ms) < interval_ms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
led_state ^= 1;
|
||||||
|
port_pin_write(OMV_BOOT_LED_PIN, led_state);
|
||||||
|
start_ms += interval_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass startup MPU defaults.
|
||||||
|
void MPU_Setup(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass startup MPU regions.
|
||||||
|
void MPU_Load_Regions(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void port_mpu_load_defaults() {
|
||||||
|
static const ARM_MPU_Region_t mpu_table[] __STARTUP_RO_DATA_ATTRIBUTE = {
|
||||||
|
{ /* SRAM0 - 4MB : RO-0, NP-1, XN-0 */
|
||||||
|
.RBAR = ARM_MPU_RBAR(0x02000000, ARM_MPU_SH_NON, 0, 1, 0),
|
||||||
|
.RLAR = ARM_MPU_RLAR(0x023FFFFF, MEMATTR_NORMAL_RA)
|
||||||
|
},
|
||||||
|
{ /* SRAM1 - 2.5MB : RO-0, NP-1, XN-0 */
|
||||||
|
.RBAR = ARM_MPU_RBAR(0x08000000, ARM_MPU_SH_NON, 0, 1, 0),
|
||||||
|
.RLAR = ARM_MPU_RLAR(0x0827FFFF, MEMATTR_NORMAL_WB_RA_WA)
|
||||||
|
},
|
||||||
|
{ /* Host Peripherals - 16MB : RO-0, NP-1, XN-1 */
|
||||||
|
.RBAR = ARM_MPU_RBAR(0x1A000000, ARM_MPU_SH_NON, 0, 1, 1),
|
||||||
|
.RLAR = ARM_MPU_RLAR(0x1AFFFFFF, MEMATTR_DEVICE_nGnRE)
|
||||||
|
},
|
||||||
|
{ /* OSPI Regs - 16MB : RO-0, NP-1, XN-1 */
|
||||||
|
.RBAR = ARM_MPU_RBAR(0x83000000, ARM_MPU_SH_NON, 0, 1, 1),
|
||||||
|
.RLAR = ARM_MPU_RLAR(0x83FFFFFF, MEMATTR_DEVICE_nGnRE)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Load the regions from the table */
|
||||||
|
ARM_MPU_Load(0, mpu_table, sizeof(mpu_table) / sizeof(ARM_MPU_Region_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) __fatal_error(const char *msg) {
|
||||||
|
while (1) {
|
||||||
|
port_led_blink(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
192
src/boot/src/ports/alif/alif_port.mk
Normal file
192
src/boot/src/ports/alif/alif_port.mk
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
# Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
#
|
||||||
|
# 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
# is done solely for personal benefit and not for any commercial
|
||||||
|
# purpose or for monetary gain. For commercial licensing options,
|
||||||
|
# please contact openmv@openmv.io
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
# OWNER 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 OpenMV board config first to set the port.
|
||||||
|
include $(OMV_BOARD_CONFIG_DIR)/omv_boardconfig.mk
|
||||||
|
|
||||||
|
LDSCRIPT ?= alif
|
||||||
|
BUILD := $(BUILD)/bootloader
|
||||||
|
FIRMWARE := bootloader
|
||||||
|
CMSIS_MCU_H := '<system_utils.h>'
|
||||||
|
|
||||||
|
# Compiler Flags
|
||||||
|
CFLAGS += -std=gnu99 \
|
||||||
|
-Wall \
|
||||||
|
-Werror \
|
||||||
|
-Warray-bounds \
|
||||||
|
-nostartfiles \
|
||||||
|
-fdata-sections \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fno-inline-small-functions \
|
||||||
|
-mfloat-abi=hard \
|
||||||
|
-mthumb \
|
||||||
|
-mcpu=$(CPU) \
|
||||||
|
-mtune=$(CPU) \
|
||||||
|
-mfpu=$(FPU) \
|
||||||
|
-march=armv8.1-m.main+fp+mve.fp \
|
||||||
|
-fsingle-precision-constant \
|
||||||
|
-Wdouble-promotion
|
||||||
|
|
||||||
|
CFLAGS += -D__VFP_FP__ \
|
||||||
|
-D$(TARGET) \
|
||||||
|
-D$(MCU_CORE) \
|
||||||
|
-DCORE_$(MCU_CORE)=1 \
|
||||||
|
-D$(ARM_MATH) \
|
||||||
|
-DARM_NN_TRUNCATE \
|
||||||
|
-DETHOS_U \
|
||||||
|
-DPINS_AF_H=$(PINS_AF_H) \
|
||||||
|
-DCMSIS_MCU_H=$(CMSIS_MCU_H) \
|
||||||
|
-DALIF_CMSIS_H=$(CMSIS_MCU_H) \
|
||||||
|
-DBOOTLOADER=1 \
|
||||||
|
-DOMV_NOSYS_STUBS_ENABLE=1 \
|
||||||
|
-DTUSB_ALIF_NO_IRQ_CFG \
|
||||||
|
-DOMV_BOOT_JUMP=$(OMV_FIRM_ADDR) \
|
||||||
|
$(OMV_BOOT_CFLAGS) \
|
||||||
|
$(OMV_BOARD_CFLAGS)
|
||||||
|
|
||||||
|
CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) \
|
||||||
|
-I$(TOP_DIR)/$(BOOT_DIR)/include \
|
||||||
|
-I$(TOP_DIR)/$(BOOT_DIR)/$(PORT_DIR) \
|
||||||
|
-I$(TOP_DIR)/$(CMSIS_DIR)/include \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/drivers/include \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/ospi_xip/source/ospi \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/se_services/include \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/Device/common/config \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/Device/common/include \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/Device/core/$(MCU_CORE)/config \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/Device/core/$(MCU_CORE)/include \
|
||||||
|
-I$(TOP_DIR)/$(HAL_DIR)/Device/$(MCU_SERIES)/$(MCU_VARIANT) \
|
||||||
|
-I$(TOP_DIR)/$(TINYUSB_DIR)/src
|
||||||
|
|
||||||
|
# Linker Flags
|
||||||
|
LDFLAGS = -mthumb \
|
||||||
|
-mcpu=$(CPU) \
|
||||||
|
-mfpu=$(FPU) \
|
||||||
|
-mfloat-abi=hard \
|
||||||
|
-mabi=aapcs-linux \
|
||||||
|
-Wl,--print-memory-usage \
|
||||||
|
-Wl,--gc-sections \
|
||||||
|
-Wl,--no-warn-rwx-segment \
|
||||||
|
-Wl,-Map=$(BUILD)/$(FIRMWARE).map \
|
||||||
|
-Wl,-T$(BUILD)/$(LDSCRIPT).lds
|
||||||
|
|
||||||
|
SRC_C += $(addprefix src/common/, \
|
||||||
|
dfu.c \
|
||||||
|
mpu.c \
|
||||||
|
desc.c \
|
||||||
|
main.c \
|
||||||
|
)
|
||||||
|
|
||||||
|
SRC_C += $(addprefix $(PORT_DIR)/, \
|
||||||
|
alif_ospi.c \
|
||||||
|
alif_port.c \
|
||||||
|
alif_flash.c \
|
||||||
|
alif_services.c \
|
||||||
|
)
|
||||||
|
|
||||||
|
SRC_C += $(addprefix $(OMV_COMMON_DIR)/, \
|
||||||
|
nosys_stubs.c \
|
||||||
|
)
|
||||||
|
|
||||||
|
SRC_C += $(addprefix $(TINYUSB_DIR)/, \
|
||||||
|
src/tusb.c \
|
||||||
|
src/class/dfu/dfu_device.c \
|
||||||
|
src/common/tusb_fifo.c \
|
||||||
|
src/device/usbd.c \
|
||||||
|
src/device/usbd_control.c \
|
||||||
|
)
|
||||||
|
|
||||||
|
SRC_C += $(addprefix $(HAL_DIR)/, \
|
||||||
|
drivers/source/pinconf.c \
|
||||||
|
drivers/source/mhu_driver.c \
|
||||||
|
drivers/source/mhu_receiver.c \
|
||||||
|
drivers/source/mhu_sender.c \
|
||||||
|
Device/common/source/clk.c \
|
||||||
|
Device/common/source/dcd.c \
|
||||||
|
Device/common/source/mpu_M55.c \
|
||||||
|
Device/common/source/tgu_M55.c \
|
||||||
|
Device/common/source/system_M55.c \
|
||||||
|
Device/common/source/system_utils.c \
|
||||||
|
Device/common/source/tcm_partition.c \
|
||||||
|
Device/core/$(MCU_CORE)/source/startup_$(MCU_CORE).c \
|
||||||
|
se_services/source/services_host_clocks.c \
|
||||||
|
se_services/source/services_host_handler.c \
|
||||||
|
se_services/source/services_host_power.c \
|
||||||
|
se_services/source/services_host_system.c \
|
||||||
|
se_services/source/services_host_maintenance.c \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Firmware objects
|
||||||
|
OBJS += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||||
|
OBJS += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
|
||||||
|
OBJS_DIR = $(sort $(dir $(OBJS)))
|
||||||
|
|
||||||
|
$(BUILD)/$(HAL_DIR)/se_services/source/services_host_boot.o: override CFLAGS += -Wno-stringop-truncation
|
||||||
|
$(BUILD)/$(HAL_DIR)/se_services/source/services_host_system.o: override CFLAGS += -Wno-maybe-uninitialized
|
||||||
|
|
||||||
|
all: $(FIRMWARE)
|
||||||
|
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
|
||||||
|
|
||||||
|
$(OBJS_DIR):
|
||||||
|
$(MKDIR) -p $@
|
||||||
|
|
||||||
|
$(BUILD)/%.o : %.c
|
||||||
|
$(ECHO) "CC $<"
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD)/$(HAL_DIR)/%.o : $(TOP_DIR)/$(HAL_DIR)/%.c
|
||||||
|
$(ECHO) "CC $(shell realpath --relative-to=pwd $<)"
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD)/$(TINYUSB_DIR)/%.o : $(TOP_DIR)/$(TINYUSB_DIR)/%.c
|
||||||
|
$(ECHO) "CC $(shell realpath --relative-to=pwd $<)"
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD)/$(OMV_COMMON_DIR)/%.o : $(TOP_DIR)/$(OMV_COMMON_DIR)/%.c
|
||||||
|
$(ECHO) "CC $(shell realpath --relative-to=pwd $<)"
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD)/%.o : %.s
|
||||||
|
$(ECHO) "AS $<"
|
||||||
|
$(AS) $(AFLAGS) $< -o $@
|
||||||
|
|
||||||
|
FIRMWARE_OBJS: | $(OBJS_DIR) $(OBJS)
|
||||||
|
|
||||||
|
$(FIRMWARE): FIRMWARE_OBJS
|
||||||
|
$(CPP) -P -E -DBOOTLOADER -DLINKER_SCRIPT -DCORE_$(MCU_CORE) -I$(OMV_COMMON_DIR) \
|
||||||
|
-I$(OMV_BOARD_CONFIG_DIR) $(PORT_DIR)/$(LDSCRIPT).ld.S > $(BUILD)/$(LDSCRIPT).lds
|
||||||
|
$(CC) $(LDFLAGS) $(OBJS) -o $(FW_DIR)/$(FIRMWARE).elf
|
||||||
|
$(OBJCOPY) -Obinary $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
|
||||||
|
BIN_SIZE=$$(stat -c%s "$(FW_DIR)/$(FIRMWARE).bin"); \
|
||||||
|
PADDED_SIZE=$$(( (BIN_SIZE + 15) / 16 * 16 )); \
|
||||||
|
if [ $$BIN_SIZE -lt $$PADDED_SIZE ]; then \
|
||||||
|
dd if=/dev/zero bs=1 count=$$((PADDED_SIZE - BIN_SIZE)) >> $(FW_DIR)/$(FIRMWARE).bin; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
-include $(OBJS:%.o=%.d)
|
||||||
153
src/boot/src/ports/alif/alif_services.c
Normal file
153
src/boot/src/ports/alif/alif_services.c
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2025 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* SE services helper functions.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include ALIF_CMSIS_H
|
||||||
|
#include "alif_services.h"
|
||||||
|
#include "services_lib_bare_metal.h"
|
||||||
|
|
||||||
|
// MHU indices.
|
||||||
|
#define MHU_M55_SE_MHU0 0
|
||||||
|
#define MAX_MHU 1
|
||||||
|
|
||||||
|
extern void __fatal_error(const char *msg);
|
||||||
|
|
||||||
|
static uint32_t se_handle;
|
||||||
|
static uint32_t se_buffer[SERVICES_MAX_PACKET_BUFFER_SIZE / sizeof(uint32_t)];
|
||||||
|
static mhu_driver_out_t mhu_driver_out;
|
||||||
|
|
||||||
|
static const uint32_t mhu_sender_base_address_list[MAX_MHU] = {
|
||||||
|
MHU_SESS_S_TX_BASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t mhu_receiver_base_address_list[MAX_MHU] = {
|
||||||
|
MHU_SESS_S_RX_BASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
void MHU_SESS_S_TX_IRQHandler(void) {
|
||||||
|
mhu_driver_out.sender_irq_handler(MHU_M55_SE_MHU0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MHU_SESS_S_RX_IRQHandler(void) {
|
||||||
|
mhu_driver_out.receiver_irq_handler(MHU_M55_SE_MHU0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy_printf(const char *fmt, ...) {
|
||||||
|
(void) fmt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void alif_services_init(void) {
|
||||||
|
// Initialize MHU.
|
||||||
|
mhu_driver_in_t mhu_driver_in = {
|
||||||
|
.sender_base_address_list = (uint32_t *) mhu_sender_base_address_list,
|
||||||
|
.receiver_base_address_list = (uint32_t *) mhu_receiver_base_address_list,
|
||||||
|
.mhu_count = MAX_MHU,
|
||||||
|
.send_msg_acked_callback = SERVICES_send_msg_acked_callback,
|
||||||
|
.rx_msg_callback = SERVICES_rx_msg_callback,
|
||||||
|
.debug_print = NULL, // not currently used by MHU_driver_initialize
|
||||||
|
};
|
||||||
|
MHU_driver_initialize(&mhu_driver_in, &mhu_driver_out);
|
||||||
|
|
||||||
|
// Initialize SE services.
|
||||||
|
services_lib_t services_init_params = {
|
||||||
|
.packet_buffer_address = (uint32_t) se_buffer,
|
||||||
|
.fn_send_mhu_message = mhu_driver_out.send_message,
|
||||||
|
.fn_wait_ms = NULL, // not currently used by services_host_handler.c
|
||||||
|
.wait_timeout = 1000000,
|
||||||
|
.fn_print_msg = dummy_printf,
|
||||||
|
};
|
||||||
|
SERVICES_initialize(&services_init_params);
|
||||||
|
|
||||||
|
// Create SE services channel for sending requests.
|
||||||
|
se_handle = SERVICES_register_channel(MHU_M55_SE_MHU0, 0);
|
||||||
|
|
||||||
|
// Enable MHU RX IRQ.
|
||||||
|
NVIC_SetPriority(MHU_SESS_S_RX_IRQ_IRQn, 0);
|
||||||
|
NVIC_ClearPendingIRQ(MHU_SESS_S_RX_IRQ_IRQn);
|
||||||
|
NVIC_EnableIRQ(MHU_SESS_S_RX_IRQ_IRQn);
|
||||||
|
|
||||||
|
// Enable MHU TX IRQ.
|
||||||
|
NVIC_SetPriority(MHU_SESS_S_TX_IRQ_IRQn, 0);
|
||||||
|
NVIC_ClearPendingIRQ(MHU_SESS_S_TX_IRQ_IRQn);
|
||||||
|
NVIC_EnableIRQ(MHU_SESS_S_TX_IRQ_IRQn);
|
||||||
|
|
||||||
|
// Send heartbeat services requests until one succeeds.
|
||||||
|
SERVICES_synchronize_with_se(se_handle);
|
||||||
|
|
||||||
|
// Set default run profile
|
||||||
|
run_profile_t run_profile = {
|
||||||
|
.dcdc_mode = DCDC_MODE_PWM,
|
||||||
|
.dcdc_voltage = DCDC_VOUT_0825,
|
||||||
|
.aon_clk_src = CLK_SRC_LFXO,
|
||||||
|
.run_clk_src = CLK_SRC_PLL,
|
||||||
|
#if CORE_M55_HP
|
||||||
|
.cpu_clk_freq = CLOCK_FREQUENCY_400MHZ,
|
||||||
|
#else
|
||||||
|
.cpu_clk_freq = CLOCK_FREQUENCY_160MHZ,
|
||||||
|
#endif
|
||||||
|
.scaled_clk_freq = SCALED_FREQ_XO_HIGH_DIV_38_4_MHZ,
|
||||||
|
.power_domains = PD_VBAT_AON_MASK | PD_SSE700_AON_MASK | PD_SYST_MASK |
|
||||||
|
PD_DBSS_MASK | PD_SESS_MASK | PD_SRAMS_MASK | PD_SRAM_CTRL_AON_MASK,
|
||||||
|
.memory_blocks = SERAM_MASK | SRAM0_MASK | SRAM1_MASK | MRAM_MASK | BACKUP4K_MASK,
|
||||||
|
.ip_clock_gating = OSPI_1_MASK | USB_MASK | LP_PERIPH_MASK,
|
||||||
|
.phy_pwr_gating = LDO_PHY_MASK | USB_PHY_MASK,
|
||||||
|
.vdd_ioflex_3V3 = IOFLEX_LEVEL_3V3,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t error;
|
||||||
|
SERVICES_set_run_cfg(se_handle, &run_profile, &error);
|
||||||
|
if (error) {
|
||||||
|
__fatal_error("SERVICES_set_run_cfg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void alif_services_deinit(void) {
|
||||||
|
// Disable MHU RX IRQ.
|
||||||
|
NVIC_DisableIRQ(MHU_SESS_S_RX_IRQ_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(MHU_SESS_S_RX_IRQ_IRQn);
|
||||||
|
|
||||||
|
// Disable MHU TX IRQ.
|
||||||
|
NVIC_DisableIRQ(MHU_SESS_S_TX_IRQ_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(MHU_SESS_S_TX_IRQ_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void alif_services_get_unique_id(uint8_t *id, size_t len) {
|
||||||
|
uint32_t error;
|
||||||
|
SERVICES_version_data_t data = { 0 };
|
||||||
|
SERVICES_system_get_device_data(se_handle, &data, &error);
|
||||||
|
if (error == 0) {
|
||||||
|
memcpy(id, data.MfgData, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/boot/src/ports/alif/alif_services.h
Normal file
38
src/boot/src/ports/alif/alif_services.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2025 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* SE services helper functions.
|
||||||
|
*/
|
||||||
|
#ifndef __ALIF_PORT_SE_H__
|
||||||
|
#define __ALIF_PORT_SE_H__
|
||||||
|
void alif_services_init(void);
|
||||||
|
void alif_services_deinit(void);
|
||||||
|
void alif_services_get_unique_id(uint8_t *id, size_t len);
|
||||||
|
#endif // __ALIF_PORT_SE_H__
|
||||||
52
src/boot/src/ports/alif/tusb_config.h
Normal file
52
src/boot/src/ports/alif/tusb_config.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* 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. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "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 LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER 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.
|
||||||
|
*
|
||||||
|
* TinyUSB config.
|
||||||
|
*/
|
||||||
|
#ifndef __ALIF_TUSB_CONFIG_H__
|
||||||
|
#define __ALIF_TUSB_CONFIG_H__
|
||||||
|
// Common configuration
|
||||||
|
#define CFG_TUSB_OS OPT_OS_NONE
|
||||||
|
#define CFG_TUSB_MCU OPT_MCU_NONE
|
||||||
|
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
|
||||||
|
#define TUP_DCD_ENDPOINT_MAX (8)
|
||||||
|
|
||||||
|
// Device stack configuration.
|
||||||
|
#define CFG_TUD_ENABLED (1)
|
||||||
|
#define CFG_TUD_DFU (1)
|
||||||
|
#define CFG_TUD_ENDPOINT0_SIZE (64)
|
||||||
|
#define CFG_TUD_DFU_XFER_BUFSIZE (4096)
|
||||||
|
|
||||||
|
// Peripherals in expansion master 0 (such as USB, Ethernet, SD/MMC)
|
||||||
|
// are by default configured as non-secure, so they don't have access
|
||||||
|
// to DTCMs. These peripherals should place buffers in regular SRAM.
|
||||||
|
#define CFG_TUSB_MEM_SECTION __attribute__((section(".bss.sram0")))
|
||||||
|
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(256)))
|
||||||
|
#endif //__ALIF_TUSB_CONFIG_H__
|
||||||
Loading…
Reference in New Issue
Block a user