From 26fb1eeef42bb46497447056ecac7a5e2271d007 Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Mon, 18 Jul 2022 20:51:43 +0200 Subject: [PATCH 1/6] mimxrt/flash: Splits mimxrt_flash.c. Splits `mimxrt_flash.c` into low-level driver functions and MicroPython code. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/Makefile | 1 + ports/mimxrt/flash.c | 127 ++++++++++++++++++++++++++++++++++++ ports/mimxrt/flash.h | 47 +++++++++++++ ports/mimxrt/mimxrt_flash.c | 51 +-------------- 4 files changed, 178 insertions(+), 48 deletions(-) create mode 100644 ports/mimxrt/flash.c create mode 100644 ports/mimxrt/flash.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 7ae3f918371b3..6423de23097aa 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -158,6 +158,7 @@ SRC_C += \ extmod/modusocket.c \ extmod/uos_dupterm.c \ fatfs_port.c \ + flash.c \ hal/pwm_backport.c \ led.c \ machine_adc.c \ diff --git a/ports/mimxrt/flash.c b/ports/mimxrt/flash.c new file mode 100644 index 0000000000000..9fccacb583051 --- /dev/null +++ b/ports/mimxrt/flash.c @@ -0,0 +1,127 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include "flash.h" + +// --------------------------------------------------------------------+ +// Global Function Definitions +// --------------------------------------------------------------------+ +void flash_init(void) { + // Upload the custom flash configuration + // This should be performed by the boot ROM but for some reason it is not. + FLEXSPI_UpdateLUT(FLEXSPI, 0, + qspiflash_config.memConfig.lookupTable, + ARRAY_SIZE(qspiflash_config.memConfig.lookupTable)); + + // Configure FLEXSPI IP FIFO access. + FLEXSPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK); + FLEXSPI->MCR0 &= ~(FLEXSPI_MCR0_ATDFEN_MASK); + FLEXSPI->MCR0 |= FLEXSPI_MCR0_ARDFEN(0); + FLEXSPI->MCR0 |= FLEXSPI_MCR0_ATDFEN(0); + + FLEXSPI_EnableIPParallelMode(FLEXSPI, true); +} + +// flash_erase_block(erase_addr) +// erases the block starting at addr. Block size according to the flash properties. +status_t flash_erase_block(uint32_t erase_addr) { + status_t status = kStatus_Fail; + + SCB_CleanInvalidateDCache(); + SCB_DisableDCache(); + __disable_irq(); + + status = flexspi_nor_flash_erase_block(FLEXSPI, erase_addr); + + __enable_irq(); + SCB_EnableDCache(); + + return status; +} + +// flash_erase_sector(erase_addr_bytes) +// erases the sector starting at addr. Sector size according to the flash properties. +status_t flash_erase_sector(uint32_t erase_addr) { + status_t status = kStatus_Fail; + + SCB_CleanInvalidateDCache(); + SCB_DisableDCache(); + __disable_irq(); + + status = flexspi_nor_flash_erase_sector(FLEXSPI, erase_addr); + + __enable_irq(); + SCB_EnableDCache(); + + return status; +} + +// flash_write_block(flash_dest_addr_bytes, data_source, length_bytes) +// writes length_byte data to the destination address +// the vfs driver takes care for erasing the sector if required +status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) { + #if FLASH_DISABLE_OP == 1 + return kStatus_Success; + #else + status_t status = kStatus_Fail; + uint32_t size; + uint32_t next_addr; + + if (length == 0) { + status = kStatus_Success; // Nothing to do + } else { + + SCB_CleanInvalidateDCache(); + SCB_DisableDCache(); + + // write data in chunks not crossing a page boundary + while (length > 0) { + next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary + size = next_addr - dest_addr; // maximal chunk length + if (size > length) { // compare against remaining data size + size = length; + } + + __disable_irq(); + + status = flexspi_nor_flash_page_program(FLEXSPI, dest_addr, (uint32_t *)src, size); + + __enable_irq(); + + if (status != kStatus_Success) { + break; + } + length -= size; + src += size; + dest_addr += size; + } + + SCB_EnableDCache(); + + } + return status; + #endif +} diff --git a/ports/mimxrt/flash.h b/ports/mimxrt/flash.h new file mode 100644 index 0000000000000..65e4f6085c4e8 --- /dev/null +++ b/ports/mimxrt/flash.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_FLASH_H +#define MICROPY_INCLUDED_MIMXRT_FLASH_H + +#include BOARD_FLASH_OPS_HEADER_H + +// --------------------------------------------------------------------+ +// Defines and Macros +// --------------------------------------------------------------------+ +#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize) +#define PAGE_SIZE_BYTES (qspiflash_config.pageSize) +#define BLOCK_SIZE_BYTES (qspiflash_config.blockSize) + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ +void flash_init(void); +__attribute__((section(".ram_functions"))) status_t flash_erase_sector(uint32_t erase_addr); +__attribute__((section(".ram_functions"))) status_t flash_erase_block(uint32_t erase_addr); +__attribute__((section(".ram_functions"))) status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length); + +#endif // MICROPY_INCLUDED_MIMXRT_FLASH_H diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c index 27ab987ed17f2..05aa3d6f02216 100644 --- a/ports/mimxrt/mimxrt_flash.c +++ b/ports/mimxrt/mimxrt_flash.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "extmod/vfs.h" #include "modmimxrt.h" +#include "flash.h" #include BOARD_FLASH_OPS_HEADER_H #define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize) @@ -60,52 +61,6 @@ STATIC mimxrt_flash_obj_t mimxrt_flash_obj = { .base = { &mimxrt_flash_type } }; -// flash_erase_block(erase_addr_bytes) -// erases the sector starting at addr. Sector size according to the flash properties. -status_t flash_erase_block(uint32_t erase_addr) __attribute__((section(".ram_functions"))); -status_t flash_erase_block(uint32_t erase_addr) { - status_t status; - SCB_CleanInvalidateDCache(); - SCB_DisableDCache(); - __disable_irq(); - status = flexspi_nor_flash_erase_sector(FLEXSPI, erase_addr); - __enable_irq(); - SCB_EnableDCache(); - return status; -} - -// flash_write_block(flash_dest_addr_bytes, data_source, length_bytes) -// writes length_byte data to the destination address -// the vfs driver takes care for erasing the sector if required -status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) __attribute__((section(".ram_functions"))); -status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) { - status_t status = 0; - uint32_t size; - uint32_t next_addr; - - SCB_CleanInvalidateDCache(); - SCB_DisableDCache(); - // write data in chunks not crossing a page boundary - while (length > 0) { - next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary - size = next_addr - dest_addr; // maximal chunk length - if (size > length) { // compare against remaining data size - size = length; - } - __disable_irq(); - status = flexspi_nor_flash_page_program(FLEXSPI, dest_addr, (uint32_t *)src, size); - __enable_irq(); - if (status != kStatus_Success) { - break; - } - length -= size; - src += size; - dest_addr += size; - } - SCB_EnableDCache(); - return status; -} - STATIC mp_obj_t mimxrt_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { // Check args. mp_arg_check_num(n_args, n_kw, 0, 0, false); @@ -161,7 +116,7 @@ STATIC mp_obj_t mimxrt_flash_writeblocks(size_t n_args, const mp_obj_t *args) { uint32_t offset = mp_obj_get_int(args[1]) * SECTOR_SIZE_BYTES; if (n_args == 3) { - status = flash_erase_block(self->flash_base + offset); + status = flash_erase_sector(self->flash_base + offset); if (status != kStatus_Success) { mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("flash erase command failed with %d"), status); @@ -199,7 +154,7 @@ STATIC mp_obj_t mimxrt_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t a return MP_OBJ_NEW_SMALL_INT(SECTOR_SIZE_BYTES); case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: { uint32_t offset = mp_obj_get_int(arg_in) * SECTOR_SIZE_BYTES; - status = flash_erase_block(self->flash_base + offset); + status = flash_erase_sector(self->flash_base + offset); return MP_OBJ_NEW_SMALL_INT(status != kStatus_Success); } default: From e84825be535cb09ceeef2bdfa84d4073861c4561 Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Mon, 18 Jul 2022 20:55:36 +0200 Subject: [PATCH 2/6] mimxrt/board_init: Refactors usb phy0 init. Refactors USB phy0 initialization routine. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/board_init.c | 53 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 12496890ac4a3..0406465b1970c 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -40,9 +40,10 @@ #include CLOCK_CONFIG_H #include "modmachine.h" - const uint8_t dcd_data[] = { 0x00 }; +void usb_phy0_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn); + void board_init(void) { // Init clock BOARD_BootClockRUN(); @@ -59,32 +60,8 @@ void board_init(void) { // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); - // ------------- USB0 ------------- // - // Clock - CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); - CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); - - #ifdef USBPHY1 - USBPHY_Type *usb_phy = USBPHY1; - #else - USBPHY_Type *usb_phy = USBPHY; - #endif - - // Enable PHY support for Low speed device + LS via FS Hub - usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; - - // Enable all power for normal operation - usb_phy->PWD = 0; - - // TX Timing - uint32_t phytx = usb_phy->TX; - phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK); - phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06); - usb_phy->TX = phytx; - - // USB1 - // CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U); - // CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U); + // USB0 + usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN // ADC machine_adc_init(); @@ -104,6 +81,28 @@ void board_init(void) { machine_rtc_start(); } +void usb_phy0_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn) { + #ifdef USBPHY1 + USBPHY_Type *usb_phy = USBPHY1; + #else + USBPHY_Type *usb_phy = USBPHY; + #endif + + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, BOARD_XTAL0_CLK_HZ); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, BOARD_XTAL0_CLK_HZ); + + #if defined(CPU_MIMXRT1176_cm7) + usb_phy->TRIM_OVERRIDE_EN = USBPHY_TRIM_OVERRIDE_EN_TRIM_DIV_SEL_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_ENV_TAIL_ADJ_VD_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_D_CAL_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DP_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DN_OVERRIDE(1); // Enable override for D_CAL and TXCAL45DP/DN + #endif + usb_phy->PWD = 0U; // Set all bits in PWD register to normal operation + usb_phy->TX = ((usb_phy->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(d_cal) | USBPHY_TX_TXCAL45DP(txcal45dp) | USBPHY_TX_TXCAL45DM(txcal45dn))); // Configure values for D_CAL and TXCAL45DP/DN +} + void USB_OTG1_IRQHandler(void) { tud_int_handler(0); tud_task(); From 19b7831186d4a549d8c79c794e2fd552bb95d1ae Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Thu, 9 Sep 2021 22:16:48 +0200 Subject: [PATCH 3/6] mimxrt/mboot: Adds bootloader support. Adds DFU bootloader for mimxrt port. The bootloader binary is packaged into the "normal" firmware binary. Therefore when setting up a new board the bootloader will be available automatically by just loading the normal firmware binary onto it. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/Makefile | 66 ++- .../boards/MIMXRT1010_EVK/mpconfigboard.mk | 2 + ports/mimxrt/boards/MIMXRT1011.ld | 24 +- ports/mimxrt/boards/MIMXRT1015.ld | 27 +- .../boards/MIMXRT1020_EVK/mpconfigboard.mk | 1 + ports/mimxrt/boards/MIMXRT1021.ld | 32 +- .../boards/MIMXRT1050_EVK/mpconfigboard.mk | 2 + ports/mimxrt/boards/MIMXRT1052.ld | 31 +- .../boards/MIMXRT1060_EVK/mpconfigboard.mk | 1 + ports/mimxrt/boards/MIMXRT1062.ld | 30 +- ports/mimxrt/boards/MIMXRT1064.ld | 35 +- .../boards/MIMXRT1064_EVK/mpconfigboard.mk | 1 + .../boards/OLIMEX_RT1010/mpconfigboard.mk | 2 + .../boards/SEEED_ARCH_MIX/mpconfigboard.mk | 1 + ports/mimxrt/boards/TEENSY40/mpconfigboard.mk | 2 + ports/mimxrt/boards/TEENSY41/mpconfigboard.mk | 1 + ports/mimxrt/boards/common.ld | 120 +++-- ports/mimxrt/boards/make-pins_new.py | 433 ++++++++++++++++++ ports/mimxrt/hal/flexspi_flash_config.h | 1 + ports/mimxrt/hal/flexspi_hyper_flash.c | 5 + ports/mimxrt/hal/flexspi_hyper_flash.h | 1 + ports/mimxrt/hal/flexspi_nor_flash.c | 31 ++ ports/mimxrt/hal/flexspi_nor_flash.h | 1 + ports/mimxrt/hal/qspi_nor_flash_config.c | 8 +- ports/mimxrt/hal/resethandler_MIMXRT10xx.S | 4 +- ports/mimxrt/main.c | 8 + ports/mimxrt/mboot.mk | 245 ++++++++++ ports/mimxrt/mboot/README.md | 36 ++ ports/mimxrt/mboot/boards/MIMXRT1011.ld | 19 + ports/mimxrt/mboot/boards/MIMXRT1015.ld | 15 + ports/mimxrt/mboot/boards/MIMXRT1021.ld | 15 + ports/mimxrt/mboot/boards/MIMXRT1052.ld | 15 + ports/mimxrt/mboot/boards/MIMXRT1062.ld | 15 + ports/mimxrt/mboot/boards/MIMXRT1064.ld | 18 + ports/mimxrt/mboot/boards/common.ld | 314 +++++++++++++ ports/mimxrt/mboot/boards/flexspi_nor_mboot.c | 54 +++ ports/mimxrt/mboot/boards/flexspi_nor_mboot.h | 111 +++++ .../hal/resethandler_mboot_MIMXRT10xx_RAM.S | 151 ++++++ ports/mimxrt/mboot/main.c | 156 +++++++ ports/mimxrt/mboot/mboot_buffer.c | 76 +++ ports/mimxrt/mboot/mboot_buffer.h | 52 +++ ports/mimxrt/mboot/mboot_dfu.c | 220 +++++++++ ports/mimxrt/mboot/mboot_dfu.h | 36 ++ ports/mimxrt/mboot/mboot_memory.h | 33 ++ ports/mimxrt/mboot/mboot_upgrade.c | 307 +++++++++++++ ports/mimxrt/mboot/mboot_upgrade.h | 75 +++ ports/mimxrt/mboot/mboot_utils.c | 33 ++ ports/mimxrt/mboot/mboot_utils.h | 39 ++ ports/mimxrt/mboot/mboot_validate.c | 130 ++++++ ports/mimxrt/mboot/mboot_validate.h | 48 ++ ports/mimxrt/mboot/shared/fw_header.h | 51 +++ ports/mimxrt/mboot/shared/mboot_command.h | 39 ++ ports/mimxrt/mboot/tools/patch-binary.py | 118 +++++ ports/mimxrt/mboot/tools/print_bin_info.py | 52 +++ ports/mimxrt/mboot/tusb_config.h | 108 +++++ ports/mimxrt/mboot/tusb_port.c | 162 +++++++ 56 files changed, 3427 insertions(+), 186 deletions(-) create mode 100644 ports/mimxrt/boards/make-pins_new.py create mode 100644 ports/mimxrt/mboot.mk create mode 100644 ports/mimxrt/mboot/README.md create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1011.ld create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1015.ld create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1021.ld create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1052.ld create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1062.ld create mode 100644 ports/mimxrt/mboot/boards/MIMXRT1064.ld create mode 100644 ports/mimxrt/mboot/boards/common.ld create mode 100644 ports/mimxrt/mboot/boards/flexspi_nor_mboot.c create mode 100644 ports/mimxrt/mboot/boards/flexspi_nor_mboot.h create mode 100644 ports/mimxrt/mboot/hal/resethandler_mboot_MIMXRT10xx_RAM.S create mode 100644 ports/mimxrt/mboot/main.c create mode 100644 ports/mimxrt/mboot/mboot_buffer.c create mode 100644 ports/mimxrt/mboot/mboot_buffer.h create mode 100644 ports/mimxrt/mboot/mboot_dfu.c create mode 100644 ports/mimxrt/mboot/mboot_dfu.h create mode 100644 ports/mimxrt/mboot/mboot_memory.h create mode 100644 ports/mimxrt/mboot/mboot_upgrade.c create mode 100644 ports/mimxrt/mboot/mboot_upgrade.h create mode 100644 ports/mimxrt/mboot/mboot_utils.c create mode 100644 ports/mimxrt/mboot/mboot_utils.h create mode 100644 ports/mimxrt/mboot/mboot_validate.c create mode 100644 ports/mimxrt/mboot/mboot_validate.h create mode 100644 ports/mimxrt/mboot/shared/fw_header.h create mode 100644 ports/mimxrt/mboot/shared/mboot_command.h create mode 100644 ports/mimxrt/mboot/tools/patch-binary.py create mode 100644 ports/mimxrt/mboot/tools/print_bin_info.py create mode 100644 ports/mimxrt/mboot/tusb_config.h create mode 100644 ports/mimxrt/mboot/tusb_port.c diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 6423de23097aa..e4bafdfedef00 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -4,6 +4,7 @@ BOARD ?= TEENSY40 BOARD_DIR ?= boards/$(BOARD) +BOOTLOADER_DIR ?= mboot BUILD ?= build-$(BOARD) PORT ?= /dev/ttyACM0 CROSS_COMPILE ?= arm-none-eabi- @@ -39,24 +40,28 @@ include $(TOP)/extmod/extmod.mk MCU_DIR = lib/nxp_driver/sdk/devices/$(MCU_SERIES) # Select linker scripts based on MCU_SERIES -LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld +LD_FILES = boards/common.ld # Parameter configurations for generation AF_FILE = boards/$(MCU_SERIES)_af.csv BOARD_PINS = $(BOARD_DIR)/pins.csv PREFIX_FILE = boards/mimxrt_prefix.c +PATCH_BINARY = mboot/tools/patch-binary.py GEN_FLEXRAM_CONFIG_SRC = $(BUILD)/flexram_config.s GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h GEN_PINS_AF_PY = $(BUILD)/pins_af.py GEN_PINS_HDR = $(HEADER_BUILD)/pins.h GEN_PINS_QSTR = $(BUILD)/pins_qstr.h GEN_PINS_SRC = $(BUILD)/pins_gen.c +# Include mboot make definitions +include mboot.mk # ============================================================================= # Includes # ============================================================================= INC += -I$(BOARD_DIR) +INC += -I$(BOOTLOADER_DIR)/shared INC += -I$(BUILD) INC += -I$(TOP) INC += -I$(TOP)/$(MCU_DIR) @@ -147,6 +152,9 @@ endif # C source files SRC_C += \ + $(SRC_ETH_C) \ + $(SRC_HAL_IMX_C) \ + $(SRC_TINYUSB_C) \ board_init.c \ boards/$(MCU_SERIES)_clock_config.c \ dma_manager.c \ @@ -201,10 +209,12 @@ SRC_C += \ shared/timeutils/timeutils.c \ systick.c \ ticks.c \ - tusb_port.c \ - $(SRC_TINYUSB_C) \ - $(SRC_HAL_IMX_C) \ - $(SRC_ETH_C) + tusb_port.c + +# Set default values if optional variables not defined +ifndef MICROPY_HW_BOARD_FLASH_FILES + MICROPY_HW_BOARD_FLASH_FILES = 0 +endif # Add sources for respective board flash type ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash qspi_hyper_flash)) @@ -221,6 +231,15 @@ else $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) endif + +# Set default values if optional variables not defined +ifndef SUPPORTS_HARDWARE_FP_DOUBLE + SUPPORTS_HARDWARE_FP_DOUBLE = 0 +endif +ifndef SUPPORTS_HARDWARE_FP_SINGLE + SUPPORTS_HARDWARE_FP_SINGLE = 0 +endif + # Math library source files ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ @@ -246,10 +265,6 @@ else endif endif -# Reset variables -SUPPORTS_HARDWARE_FP_SINGLE = 0 -SUPPORTS_HARDWARE_FP_DOUBLE = 0 - # Assembly source files SRC_SS = \ $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S \ @@ -405,7 +420,20 @@ LDFLAGS = \ LDDEFINES = \ -DMICROPY_HW_FLASH_TYPE=$(MICROPY_HW_FLASH_TYPE) \ - -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DBOARD_LINKER_SCRIPT_H=\"$(MCU_SERIES).ld\" \ + -DBOOTLOADER_ENABLED=1 + +# Start of firmware is dependent on board flash type. Bootloader requires at least 32kB. +# Firmware start has to be aligned to sector size to allow erase of firmware without affecting the bootloader. +# Sector size is different between QPSI flash (4kB) and HyperFlash (256kB) devices! +ifeq ($(MICROPY_HW_FLASH_TYPE),qspi_nor_flash) + LDDEFINES += -DMICROPY_HW_FLASH_FIRMWARE_START_ADDR=0x00008000 +else ifeq ($(MICROPY_HW_FLASH_TYPE),qspi_hyper_flash) + LDDEFINES += -DMICROPY_HW_FLASH_FIRMWARE_START_ADDR=0x00040000 +else + $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) +endif ifdef MICROPY_HW_FLASH_RESERVED LDDEFINES += -DMICROPY_HW_FLASH_RESERVED=$(MICROPY_HW_FLASH_RESERVED) @@ -454,10 +482,23 @@ $(BUILD)/firmware.elf: $(OBJ) $(Q)$(CC) -E -x c $(LDDEFINES) $(LD_FILES) | grep -v '^#' > $(BUILD)/link.ld $(ECHO) "LINK $@" $(Q)$(LD) -T$(BUILD)/link.ld $(LDFLAGS) -o $@ $^ $(LIBS) + $(ECHO) "" + $(ECHO) "UPDATE SECTION .fw_header" + $(Q)$(OBJCOPY) -O binary $@ $(BUILD)/temp_firmware.bin + $(Q)$(PYTHON) $(PATCH_BINARY) $(BUILD)/temp_firmware.bin $(BUILD)/fw_header.bin 1024 $$(($(MICROPY_BOOT_BUFFER_SIZE))) + $(Q)$(OBJCOPY) $@ --update-section .fw_header=$(BUILD)/fw_header.bin + $(ECHO) "$(BUILD)/fw_header.bin ==> .fw_header" + $(ECHO) "" + $(ECHO) "UPDATE SECTION .mboot" + $(Q)$(OBJCOPY) $@ --update-section .mboot=$(BUILD_BL)/mboot.bin + $(ECHO) "$(BUILD_BL)/mboot.bin ==> .mboot" + $(ECHO) "" + $(ECHO) "OUTPUT INFO" $(Q)$(SIZE) $@ + $(ECHO) "" $(BUILD)/firmware.bin: $(BUILD)/firmware.elf - $(Q)$(OBJCOPY) -O binary $^ $@ + $(Q)$(OBJCOPY) -O binary $< $@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(Q)$(OBJCOPY) -O ihex -R .eeprom $< $@ @@ -467,7 +508,7 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf # any of the objects. The normal dependency generation will deal with the # case when pins.h is modified. But when it doesn't exist, we don't know # which source files might need it. -$(OBJ): | $(GEN_PINS_HDR) $(GEN_FLEXRAM_CONFIG_SRC) +$(OBJ): | $(BUILD_BL)/mboot.bin $(BUILD_BL)/mboot.hex $(GEN_PINS_HDR) $(GEN_FLEXRAM_CONFIG_SRC) # With conditional pins, we may need to regenerate qstrdefs.h when config # options change. @@ -478,7 +519,6 @@ $(GEN_FLEXRAM_CONFIG_SRC): $(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES).h \ -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $(GEN_FLEXRAM_CONFIG_SRC) - # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_gen.c and pins.h $(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk index 19db53c3f8710..50824a4a177f3 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk @@ -6,6 +6,8 @@ MICROPY_PY_MACHINE_SDCARD = 0 MICROPY_HW_FLASH_TYPE = qspi_nor_flash MICROPY_HW_FLASH_SIZE = 0x1000000 # 16MB +MICROPY_BOOT_BUFFER_SIZE = (32 * 1024) + JLINK_PATH ?= /media/RT1010-EVK/ JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld index 908eefffd643f..910014ec42cdf 100644 --- a/ports/mimxrt/boards/MIMXRT1011.ld +++ b/ports/mimxrt/boards/MIMXRT1011.ld @@ -4,22 +4,16 @@ reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else -#error Unknown MICROPY_HW_FLASH_TYPE + #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); + +/* MIMXRT1011 requires different offset for flash configuration */ flash_config_start = flash_start + 0x00000400; flash_config_size = 0x00000C00; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; -vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); + itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; @@ -29,12 +23,6 @@ ocrm_size = 0x00010000; /* 20kiB stack. */ __stack_size__ = 0x5000; -_estack = __StackTop; -_sstack = __StackLimit; /* Do not use the traditional C heap. */ __heap_size__ = 0; - -/* Use second OCRAM bank for GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); diff --git a/ports/mimxrt/boards/MIMXRT1015.ld b/ports/mimxrt/boards/MIMXRT1015.ld index 90336a2437127..02ef5d3426fe6 100644 --- a/ports/mimxrt/boards/MIMXRT1015.ld +++ b/ports/mimxrt/boards/MIMXRT1015.ld @@ -1,25 +1,15 @@ /* Memory configuration */ -#if defined MICROPY_HW_FLASH_RESERVED +#if MICROPY_HW_FLASH_RESERVED reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else -#error Unknown MICROPY_HW_FLASH_TYPE + #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = flash_start; -flash_config_size = 0x00001000; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; -vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); + itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; @@ -29,10 +19,3 @@ ocrm_size = 0x00010000; /* 24kiB stack. */ __stack_size__ = 0x5000; -_estack = __StackTop; -_sstack = __StackLimit; - -/* Use second OCRAM bank for GC heap. */ -/* Use all OCRAM for the GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk index e8922e4b7abfb..af868ff6d4fcc 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk @@ -9,6 +9,7 @@ MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB +MICROPY_BOOT_BUFFER_SIZE = (32 * 1024) MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld index bef0c13df5505..28153f76b1de0 100644 --- a/ports/mimxrt/boards/MIMXRT1021.ld +++ b/ports/mimxrt/boards/MIMXRT1021.ld @@ -1,25 +1,15 @@ /* Memory configuration */ -#if defined MICROPY_HW_FLASH_RESERVED +#if MICROPY_HW_FLASH_RESERVED reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else -#error Unknown MICROPY_HW_FLASH_TYPE + #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = flash_start; -flash_config_size = 0x00001000; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; -vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); + itcm_start = 0x00000000; itcm_size = 0x00010000; dtcm_start = 0x20000000; @@ -34,15 +24,3 @@ sdram_size = MICROPY_HW_SDRAM_SIZE; /* 24kiB stack. */ __stack_size__ = 0x6000; -_estack = __StackTop; -_sstack = __StackLimit; - -#if MICROPY_HW_SDRAM_AVAIL -_gc_heap_start = ORIGIN(m_sdram); -_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); -#else -/* Use second OCRAM bank for GC heap. */ -/* Use all OCRAM for the GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); -#endif diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk index 00843350494a7..6ca244d6818f0 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk @@ -9,6 +9,8 @@ MICROPY_HW_FLASH_SIZE = 0x4000000 # 64MB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) + MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld index ca656711a5a77..e1e5525970e53 100644 --- a/ports/mimxrt/boards/MIMXRT1052.ld +++ b/ports/mimxrt/boards/MIMXRT1052.ld @@ -4,24 +4,16 @@ reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else -#error Unknown MICROPY_HW_FLASH_TYPE + #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = flash_start; -flash_config_size = 0x00001000; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; + vfs_start = flash_start + 0x00200000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; @@ -36,14 +28,3 @@ sdram_size = MICROPY_HW_SDRAM_SIZE; /* 24kiB stack. */ __stack_size__ = 0x6000; -_estack = __StackTop; -_sstack = __StackLimit; - -#if MICROPY_HW_SDRAM_AVAIL -_gc_heap_start = ORIGIN(m_sdram); -_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); -#else -/* Use second OCRAM bank for GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); -#endif diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk index 96afe276f706d..5a7cbd3407c35 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk @@ -9,6 +9,7 @@ MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld index 5b91550d97d60..36c30d1ad6d8f 100644 --- a/ports/mimxrt/boards/MIMXRT1062.ld +++ b/ports/mimxrt/boards/MIMXRT1062.ld @@ -4,24 +4,15 @@ reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = flash_start; -flash_config_size = 0x00001000; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; -vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); + itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; @@ -36,14 +27,3 @@ sdram_size = MICROPY_HW_SDRAM_SIZE; /* 32kiB stack. */ __stack_size__ = 0x8000; -_estack = __StackTop; -_sstack = __StackLimit; - -#if MICROPY_HW_SDRAM_AVAIL -_gc_heap_start = ORIGIN(m_sdram); -_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); -#else -/* Use second OCRAM bank for GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); -#endif diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld index 1fbc855fa13f5..fd58e9515396e 100644 --- a/ports/mimxrt/boards/MIMXRT1064.ld +++ b/ports/mimxrt/boards/MIMXRT1064.ld @@ -4,26 +4,18 @@ reserved_size = MICROPY_HW_FLASH_RESERVED; #endif #if MICROPY_HW_FLASH_TYPE == qspi_nor_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash -flash_start = 0x60000000; + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; #elif MICROPY_HW_FLASH_TYPE == internal -flash_start = 0x70000000; + flash_start = 0x70000000; + flash_size = MICROPY_HW_FLASH_SIZE; #else -#error Unknown MICROPY_HW_FLASH_TYPE + #error Unknown MICROPY_HW_FLASH_TYPE #endif -flash_size = MICROPY_HW_FLASH_SIZE; -flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = flash_start; -flash_config_size = 0x00001000; -ivt_start = flash_start + 0x00001000; -ivt_size = 0x00001000; -interrupts_start = flash_start + 0x00002000; -interrupts_size = 0x00000400; -text_start = flash_start + 0x00002400; -vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); -vfs_size = ((flash_end) - (vfs_start)); + itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; @@ -38,14 +30,3 @@ sdram_size = MICROPY_HW_SDRAM_SIZE; /* 24kiB stack. */ __stack_size__ = 0x6000; -_estack = __StackTop; -_sstack = __StackLimit; - -#if MICROPY_HW_SDRAM_AVAIL -_gc_heap_start = ORIGIN(m_sdram); -_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); -#else -/* Use second OCRAM bank for GC heap. */ -_gc_heap_start = ORIGIN(m_ocrm); -_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); -#endif diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk index ceb1e9796e01b..78af44a6733f1 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk @@ -9,6 +9,7 @@ MICROPY_HW_FLASH_SIZE = 0x4000000 # 64MB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.mk b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.mk index 135c43257c95e..8eb464b19ae8f 100644 --- a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.mk +++ b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.mk @@ -7,6 +7,8 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash MICROPY_HW_FLASH_SIZE = 0x200000 # 2MB MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB +MICROPY_BOOT_BUFFER_SIZE = (32 * 1024) + CFLAGS += -DMICROPY_HW_FLASH_DQS=kFlexSPIReadSampleClk_LoopbackInternally SRC_C += \ diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk index 2312d11311e50..695f815156470 100644 --- a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk @@ -9,6 +9,7 @@ MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk index 4482c629f7dcc..98cb385140c57 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk @@ -7,5 +7,7 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash MICROPY_HW_FLASH_SIZE = 0x200000 # 2MB MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) + deploy: $(BUILD)/firmware.hex teensy_loader_cli --mcu=imxrt1062 -v -w $< diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk index 601a2cfe8606c..62b1ebf2b142d 100755 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk @@ -7,6 +7,7 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB +MICROPY_BOOT_BUFFER_SIZE = (64 * 1024) MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld index fbc99da3ddb0e..d3095b7190f41 100644 --- a/ports/mimxrt/boards/common.ld +++ b/ports/mimxrt/boards/common.ld @@ -1,7 +1,7 @@ /* ** ################################################################### ** Linker script inspired by NXP linker script for MIMXRT10xx -** +** ** Copyright for original linker script: ** Copyright 2016 Freescale Semiconductor, Inc. ** Copyright 2016-2018 NXP @@ -19,33 +19,87 @@ ** ################################################################### */ +#include BOARD_LINKER_SCRIPT_H + /* Entry Point */ ENTRY(Reset_Handler) + +#if defined MICROPY_HW_FLASH_RESERVED + /* Reserved Area + * Users can create a reserved area at the end of the flash memory via + * 'reserved_size' variable. The size of the reserved area should be a multiple + * of the sector size of the flash memory! + */ + reserved_size = MICROPY_HW_FLASH_RESERVED; + flash_end = flash_start + (flash_size - reserved_size); +#else + reserved_size = 0; + flash_end = flash_start + flash_size; +#endif + +/* Flash configuration is physically used only in non-bootloader builds. + * For bootloader builds this section will be NOLOAD since information is already present in flash memory through bootloader binary. + */ +flash_config_start = DEFINED(flash_config_start) ? flash_config_start : flash_start; +flash_config_size = DEFINED(flash_config_size) ? flash_config_size : 0x00001000; + +mboot_start = flash_config_start; +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + mboot_size = MICROPY_HW_FLASH_FIRMWARE_START_ADDR - (flash_config_start - flash_start); +#elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash + mboot_size = MICROPY_HW_FLASH_FIRMWARE_START_ADDR - (flash_config_start - flash_start); +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif +firmware_start = mboot_start + mboot_size; +firmware_size = flash_end - firmware_start; + +ivt_start = flash_config_start + flash_config_size; +ivt_size = 0x00001000; +fw_header_start = firmware_start; +fw_header_size = 0x00000400; +interrupts_start = (fw_header_start + fw_header_size); + +interrupts_size = 0x00000400; +text_start = (interrupts_start + interrupts_size); + +/* VFS starts at fixed offset of 0x0010'0000 from flash_start */ +vfs_start = DEFINED(vfs_start) ? vfs_start : flash_start + 0x00100000; +text_size = ((vfs_start) - (text_start)); +vfs_size = flash_end - vfs_start; + +_estack = __StackTop; +_sstack = __StackLimit; + +#if MICROPY_HW_SDRAM_AVAIL +_gc_heap_start = ORIGIN(m_sdram); +_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); +#else +/* Use second OCRAM bank for GC heap. */ +_gc_heap_start = ORIGIN(m_ocrm); +_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); +#endif + + HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; -/* Reserved Area - * Users can create a reserved area at the end of the flash memory via - * 'reserved_size' variable. The size of the reserved area should be a multiple - * of the sector size of the flash memory! - */ -reserved_size = DEFINED(reserved_size) ? reserved_size : 0k; /* Specify the memory areas */ MEMORY { - m_flash_config (RX) : ORIGIN = flash_config_start, LENGTH = flash_config_size - m_ivt (RX) : ORIGIN = ivt_start, LENGTH = ivt_size + m_mboot (RX) : ORIGIN = flash_config_start, LENGTH = mboot_size + /* --- */ + m_fw_header (RX) : ORIGIN = fw_header_start, LENGTH = fw_header_size m_interrupts (RX) : ORIGIN = interrupts_start, LENGTH = interrupts_size m_text (RX) : ORIGIN = text_start, LENGTH = text_size m_vfs (RX) : ORIGIN = vfs_start, LENGTH = vfs_size /* Teensy uses the last bit of flash for recovery. */ - m_reserved (RX) : ORIGIN = (vfs_start + vfs_size), LENGTH = reserved_size + m_reserved (RX) : ORIGIN = (vfs_start + vfs_size), LENGTH = reserved_size m_itcm (RX) : ORIGIN = itcm_start, LENGTH = itcm_size m_dtcm (RW) : ORIGIN = dtcm_start, LENGTH = dtcm_size m_ocrm (RW) : ORIGIN = ocrm_start, LENGTH = ocrm_size - #if MICROPY_HW_SDRAM_AVAIL m_sdram (RX) : ORIGIN = sdram_start, LENGTH = sdram_size #endif @@ -55,30 +109,35 @@ MEMORY SECTIONS { __flash_start = flash_start; + __vfs_start = ORIGIN(m_vfs); + __vfs_end = __vfs_start + LENGTH(m_vfs); #if MICROPY_HW_SDRAM_AVAIL __sdram_start = sdram_start; #endif - __vfs_start = ORIGIN(m_vfs); - __vfs_end = __vfs_start + LENGTH(m_vfs); - - .flash_config : + + .mboot : { + FILL(0x00); . = ALIGN(4); __FLASH_BASE = .; KEEP(* (.boot_hdr.conf)) /* flash config section */ - . = ALIGN(4); - } > m_flash_config - - ivt_begin = ORIGIN(m_flash_config) + LENGTH(m_flash_config); - - .ivt : AT(ivt_begin) - { - . = ALIGN(4); + . = ORIGIN(m_mboot) + flash_config_size; KEEP(* (.boot_hdr.ivt)) /* ivt section */ KEEP(* (.boot_hdr.boot_data)) /* boot section */ KEEP(* (.boot_hdr.dcd_data)) /* dcd section */ + . = ORIGIN(m_mboot) + LENGTH(m_mboot) - 1; + BYTE(0x00) + } > m_mboot + + . = ORIGIN(m_fw_header); + .fw_header : + { + FILL(0x00); . = ALIGN(4); - } > m_ivt + KEEP(* (.fw_header)) + . = ORIGIN(m_fw_header) + LENGTH(m_fw_header) - 1; + BYTE(0x00) + } > m_fw_header /* The startup code goes first into internal RAM */ .interrupts : @@ -176,8 +235,17 @@ SECTIONS KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); } > m_text - + __etext = .; /* define a global symbol at end of code */ + + .no_init : AT(__etext) + { + __no_init_ram_begin = .; + KEEP(*(._bl_command*)) + __no_init_ram_end = .; + } > m_dtcm + + . = __etext + (__no_init_ram_end - __no_init_ram_begin); __DATA_ROM = .; /* Symbol is used by startup for data initialization */ .data : AT(__DATA_ROM) @@ -205,7 +273,7 @@ SECTIONS *(.text*) . = ALIGN(4); __ram_function_end__ = .; - } > m_itcm + } > m_itcm __NDATA_ROM = __DATA_ROM + (__ram_function_end__ - __data_start__); .ncache.init : AT(__NDATA_ROM) diff --git a/ports/mimxrt/boards/make-pins_new.py b/ports/mimxrt/boards/make-pins_new.py new file mode 100644 index 0000000000000..88a3d5f72dcf3 --- /dev/null +++ b/ports/mimxrt/boards/make-pins_new.py @@ -0,0 +1,433 @@ +#!/usr/bin/env python +"""Creates the pin file for the MIMXRT10xx.""" + +import argparse +import csv +import re +import warnings + +""" +typedef struct gpio_mux_info_t_ { + uint16_t:1 available; # `1` if Pad supports peripheral function + uint16_t:5 mux_mode; # Alternate function index - e.g. 4 for AF4 + uint16_t:4 instance_idx; # Instance number - e.g. `1` for LPSPI1 + uint16_t:6 io; + uint16_t misc; + uint32_t mux_reg; + uint32_t config_reg; +} gpio_mux_info_t; + +typedef struct adc_mux_info_t_ { + uint32_t placeholder; +} adc_mux_info_t; + +typedef struct acmp_mux_info_t_ { + uint32_t placeholder; +} acmp_mux_info_t; + +// Todo: Make mux array dynamic dependent on actually available alternate functions of chip + +typedef struct pin_config_t_ { + gpio_mux_info_t gpio_mux[9]; + adc_mux_info_t adc_mux; + acmp_mux_info_t acmp_mux; +} +""" + +""" +ENET +FLEXIO +FLEXPWM +FLEXSPI +GPIO +GPT +KPP +LPSPI +LPUART +MQS +PIT +SAI +SPDIF +TMR +USB +--- +ADC +ACMP + +""" + +""" +- Erzeugen von separaten mux konfigurationen für ADC und ACMP + - vor allem bei ACMP muss die Kombination von ACMP_IN und ACMP_OUT auf einem GPIO berücksichtigt werden +- Zusammenführung von geparsten informaiton aus der iomux und dem csv. IM CSV müsste igentlich nur infos für ADC und ACMP stehen! +- Eventuell könnte mux und config reg auf weniger Speicherplatz getrimmt werden wenn: + - lookup bei wenigen basisadressen mit index + - offset in 16/8bit mit Speichern der Basis +- Speichern von inputRegister inputDaisy in der mux config // Ausgabe +- besser gekapselter pretty print +- zusammenfügen des parsens von af.csv und iomux um direkt "volle" Pin Objekte zu erzeugen +- mux array abhängig von gewünschten/unterstützten mux modes//AFs -> einbauen für code generierung +- prüfung einbauen ob gleiches peripheral bei einem gpio mehrer mux mides belegt (ACMP bekannte ausnahme die gesondert behandelt werden muss) +- herausfindne wie groß die pin datentypen derzeit sind +""" + + +class PinAf(object): + def __init__(self, **kwargs): + self.peripheral = kwargs.get("peripheral", "") + # mux_mode + mux_mode_temp = kwargs.get("muxMode", "") + mux_mode_temp = mux_mode_temp.strip("U") # Remove unsigned specifier + self.mux_mode = int(mux_mode_temp, base=16) # Create int from hex string + # + self.instance = kwargs.get("instance", "") + self.instance_number = kwargs.get("instance_number", "") + # + self.pin_function = kwargs.get("pin_function", "") + self.mux_register = kwargs.get("muxRegister", "") + self.input_register = kwargs.get("inputRegister", "") + # input_daisy + input_daisy_temp = kwargs.get("inputDaisy", "") + input_daisy_temp = input_daisy_temp.strip("U") # Remove unsigned specifier + self.input_daisy = int(input_daisy_temp, base=16) # Create int from hex string + # + self.config_register = kwargs.get("configRegister", "") + + def __repr__(self): + return f"[{self.mux_mode}] {self.peripheral:10} {self.pin_function}" + + +class PinNew(object): + def __init__(self, pad): + self.pad = pad + self.afs = dict() + + def add_af(self, af): + if af.peripheral in self.afs: + warnings.warn(f"{self.pad} already contains AF for {af.peripheral}!") + self.afs[af.peripheral] = af + + def __hash__(self): + return hash(self.pad) + + def __eq__(self, other): + if hash(other) == hash(self): + return True + else: + return False + + def __lt__(self, other): + return self.pad < other.pad + + def __repr__(self): + return self.pad + + +class Pin(object): + af_pattern = ( + r"(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*)" + ) + + def __init__(self, pad, afs, alt_name=""): + self.pad = pad + self.alt_name = alt_name + + # Split alternate function into: + # FLEXPWM2_PWM1_A + # |________|______| + # | |----> PWM1_A + # |------------> FLEXPWM2 + # |______|_| + # FLEXPWM <------| | + # 2 <----------------| + self.afs = dict() + pattern = re.compile(self.af_pattern) + # + for i, af in enumerate(afs): + match = pattern.match(af) + if match: + af_dict = match.groupdict() + af_dict["af_idx"] = i + self.afs[match.group("peripheral")] = af_dict + + def __hash__(self): + return hash(self.pad) + + def __eq__(self, other): + if hash(other) == hash(self): + return True + else: + return False + + def __lt__(self, other): + return self.pad < other.pad + + def __str__(self): + # Get GPIO info + gpio_af = self.afs["GPIO"] + return f"{self.pad} ({self.alt_name}) - {gpio_af['instance']} {gpio_af['pin_function']}" + + def __repr__(self): + return self.pad + + +def parse_mux_files(mux_file, user_mux_file): + pins_dict = dict() # {"pad": Pin} + + # Parse mux file and generate Pin objects from it + regexes = [ + r"IOMUXC_(?PGPIO_SD_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_EMC_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_SD_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + ] + + with open(mux_file, "r") as mux_file_: + input_str = mux_file_.read() + + # Create iomux configuration tree + # + # From: + # #define IOMUXC_GPIO_AD_B0_00_GPT1_COMPARE1 0x401F80BCU, 0x7U, 0, 0, 0x401F8230U + # #define IOMUXC_GPIO_EMC_41_SPDIF_IN 0x401F80B8U, 0x2U, 0x401F8488U, 0x1U, 0x401F822CU + # + # Generate: + # { + # "GPIO_AD_B0_00": { + # 'pad': 'GPIO_AD_B0_00', + # 'instance': 'GPT1', + # 'peripheral': 'GPT', + # 'instance_number': '1', + # 'pin_function': 'COMPARE1', + # 'muxRegister': '0x401F80BCU', + # 'muxMode': '0x7U', + # 'inputRegister': '0', + # 'inputDaisy': '0', + # 'configRegister': '0x401F8230U' + # } + # } + + for regex in regexes: + matches = re.finditer(regex, input_str, re.MULTILINE) + + for match in matches: + pin_af = PinAf(**match.groupdict()) + + if match.group("pad") not in pins_dict: + pins_dict[match.group("pad")] = PinNew(match.group("pad")) + + pins_dict[match.group("pad")].add_af(pin_af) + + print(len(pins_dict)) + print(pins_dict["GPIO_AD_B1_01"]) + for af in pins_dict["GPIO_AD_B1_01"].afs: + print("\t" + str(af)) + + # Parse user mux file and enricht pin objets with more information + # Return list of pins + pass + + +def parse_af_file(af_file, pad_col, af_start_col): + af_end_col = af_start_col + 12 + available_pins = list() + available_afs = set() + + with open(af_file, "r") as csvfile: + _available_pins = set() + rows = csv.reader(csvfile) + header = next(rows) + for row in rows: + _available_pins.add(Pin(row[pad_col], row[af_start_col:af_end_col])) + + # Parse alternate functions + for af_idx, af in enumerate(row[af_start_col:af_end_col]): + match = re.match(Pin.af_pattern, af) + if match: + available_afs.add(match.group("peripheral")) + available_pins = list(_available_pins) + available_pins.sort() + + return {available_pin.pad: available_pin for available_pin in available_pins}, list( + available_afs + ) + + +def parse_iomux_file(iomux_file): + iomux_pin_configs = dict() + regexes = [ + r"IOMUXC_(?PGPIO_SD_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_EMC_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_B\d_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_SD_\d\d)_(?P(?P[a-zA-Z]+)(?P\d?))\_?(?P\w*) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + ] + + with open(iomux_file, "r") as iomuxfile: + input_str = iomuxfile.read() + + # Create iomux configuration tree + # + # From: + # #define IOMUXC_GPIO_AD_B0_00_GPT1_COMPARE1 0x401F80BCU, 0x7U, 0, 0, 0x401F8230U + # + # Generate: + # { + # "GPIO_AD_B0_00": { + # 'pad': 'GPIO_AD_B0_00', + # 'instance': 'GPT1', + # 'peripheral': 'GPT', + # 'instance_number': '1', + # 'pin_function': 'COMPARE1', + # 'muxRegister': '0x401F80BCU', + # 'muxMode': '0x7U', + # 'inputRegister': '0', + # 'inputDaisy': '0', + # 'configRegister': '0x401F8230U' + # } + # } + + for regex in regexes: + matches = re.finditer(regex, input_str, re.MULTILINE) + + for match in matches: + if match: + iomux_pin_configs[match.group("pad")] = match.groupdict() + return iomux_pin_configs + + +def parse_board_pins_file(board_file): + board_pins = dict() + with open(board_file, "r") as csvfile: + rows = csv.reader(csvfile) + for row in rows: + if len(row) == 0 or row[0].startswith("#"): + # Skip empty lines, and lines starting with "#" + continue + if len(row) != 2: + raise ValueError("Expecting two entries in a row") + + # Todo: Add error when pin is found multiple times + board_pins[row[1]] = row[0] + + # Return dict with {pad: alt_name} + return board_pins + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file", + ) + parser.add_argument( + "-a", + "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="mimxrt1021_af.csv", + ) + parser.add_argument( + "-i", + "--iomux", + dest="iomux_filename", + help="Specifies the fsl_iomuxc.h file for the chip", + default="fsl_iomuxc.h", + ) + parser.add_argument( + "-b", + "--board", + dest="board_filename", + help="Specifies the board file", + default="MIMXRT1020_EVK/pins.csv", + ) + parser.add_argument( + "-p", + "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="mimxrt_prefix.c", + ) + parser.add_argument( + "-r", + "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h", + ) + + # test code + args = parser.parse_args( + [ + "-a=/home/philipp/Projects/micropython/micropython/ports/mimxrt/boards/MIMXRT1064_af.csv", + "-i=/home/philipp/Projects/micropython/micropython/lib/nxp_driver/sdk/devices/MIMXRT1021/drivers/fsl_iomuxc.h", + ] + ) + # + + parse_mux_files(args.iomux_filename, args.af_filename) + + """ + available_pins, available_afs = parse_af_file(args.af_filename, 0, 1) + iomux_configs = parse_iomux_file(args.iomux_filename) + board_pins = parse_board_pins_file(args.board_filename) + # + available_afs = [ + "ENET", + "FLEXIO", + "FLEXPWM", + "FLEXSPI", + "GPIO", + "GPT", + "KPP", + "LPSPI", + "LPUART", + "MQS", + "PIT", + "SAI", + "SPDIF", + "TMR", + "USB", + "ADC", + ] + # + pins_to_generate = list() + for pad, alt_name in board_pins.items(): + pin = available_pins[pad] + pin.alt_name = alt_name + pins_to_generate.append(pin) + # + def print_pin_config(pin, indent="", end=","): + print(indent + "[" + pin.pad + "] " + "=" + " {") + for alt_fn in available_afs[:-1]: + if alt_fn in pin.afs: + print((indent * 2) + "[" + alt_fn + "]" + " = " + f"GPIO_MUX(1U, {pin.afs[alt_fn]['af_idx']}, {pin.afs[alt_fn]['instance_number']}, {pin.afs['GPIO']['pin_function'].lstrip('IO')}, 0U, {iomux_configs[pin.pad]['muxRegister']}, {iomux_configs[pin.pad]['configRegister']}), ") + else: + print((indent * 2) + "[" + alt_fn + "]" + " = " + f"GPIO_MUX(0U, 0U, 0U, 0U, 0U, 0U, 0U), ") + + if available_afs[-1] in pin.afs: + print((indent * 2) + "[" + available_afs[-1] + "]" + " = " + f"GPIO_MUX(1U, {pin.afs[available_afs[-1]]['af_idx']}, {pin.afs[available_afs[-1]]['instance_number']}, {pin.afs['GPIO']['pin_function'].lstrip('IO')}, 0U, {iomux_configs[pin.pad]['muxRegister']}, {iomux_configs[pin.pad]['configRegister']}), ") + else: + print((indent * 2) + "[" + available_afs[-1] + "]" + " = " + f"GPIO_MUX(0U, 0U, 0U, 0U, 0U, 0U, 0U), ") + + print(indent + "}" + end) + + print("pinconfigs = ") + print("{") + for pin in pins_to_generate[:-1]: + print_pin_config(pin, indent=" ") + print_pin_config(pins_to_generate[-1], indent=" ", end="") + print("};") + """ + + +# .available=1U, .mux_mode=10, .instance_idx=, .io=, .misc=, .mux_reg=, .config_reg= + + +if __name__ == "__main__": + main() diff --git a/ports/mimxrt/hal/flexspi_flash_config.h b/ports/mimxrt/hal/flexspi_flash_config.h index 3c21eb609a77c..0198d8d26ccce 100644 --- a/ports/mimxrt/hal/flexspi_flash_config.h +++ b/ports/mimxrt/hal/flexspi_flash_config.h @@ -222,6 +222,7 @@ typedef struct _FlexSPIConfig #define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 #define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 #define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 +#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 13 #define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 #define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.c b/ports/mimxrt/hal/flexspi_hyper_flash.c index c7b41658a4988..20c7fb0efec43 100644 --- a/ports/mimxrt/hal/flexspi_hyper_flash.c +++ b/ports/mimxrt/hal/flexspi_hyper_flash.c @@ -175,6 +175,11 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { return status; } +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions"))); +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) { + return flexspi_nor_flash_erase_sector(base, address); // HyperFlash does not support block erase! +} + status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) { status_t status; diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h index dbd028fd6f718..b40fe8d9fe506 100644 --- a/ports/mimxrt/hal/flexspi_hyper_flash.h +++ b/ports/mimxrt/hal/flexspi_hyper_flash.h @@ -36,6 +36,7 @@ extern flexspi_nor_config_t qspiflash_config; status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base); void flexspi_nor_update_lut(void); status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size); static inline uint32_t flexspi_get_frequency(void) { diff --git a/ports/mimxrt/hal/flexspi_nor_flash.c b/ports/mimxrt/hal/flexspi_nor_flash.c index 8c04150d12738..556ad3c72c852 100644 --- a/ports/mimxrt/hal/flexspi_nor_flash.c +++ b/ports/mimxrt/hal/flexspi_nor_flash.c @@ -165,6 +165,37 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { return status; } +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions"))); +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) { + status_t status; + flexspi_transfer_t flashXfer; + + /* Write enable */ + status = flexspi_nor_write_enable(base, address); + + if (status != kStatus_Success) { + return status; + } + + /* Erase sector */ + flashXfer.deviceAddress = address; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK; + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) { + return status; + } + + status = flexspi_nor_wait_bus_busy(base); + + flexspi_nor_reset(base); + + return status; +} + status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) { status_t status; diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h index f8c31488a9883..d4f8445b66469 100644 --- a/ports/mimxrt/hal/flexspi_nor_flash.h +++ b/ports/mimxrt/hal/flexspi_nor_flash.h @@ -36,6 +36,7 @@ extern flexspi_nor_config_t qspiflash_config; status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId); void flexspi_nor_update_lut(void); status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); +status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size); static inline uint32_t flexspi_get_frequency(void) { diff --git a/ports/mimxrt/hal/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c index 469a584b877a4..a6bbd624ed534 100644 --- a/ports/mimxrt/hal/qspi_nor_flash_config.c +++ b/ports/mimxrt/hal/qspi_nor_flash_config.c @@ -129,11 +129,17 @@ const flexspi_nor_config_t qspiflash_config = { FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 13 Erase Block (32k) -> 13 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x52, RADDR_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler }, }, .pageSize = 256u, .sectorSize = 4u * 1024u, - .blockSize = 64u * 1024u, + .blockSize = 32u * 1024u, .isUniformBlockSize = false, // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, }; diff --git a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S index 8fe061103388b..a0ad99fac97a2 100644 --- a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S +++ b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S @@ -51,13 +51,13 @@ Reset_Handler: /* Loop to copy data from read only memory to RAM. The ranges * of copy from/to are specified by following symbols evaluated in * linker script. - * __etext: End of code section, i.e., begin of data sections to copy from. + * __DATA_ROM: End of code section, i.e., begin of data sections to copy from. * __data_start__/__data_end__: RAM address range that data should be * __noncachedata_start__/__noncachedata_end__ : none cachable region * __ram_function_start__/__ram_function_end__ : ramfunction region * copied to. Both must be aligned to 4 bytes boundary. */ - ldr r1, =__etext + ldr r1, =__DATA_ROM ldr r2, =__data_start__ ldr r3, =__data_end__ diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 82e07868a1d41..87f21f9c68ed3 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -38,6 +38,7 @@ #include "led.h" #include "pendsv.h" #include "modmachine.h" +#include "fw_header.h" #if MICROPY_PY_LWIP #include "lwip/init.h" @@ -48,6 +49,13 @@ extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end; +extern void Reset_Handler(void); + +__attribute__((section(".fw_header"))) const fw_header_t fw_header = { + .magic = FW_HEADER_MAGIC, + .entry_addr = (uintptr_t)Reset_Handler, +}; + void board_init(void); int main(void) { diff --git a/ports/mimxrt/mboot.mk b/ports/mimxrt/mboot.mk new file mode 100644 index 0000000000000..c6744e4a346fa --- /dev/null +++ b/ports/mimxrt/mboot.mk @@ -0,0 +1,245 @@ +BUILD_BL ?= build-$(BOARD)/mboot +LD_FILES_BL = $(BOOTLOADER_DIR)/boards/common.ld + +INC_BL += \ + -I$(BOARD_DIR) \ + -I$(BOOTLOADER_DIR) \ + -I$(BOOTLOADER_DIR)/boards \ + -I$(BOOTLOADER_DIR)/hal \ + -I$(BOOTLOADER_DIR)/shared \ + -I$(TOP)/$(MCU_DIR) \ + -I$(TOP)/$(MCU_DIR)/drivers \ + -I$(TOP)/lib/cmsis/inc \ + -I$(TOP)/lib/tinyusb/hw \ + -I$(TOP)/lib/tinyusb/src \ + -I. \ + -Ihal + +SRC_HAL_IMX_C_BL += \ + $(MCU_DIR)/drivers/fsl_cache.c \ + $(MCU_DIR)/drivers/fsl_clock.c \ + $(MCU_DIR)/drivers/fsl_common.c \ + $(MCU_DIR)/drivers/fsl_flexram.c \ + $(MCU_DIR)/drivers/fsl_flexspi.c \ + $(MCU_DIR)/drivers/fsl_gpt.c \ + $(MCU_DIR)/system_$(MCU_SERIES).c + +SRC_TINYUSB_C_BL += \ + lib/tinyusb/src/class/dfu/dfu_device.c \ + lib/tinyusb/src/common/tusb_fifo.c \ + lib/tinyusb/src/device/usbd.c \ + lib/tinyusb/src/device/usbd_control.c \ + lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c \ + lib/tinyusb/src/tusb.c + +SRC_C_BL += \ + $(BOOTLOADER_DIR)/boards/flexspi_nor_mboot.c \ + $(BOOTLOADER_DIR)/main.c \ + $(BOOTLOADER_DIR)/mboot_buffer.c \ + $(BOOTLOADER_DIR)/mboot_dfu.c \ + $(BOOTLOADER_DIR)/mboot_upgrade.c \ + $(BOOTLOADER_DIR)/mboot_utils.c \ + $(BOOTLOADER_DIR)/mboot_validate.c \ + $(BOOTLOADER_DIR)/tusb_port.c \ + $(SRC_HAL_IMX_C_BL) \ + $(SRC_TINYUSB_C_BL) \ + boards/$(MCU_SERIES)_clock_config.c \ + flash.c + +# Set default values if optional variables not defined +ifndef MICROPY_HW_BOARD_FLASH_FILES + MICROPY_HW_BOARD_FLASH_FILES = 0 +endif + +# Add sources for respective board flash type +ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash qspi_hyper_flash)) + # Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively + SRC_C_BL += hal/flexspi_$(subst qspi_,,$(MICROPY_HW_FLASH_TYPE)).c + # + # Add custom (board specific) or default configuration + ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1) + SRC_C_BL += $(BOARD_DIR)/$(MICROPY_HW_FLASH_TYPE)_config.c + else + SRC_C_BL += hal/$(MICROPY_HW_FLASH_TYPE)_config.c + endif +else + $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) +endif + +SRC_SS_BL = \ + $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S \ + $(BOOTLOADER_DIR)/hal/resethandler_mboot_MIMXRT10xx_RAM.S + +# Flags +CFLAGS_DEFINES_BL += \ + -DMICROPY_BOOT_BUFFER_SIZE='$(MICROPY_BOOT_BUFFER_SIZE)' + +# Tune for Debugging or Optimization +ifeq ($(DEBUG),1) +CFLAGS_DEBUG_BL += -Og -ggdb -DNDEBUG +else +CFLAGS_DEBUG_BL += -Os -DNDEBUG +endif + +CFLAGS_BL += \ + $(CFLAGS_DEBUG_BL) \ + $(CFLAGS_DEFINES_BL) \ + $(INC_BL) \ + -D__START=main \ + -D__STARTUP_CLEAR_BSS \ + -D__STARTUP_INITIALIZE_RAMFUNCTION \ + -DBOARD_$(BOARD) \ + -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX \ + -DCLOCK_CONFIG_H='' \ + -DCPU_$(MCU_SERIES) \ + -DCPU_$(MCU_VARIANT) \ + -DCPU_HEADER_H='<$(MCU_SERIES).h>' \ + -DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \ + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DXIP_BOOT_HEADER_ENABLE=1 \ + -DXIP_EXTERNAL_FLASH=1 \ + -fdata-sections \ + -ffunction-sections \ + -mcpu=cortex-m7 \ + -mtune=cortex-m7 \ + -nostdlib \ + -std=c99 \ + -Wall \ + -Wdouble-promotion \ + -Werror \ + -Wfloat-conversion \ + -Wno-error=unused-parameter + +# Configure respective board flash type +ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash qspi_hyper_flash)) + # Add hal/flexspi_nor_flash.h or hal/flexspi_hyper_flash.h respectively + CFLAGS_BL += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_$(subst qspi_,,$(MICROPY_HW_FLASH_TYPE)).h\" + # + # Add custom (board specific) or default configuration + ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1) + CFLAGS_BL += -DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_flash_config.h\" + else + CFLAGS_BL += -DBOARD_FLASH_CONFIG_HEADER_H=\"hal/flexspi_flash_config.h\" + endif +else + $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) +endif + +LDFLAGS_BL += \ + -mcpu=cortex-m7 \ + -mtune=cortex-m7 \ + -specs=nano.specs \ + -specs=nosys.specs \ + -Wl,--cref \ + -Wl,--gc-sections \ + -Wl,--print-memory-usage \ + -Wl,-Map=$@.map \ + -Wl,-N + +# LDDEFINES_BL are used for link time adaptation of linker scripts, utilizing +# the C preprocessor. Therefore keep LDDEFINES_BL separated from LDFLAGS! + +LDDEFINES_BL = \ + -DMICROPY_HW_FLASH_TYPE=$(MICROPY_HW_FLASH_TYPE) \ + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DBOARD_LINKER_SCRIPT_H=\"$(MCU_SERIES).ld\" + +# Start of firmware is dependent on board flash type. Bootloader requires at least 32kB. +# Firmware start has to be aligned to sector size to allow erase of firmware without affecting the bootloader. +# Sector size is different between QPSI flash (4kB) and HyperFlash (256kB) devices! +ifeq ($(MICROPY_HW_FLASH_TYPE),qspi_nor_flash) + LDDEFINES_BL += -DMICROPY_HW_FLASH_FIRMWARE_START_ADDR=0x00008000 +else ifeq ($(MICROPY_HW_FLASH_TYPE),qspi_hyper_flash) + LDDEFINES_BL += -DMICROPY_HW_FLASH_FIRMWARE_START_ADDR=0x00040000 +else + $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) +endif + +LIBS_BL = $(shell $(CC) $(CFLAGS_BL) -print-libgcc-file-name) +OBJ_BL += $(addprefix $(BUILD_BL)/, $(SRC_C_BL:.c=.o)) +OBJ_BL += $(addprefix $(BUILD_BL)/, $(SRC_SS_BL:.S=.o)) + +define compile_c_bl +$(ECHO) "CC $<" +$(Q)$(CC) $(CFLAGS_BL) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +# Targets +mboot_all: $(BUILD_BL)/mboot.bin $(BUILD_BL)/mboot.hex $(BUILD_BL)/mboot.hex mboot_info +.PHONY: mboot_all + +mboot_clean: + $(RM) -rf $(BUILD_BL) +.PHONY: mboot_clean + +OBJ_DIRS_BL = $(sort $(dir $(OBJ_BL))) +$(OBJ_BL): | $(OBJ_DIRS_BL) +$(OBJ_DIRS_BL): + $(MKDIR) -p $@ + +vpath %.S . $(TOP) +$(BUILD_BL)/%.o: %.S + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS_BL) -c -o $@ $< + +vpath %.s . $(TOP) +$(BUILD_BL)/%.o: %.s + $(ECHO) "AS $<" + $(Q)$(AS) -o $@ $< + +vpath %.c . $(TOP) +$(BUILD_BL)/%.o: %.c + $(call compile_c_bl) + +$(BUILD_BL)/%.pp: %.c + $(ECHO) "PreProcess $<" + $(Q)$(CPP) $(CFLAGS_BL) -Wp,-C,-dD,-dI -o $@ $< + +$(BUILD_BL)/mboot.elf: $(OBJ_BL) + $(ECHO) $(LINK_MSG) + $(ECHO) "PREPROCESS LINK $@" + $(Q)$(CC) -E -x c $(LDDEFINES_BL) $(LD_FILES_BL) | grep -v '^#' > $(BUILD_BL)/link.ld + $(ECHO) "LINK $@" + $(Q)$(CC) $(addprefix -T, $(BUILD_BL)/link.ld) $(LDFLAGS_BL) -o $@ $^ $(LIBS_BL) + +$(BUILD_BL)/mboot.bin: $(BUILD_BL)/mboot.elf + $(Q)$(OBJCOPY) -O binary $^ $@ + +$(BUILD_BL)/mboot.hex: $(BUILD_BL)/mboot.elf + $(Q)$(OBJCOPY) -O ihex $^ $@ + +mboot_info: $(BUILD_BL)/mboot.elf $(BUILD_BL)/mboot.bin + $(ECHO) "Bootloader Info" + $(ECHO) "Download buffer $(MICROPY_BOOT_BUFFER_SIZE)" + $(Q)$(SIZE) $(BUILD_BL)/mboot.elf + $(Q)$(SIZE) $(BUILD_BL)/mboot.bin --target binary + +BL_JLINK_COMMANDER_SCRIPT = $(BUILD_BL)/script_mboot.jlink + +ifdef JLINK_IP +BL_JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP) +else +BL_JLINK_CONNECTION_SETTINGS = -USB +endif + +mboot_deploy_jlink: $(BUILD_BL)/mboot.hex + $(Q)$(TOUCH) $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "ExitOnError 1" > $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "speed auto" >> $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "r" >> $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "st" >> $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "loadfile \"$(realpath $(BUILD_BL)/mboot.hex)\"" >> $(BL_JLINK_COMMANDER_SCRIPT) + $(ECHO) "qc" >> $(BL_JLINK_COMMANDER_SCRIPT) + $(JLINK_PATH)JLinkExe -device $(MCU_VARIANT) -if SWD $(BL_JLINK_CONNECTION_SETTINGS) -CommanderScript $(BL_JLINK_COMMANDER_SCRIPT) + + + +.PHONY: mboot_info +.PHONY: mboot_deploy_jlink diff --git a/ports/mimxrt/mboot/README.md b/ports/mimxrt/mboot/README.md new file mode 100644 index 0000000000000..d8ec8662cc348 --- /dev/null +++ b/ports/mimxrt/mboot/README.md @@ -0,0 +1,36 @@ +# Memory Layout + +## QSPI +``` + +--------------+ +0x6000'0000 | mboot | + | | + +--------------+ +0x6000'8000 | firmware | + | | + | | + +--------------+ +0x6010'0000 | VFS | + | | + / ... / + | | + +--------------+ +``` + +## HyperFlash +``` + +--------------+ +0x6000'0000 | mboot | + | | + +--------------+ +0x6004'0000 | firmware | + | | + | | + +--------------+ +0x6010'0000 | VFS | + | | + / ... / + | | + +--------------+ +``` +Since HyperFlash memory has 256k sectors the firmware has to start at a sector border. diff --git a/ports/mimxrt/mboot/boards/MIMXRT1011.ld b/ports/mimxrt/mboot/boards/MIMXRT1011.ld new file mode 100644 index 0000000000000..6d3c070a89be6 --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1011.ld @@ -0,0 +1,19 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +/* MIMXRT1011 requires different offset for flash configuration */ +flash_config_start = flash_start + 0x00000400; +flash_config_size = 0x00000C00; + +itcm_start = 0x00000000; +itcm_size = 0x00008000; /* 32KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00008000; /* 32KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00010000; /* 64KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/MIMXRT1015.ld b/ports/mimxrt/mboot/boards/MIMXRT1015.ld new file mode 100644 index 0000000000000..fe470531aa535 --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1015.ld @@ -0,0 +1,15 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +itcm_start = 0x00000000; +itcm_size = 0x00008000; /* 32KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00008000; /* 32KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00010000; /* 64KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/MIMXRT1021.ld b/ports/mimxrt/mboot/boards/MIMXRT1021.ld new file mode 100644 index 0000000000000..1eb0f0cfbd86a --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1021.ld @@ -0,0 +1,15 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +itcm_start = 0x00000000; +itcm_size = 0x00010000; /* 64KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00010000; /* 64KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00020000; /* 128KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/MIMXRT1052.ld b/ports/mimxrt/mboot/boards/MIMXRT1052.ld new file mode 100644 index 0000000000000..183a691823679 --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1052.ld @@ -0,0 +1,15 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash || MICROPY_HW_FLASH_TYPE == qspi_hyper_flash + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +itcm_start = 0x00000000; +itcm_size = 0x00020000; /* 128KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00020000; /* 128KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00040000; /* 256KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/MIMXRT1062.ld b/ports/mimxrt/mboot/boards/MIMXRT1062.ld new file mode 100644 index 0000000000000..fbc10fa41d326 --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1062.ld @@ -0,0 +1,15 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +itcm_start = 0x00000000; +itcm_size = 0x00020000; /* 128KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00020000; /* 128KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00040000; /* 256KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/MIMXRT1064.ld b/ports/mimxrt/mboot/boards/MIMXRT1064.ld new file mode 100644 index 0000000000000..efed70edd68d8 --- /dev/null +++ b/ports/mimxrt/mboot/boards/MIMXRT1064.ld @@ -0,0 +1,18 @@ +/* Memory configuration */ +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + flash_start = 0x60000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#elif MICROPY_HW_FLASH_TYPE == internal + flash_start = 0x70000000; + flash_size = MICROPY_HW_FLASH_SIZE; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +itcm_start = 0x00000000; +itcm_size = 0x00020000; /* 128KB */ +dtcm_start = 0x20000000; +dtcm_size = 0x00020000; /* 128KB */ +ocrm_start = 0x20200000; +ocrm_size = 0x00040000; /* 256KB */ +ocrm_end = (ocrm_start + ocrm_size); diff --git a/ports/mimxrt/mboot/boards/common.ld b/ports/mimxrt/mboot/boards/common.ld new file mode 100644 index 0000000000000..30b58a14b9a7d --- /dev/null +++ b/ports/mimxrt/mboot/boards/common.ld @@ -0,0 +1,314 @@ +/* +** ################################################################### +** Linker script inspired by NXP linker script for MIMXRT10xx +** +** Copyright for original linker script: +** Copyright 2016 Freescale Semiconductor, Inc. +** Copyright 2016-2018 NXP +** SPDX-License-Identifier: BSD-3-Clause +** +** http: www.nxp.com +** mail: support@nxp.com +** +** Integrated ideas from CircuitPython: +** SPDX-License-Identifier: The MIT License (MIT) +** SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft (tannewt) +** +** Copyright (c) 2021 Philipp Ebensberger +** +** ################################################################### +*/ + +#include BOARD_LINKER_SCRIPT_H + +/* Entry Point */ +ENTRY(Reset_Handler) + +#if defined MICROPY_HW_FLASH_RESERVED + /* Reserved Area + * Users can create a reserved area at the end of the flash memory via + * 'reserved_size' variable. The size of the reserved area should be a multiple + * of the sector size of the flash memory! + */ + reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); + +/* Flash configuration is physically used only in non-bootloader builds. + * For bootloader builds this section will be NOLOAD since information is already present in flash memory through bootloader binary. + */ +flash_config_start = DEFINED(flash_config_start) ? flash_config_start : flash_start; +flash_config_size = DEFINED(flash_config_size) ? flash_config_size : 0x00001000; + +#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash + firmware_start = flash_start + MICROPY_HW_FLASH_FIRMWARE_START_ADDR; +#elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash + firmware_start = flash_start + MICROPY_HW_FLASH_FIRMWARE_START_ADDR; +#else + #error Unknown MICROPY_HW_FLASH_TYPE +#endif + +ivt_start = flash_config_start + flash_config_size; +ivt_size = 0x00000400; +interrupts_start = ivt_start + ivt_size; +interrupts_size = 0x00000400; +text_start = interrupts_start + interrupts_size; +text_size = (firmware_start - text_start); + +firmware_size = flash_end - firmware_start; +mboot_flash_start = flash_start; +mboot_flash_size = firmware_start - mboot_flash_start; + +_estack = __StackTop; +_sstack = __StackLimit; + + +HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; + +/* Specify the memory areas */ +MEMORY +{ + m_flash_config (RX) : ORIGIN = flash_config_start, LENGTH = flash_config_size + m_ivt (RX) : ORIGIN = ivt_start, LENGTH = ivt_size + m_interrupts (RX) : ORIGIN = interrupts_start, LENGTH = interrupts_size + m_text (RX) : ORIGIN = text_start, LENGTH = text_size + m_firmware (RX) : ORIGIN = firmware_start, LENGTH = firmware_size + m_itcm (RX) : ORIGIN = itcm_start, LENGTH = itcm_size + m_dtcm (RW) : ORIGIN = dtcm_start, LENGTH = dtcm_size + m_ocrm (RW) : ORIGIN = ocrm_start, LENGTH = ocrm_size +} + +/* Define output sections */ +SECTIONS +{ + __flash_start = flash_start; + __flash_config_start = flash_config_start; + __firmware_start = ORIGIN(m_firmware); + __firmware_end = __firmware_start + LENGTH(m_firmware); + + .flash_config : + { + FILL(0x00); + . = ALIGN(4); + KEEP(* (.boot_hdr.conf)) /* flash config section */ + . = ORIGIN(m_flash_config) + LENGTH(m_flash_config) - 1; + BYTE(0x00) + . = ALIGN(4); + } > m_flash_config + + __FLASH_BASE = flash_config_start; + ivt_begin = ORIGIN(m_flash_config) + LENGTH(m_flash_config); + .ivt : AT(ivt_begin) + { + FILL(0x00); + __ivt_begin = .; + . = ALIGN(4); + KEEP(* (.boot_hdr.ivt)) /* ivt section */ + KEEP(* (.boot_hdr.boot_data)) /* boot section */ + KEEP(* (.boot_hdr.dcd_data)) /* dcd section */ + . = ORIGIN(m_ivt) + LENGTH(m_ivt) - 1; + BYTE(0x00) + . = ALIGN(4); + __ivt_end = .; + } > m_ivt + + __interrupts_begin = ivt_begin + LENGTH(m_ivt); + .interrupts : AT(__interrupts_begin) + { + __interrupts_begin = .; + __VECTOR_TABLE = .; + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + __interrupts_rom_end = .; + } > m_interrupts + + __VECTOR_RAM = __VECTOR_TABLE; + __RAM_VECTOR_TABLE_SIZE_BYTES = 0x0; + + __text_begin = __interrupts_begin + (__interrupts_rom_end - __interrupts_begin); + _stext = __text_begin; + .text : AT(__text_begin) + { + __text_begin = .; + . = ALIGN(4); + *(EXCLUDE_FILE(*fsl_flexspi.o) .text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + KEEP (*(.init)) + KEEP (*(.fini)) + . = ALIGN(4); + __text_rom_end = .; + } > m_text + + __extab_begin = __text_begin + (__text_rom_end - __text_begin); + .ARM.extab : AT(__extab_begin) + { + __extab_begin = .; + PROVIDE_HIDDEN (__arm_extab_start = .); + *(.ARM.extab* .gnu.linkonce.armextab.*) + PROVIDE_HIDDEN (__arm_extab_end = .); + __extab_rom_end = .; + } > m_text + + __arm_begin = __extab_begin + (__extab_rom_end - __extab_begin); + .ARM : AT(__arm_begin) + { + __exidx_begin = .; + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + __exidx_rom_end = .; + } > m_text + + __preinit_begin = __arm_begin + (__exidx_rom_end - __exidx_begin); + .preinit_array : AT(__preinit_begin) + { + __preinit_array_begin = .; + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + __preinit_array_rom_end = .; + } > m_text + + __init_array_begin = __preinit_begin + (__preinit_array_rom_end - __preinit_array_begin); + .init_array : AT(__init_array_begin) + { + __init_array_begin = .; + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + __init_array_rom_end = .; + } > m_text + + __fini_array_begin = __init_array_begin + (__init_array_rom_end - __init_array_begin); + .fini_array : AT(__fini_array_begin) + { + __fini_array_begin = .; + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + __fini_array_rom_end = .; + } > m_text + + __etext = __fini_array_begin + (__fini_array_rom_end - __fini_array_begin); + + .no_init : AT(__etext) + { + __no_init_begin = .; + KEEP(*(._bl_command*)) + __no_init_rom_end = .; + } > m_dtcm + + . = __etext + (__no_init_rom_end - __no_init_begin); + + __DATA_ROM = .; + + .data : AT(__DATA_ROM) + { + . = ALIGN(4); + __DATA_RAM = .; + __data_start__ = .; /* create a global symbol at data start */ + *(m_usb_dma_init_data) + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + KEEP(*(.jcr*)) + . = ALIGN(4); + __data_end__ = .; /* define a global symbol at data end */ + } > m_dtcm + + __RAM_FUNCTIONS_ROM = __DATA_ROM + (__data_end__ - __data_start__); + .ram_functions : AT(__RAM_FUNCTIONS_ROM) + { + . = ALIGN(4); + __ram_function_start__ = .; + *(.ram_functions*) + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + __ram_function_end__ = .; + } > m_itcm + + __NDATA_ROM = __DATA_ROM + (__ram_function_end__ - __ram_function_start__); + .ncache.init : AT(__NDATA_ROM) + { + __noncachedata_start__ = .; /* create a global symbol at ncache data start */ + *(NonCacheable.init) + . = ALIGN(4); + __noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ + } > m_dtcm + . = __noncachedata_init_end__; + .ncache : + { + *(NonCacheable) + . = ALIGN(4); + __noncachedata_end__ = .; /* define a global symbol at ncache data end */ + } > m_dtcm + + __DATA_END = __NDATA_ROM + (__noncachedata_end__ - __noncachedata_start__); + text_end = ORIGIN(m_text) + LENGTH(m_text); + ASSERT(__DATA_END <= (mboot_flash_start + mboot_flash_size), "region m_text overflowed with text and data") + + /* Uninitialized data section */ + .bss (NOLOAD): + { + /* This is used by the startup in order to initialize the .bss section */ + . = ALIGN(4); + __START_BSS = .; + __bss_start__ = .; + __bss_section_table = .; + *(m_usb_dma_noninit_data) + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + __END_BSS = .; + } > m_dtcm + + .heap (NOLOAD): + { + . = ALIGN(8); + __end__ = .; + PROVIDE(end = .); + __HeapBase = .; + . += HEAP_SIZE; + __HeapLimit = .; + __heap_limit = .; /* Add for _sbrk */ + } > m_dtcm + + .stack : + { + . = ALIGN(8); + . += STACK_SIZE; + } > m_dtcm + + .fw_buffer (NOLOAD): + { + . = ALIGN(0x400); + *(.fw_buffer); + . = ALIGN(4); + __END_FW_BUFFER = .; + } > m_ocrm + + /* Initializes stack on the end of block */ + __StackTop = ORIGIN(m_dtcm) + LENGTH(m_dtcm); + __StackLimit = __StackTop - STACK_SIZE; + PROVIDE(__stack = __StackTop); + + + boot_data_start_address = flash_config_start; + boot_data_size = __etext - flash_start; + + .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT(__StackLimit >= __HeapLimit, "region m_dtcm overflowed with stack and heap") +} + diff --git a/ports/mimxrt/mboot/boards/flexspi_nor_mboot.c b/ports/mimxrt/mboot/boards/flexspi_nor_mboot.c new file mode 100644 index 0000000000000..da5c989720c47 --- /dev/null +++ b/ports/mimxrt/mboot/boards/flexspi_nor_mboot.c @@ -0,0 +1,54 @@ +/* + * Copyright 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "flexspi_nor_mboot.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.xip_device" +#endif + +extern uint32_t __ivt_begin; +extern uint32_t boot_data_start_address; +extern uint32_t boot_data_size; +extern void Reset_Handler(); + +#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.ivt"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.ivt" +#endif +/************************************* + * IVT Data + *************************************/ +const ivt image_vector_table = { + IVT_HEADER, /* IVT Header */ + (uint32_t)&Reset_Handler, /* Image Entry Function */ + IVT_RSVD, /* Reserved = 0 */ + (uint32_t)0, /* Address where DCD information is stored */ + (uint32_t)BOOT_DATA_ADDRESS, /* Address where BOOT Data Structure is stored */ + (uint32_t)&__ivt_begin, /* Pointer to IVT Self (absolute address */ + (uint32_t)0, /* Address where CSF file is stored */ + IVT_RSVD /* Reserved = 0 */ +}; + +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.boot_data"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.boot_data" +#endif +/************************************* + * Boot Data + *************************************/ +const BOOT_DATA_T boot_data = { + (uint32_t)&boot_data_start_address, /* boot start location */ + (uint32_t)&boot_data_size, /* size */ + PLUGIN_FLAG, /* Plugin flag*/ + 0xFFFFFFFF /* empty - extra data word */ +}; +#endif diff --git a/ports/mimxrt/mboot/boards/flexspi_nor_mboot.h b/ports/mimxrt/mboot/boards/flexspi_nor_mboot.h new file mode 100644 index 0000000000000..481f97d6ba78f --- /dev/null +++ b/ports/mimxrt/mboot/boards/flexspi_nor_mboot.h @@ -0,0 +1,111 @@ +/* + * Copyright 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __FLEXSPI_NOR_MBOOT_H__ +#define __FLEXSPI_NOR_MBOOT_H__ + +#include +#include "board.h" + +/*! @name Driver version */ +/*@{*/ +/*! @brief XIP_DEVICE driver version 2.0.0. */ +#define FSL_XIP_DEVICE_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/************************************* + * IVT Data + *************************************/ +typedef struct _ivt_ { + /** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields + * (see @ref data) + */ + uint32_t hdr; + /** Absolute address of the first instruction to execute from the + * image + */ + uint32_t entry; + /** Reserved in this version of HAB: should be NULL. */ + uint32_t reserved1; + /** Absolute address of the image DCD: may be NULL. */ + uint32_t dcd; + /** Absolute address of the Boot Data: may be NULL, but not interpreted + * any further by HAB + */ + uint32_t boot_data; + /** Absolute address of the IVT.*/ + uint32_t self; + /** Absolute address of the image CSF.*/ + uint32_t csf; + /** Reserved in this version of HAB: should be zero. */ + uint32_t reserved2; +} ivt; + +#define IVT_MAJOR_VERSION 0x4 +#define IVT_MAJOR_VERSION_SHIFT 0x4 +#define IVT_MAJOR_VERSION_MASK 0xF +#define IVT_MINOR_VERSION 0x1 +#define IVT_MINOR_VERSION_SHIFT 0x0 +#define IVT_MINOR_VERSION_MASK 0xF + +#define IVT_VERSION(major, minor) \ + ((((major) & IVT_MAJOR_VERSION_MASK) << IVT_MAJOR_VERSION_SHIFT) | \ + (((minor) & IVT_MINOR_VERSION_MASK) << IVT_MINOR_VERSION_SHIFT)) + +/* IVT header */ +#define IVT_TAG_HEADER 0xD1 /**< Image Vector Table */ +#define IVT_SIZE 0x2000 +#define IVT_PAR IVT_VERSION(IVT_MAJOR_VERSION, IVT_MINOR_VERSION) +#define IVT_HEADER (IVT_TAG_HEADER | (IVT_SIZE << 8) | (IVT_PAR << 24)) + +/* Set resume entry */ +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) +extern uint32_t __Vectors[]; +extern uint32_t Image$$RW_m_config_text$$Base[]; +#define IMAGE_ENTRY_ADDRESS ((uint32_t)__Vectors) +#define FLASH_BASE ((uint32_t)Image$$RW_m_config_text$$Base) +#elif defined(__MCUXPRESSO) +extern uint32_t __Vectors[]; +extern uint32_t __boot_hdr_start__[]; +#define IMAGE_ENTRY_ADDRESS ((uint32_t)__Vectors) +#define FLASH_BASE ((uint32_t)__boot_hdr_start__) +#elif defined(__ICCARM__) +extern uint32_t __VECTOR_TABLE[]; +extern uint32_t m_boot_hdr_conf_start[]; +#define IMAGE_ENTRY_ADDRESS ((uint32_t)__VECTOR_TABLE) +#define FLASH_BASE ((uint32_t)m_boot_hdr_conf_start) +#elif defined(__GNUC__) +extern uint32_t __VECTOR_TABLE[]; +extern uint32_t __FLASH_BASE[]; +#define IMAGE_ENTRY_ADDRESS ((uint32_t)__VECTOR_TABLE) +#define FLASH_BASE ((uint32_t)__FLASH_BASE) +#endif + +#define DCD_ADDRESS dcd_data +#define BOOT_DATA_ADDRESS &boot_data +#define CSF_ADDRESS 0 +#define IVT_RSVD (uint32_t)(0x00000000) + +/************************************* + * Boot Data + *************************************/ +typedef struct _boot_data_ { + uint32_t start; /* boot start location */ + uint32_t size; /* size */ + uint32_t plugin; /* plugin flag - 1 if downloaded application is plugin */ + uint32_t placeholder; /* placehoder to make even 0x10 size */ +}BOOT_DATA_T; + +extern uint32_t mboot_flash_size; +#define FLASH_SIZE (uint32_t)&mboot_flash_size +#define PLUGIN_FLAG (uint32_t)0 + +/* External Variables */ +const BOOT_DATA_T boot_data; +extern const uint8_t dcd_data[]; + +#endif /* __FLEXSPI_NOR_MBOOT_H__ */ diff --git a/ports/mimxrt/mboot/hal/resethandler_mboot_MIMXRT10xx_RAM.S b/ports/mimxrt/mboot/hal/resethandler_mboot_MIMXRT10xx_RAM.S new file mode 100644 index 0000000000000..4c7c4e4eaaa88 --- /dev/null +++ b/ports/mimxrt/mboot/hal/resethandler_mboot_MIMXRT10xx_RAM.S @@ -0,0 +1,151 @@ + + .syntax unified + .arch armv7-m + +/* Reset Handler */ + + .thumb_func + .align 2 + .globl Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + cpsid i /* Mask interrupts */ + .equ VTOR, 0xE000ED08 + ldr r0, =VTOR + ldr r1, =__isr_vector + str r1, [r0] + ldr r2, [r1] + msr msp, r2 + +#ifndef __NO_SYSTEM_INIT + ldr r0,=SystemInit + blx r0 +#endif +/* Loop to copy data from read only memory to RAM. The ranges + * of copy from/to are specified by following symbols evaluated in + * linker script. + * __DATA_ROM: End of code section, i.e., begin of data sections to copy from. + * __data_start__/__data_end__: RAM address range that data should be + * __ocram_data_start__/__ocram_data_end__ : OCRAM region + * __ram_function_start__/__ram_function_end__ : ramfunction region + * __noncachedata_start__/__noncachedata_end__ : none cachable region + * copied to. Both must be aligned to 4 bytes boundary. */ + + ldr r1, =__DATA_ROM + ldr r2, =__data_start__ + ldr r3, =__data_end__ + +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC1 +.LC0: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC0 +.LC1: +#else /* code size implemenation */ +.LC0: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC0 +#endif + +#ifdef __STARTUP_INITIALIZE_RAMFUNCTION + ldr r2, =__ram_function_start__ + ldr r3, =__ram_function_end__ +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC_ramfunc_copy_end +.LC_ramfunc_copy_start: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC_ramfunc_copy_start +.LC_ramfunc_copy_end: +#else /* code size implemenation */ +.LC_ramfunc_copy_start: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC_ramfunc_copy_start +#endif +#endif /* __STARTUP_INITIALIZE_RAMFUNCTION */ + +#ifdef __STARTUP_INITIALIZE_NONCACHEDATA + ldr r2, =__noncachedata_start__ + ldr r3, =__noncachedata_init_end__ +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC3 +.LC2: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC2 +.LC3: +#else /* code size implemenation */ +.LC2: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC2 +#endif +/* zero inited ncache section initialization */ + ldr r3, =__noncachedata_end__ + movs r0,0 +.LC4: + cmp r2,r3 + itt lt + strlt r0,[r2],#4 + blt .LC4 +#endif /* __STARTUP_INITIALIZE_NONCACHEDATA */ + +#ifdef __STARTUP_CLEAR_BSS +/* This part of work usually is done in C library startup code. Otherwise, + * define this macro to enable it in this startup. + * + * Loop to zero out BSS section, which uses following symbols + * in linker script: + * __bss_start__: start of BSS section. Must align to 4 + * __bss_end__: end of BSS section. Must align to 4 + */ + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ + + movs r0, 0 +.LC5: + cmp r1, r2 + itt lt + strlt r0, [r1], #4 + blt .LC5 +#endif /* __STARTUP_CLEAR_BSS */ + + cpsie i /* Unmask interrupts */ +#ifndef __START +#define __START _start +#endif +#ifndef __ATOLLIC__ + ldr r0,=__START + blx r0 +#else + ldr r0,=__libc_init_array + blx r0 + ldr r0,=main + bx r0 +#endif + .pool + .size Reset_Handler, . - Reset_Handler diff --git a/ports/mimxrt/mboot/main.c b/ports/mimxrt/mboot/main.c new file mode 100644 index 0000000000000..7f6bf360c182f --- /dev/null +++ b/ports/mimxrt/mboot/main.c @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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. + * + */ + +/* + * After device is enumerated in dfu mode run the following commands + * + * To transfer firmware from host to device: + * + * $ dfu-util -D [filename] + * + * To transfer firmware from device to host: + * + * $ dfu-util -U [filename] + * + */ + +#include CPU_HEADER_H +// include fsl_clock.h BEFORE including clock configuration due to bug in NXP HAL. +#include "fsl_clock.h" +#include CLOCK_CONFIG_H +#include +#include "mboot_buffer.h" +#include "mboot_command.h" +#include "mboot_dfu.h" +#include "mboot_memory.h" +#include "mboot_validate.h" +#include "fw_header.h" + +// --------------------------------------------------------------------+ +// Type Definitions +// --------------------------------------------------------------------+ +typedef void (*firmware_entry_func)(void); + +// --------------------------------------------------------------------+ +// Local Variables +// --------------------------------------------------------------------+ +MEM_AT_SECTION("._bl_command") mboot_command_t bl_command; +const uint8_t dcd_data[] = { 0x00 }; + +// --------------------------------------------------------------------+ +// External Variables +// --------------------------------------------------------------------+ +extern uint32_t __firmware_start; // Linker symbol + +// --------------------------------------------------------------------+ +// External Function Declarations +// --------------------------------------------------------------------+ +extern void SystemInit(); + +// --------------------------------------------------------------------+ +// Local Function Declarations +// --------------------------------------------------------------------+ +static void board_init(void); +static bool reprog_request(void); +static bool valid_fw_available(void); +static inline firmware_entry_func get_entry_func(void); +static inline void fw_start(void) __attribute__ ((noreturn)); + +// --------------------------------------------------------------------+ +// Global Function Definitions +// --------------------------------------------------------------------+ +int main(void) { + board_init(); + + if (reprog_request() || !valid_fw_available()) { + mboot_dfu_init(); + mboot_dfu_run(); + // Reset controller after upgrade + NVIC_SystemReset(); + } else { + fw_start(); + } + + // Fatal error occured - wait for power cycle + for (;;) + { + __asm__ ("nop"); + } + + return 0; +} + +// --------------------------------------------------------------------+ +// Local Function Definitions +// --------------------------------------------------------------------+ +static bool reprog_request() { + bool reprogramming_requested = false; + + if ((bl_command.magic == BOOT_COMMAND_MAGIC) && (bl_command.command == BOOT_COMMAND_RESET_DFU)) { + reprogramming_requested = true; + } else { + reprogramming_requested = false; + } + + // Clear reprogramming header flags immediately to prevent reboot loops + bl_command.magic = 0x0UL; + bl_command.command = 0x0UL; + + return reprogramming_requested; +} + +static bool valid_fw_available() { + fw_header_t *fw_header = (fw_header_t *)MEM_GET_SYMBOL_VALUE(__firmware_start); + uintptr_t start_addr = ((uintptr_t)MEM_GET_SYMBOL_VALUE(__firmware_start)) + sizeof(fw_header_t); + mboot_validate_status_t fw_status = mboot_validate_firmware(fw_header, start_addr); + + return fw_status == FWV_STATUS_OK ? true : false; +} + +static inline firmware_entry_func get_entry_func() { + fw_header_t *fw_header = (fw_header_t *)&__firmware_start; + firmware_entry_func entry_func = (firmware_entry_func)fw_header->entry_addr; + return entry_func; +} + +static inline void fw_start() { + firmware_entry_func entry_func = get_entry_func(); + + entry_func(); + + for (;;) + { + __asm__ ("nop"); + } +} + +static void board_init() { + // Init clock + BOARD_BootClockRUN(); + SystemCoreClockUpdate(); + + // Enable IOCON clock + CLOCK_EnableClock(kCLOCK_Iomuxc); +} diff --git a/ports/mimxrt/mboot/mboot_buffer.c b/ports/mimxrt/mboot/mboot_buffer.c new file mode 100644 index 0000000000000..c06c13934456f --- /dev/null +++ b/ports/mimxrt/mboot/mboot_buffer.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include +#include "mboot_buffer.h" +#include "mboot_memory.h" + +// --------------------------------------------------------------------+ +// Local Variables +// --------------------------------------------------------------------+ +MEM_AT_SECTION(".fw_buffer") uint8_t fw_buffer[MICROPY_BOOT_BUFFER_SIZE]; +static size_t buffer_length; + +// --------------------------------------------------------------------+ +// Global Function Definitions +// --------------------------------------------------------------------+ +void mboot_buffer_init(void) { + buffer_length = 0UL; + memset(&fw_buffer[0], 0, MICROPY_BOOT_BUFFER_SIZE); +} + +size_t mboot_buffer_append(const uint8_t *data, size_t length) { + size_t bytes_remaining = (size_t)MICROPY_BOOT_BUFFER_SIZE - buffer_length; + size_t bytes_to_buffer = (bytes_remaining >= length) ? length : bytes_remaining; + + memcpy((void *)&fw_buffer[buffer_length], (void *)data, bytes_to_buffer); + buffer_length += bytes_to_buffer; + + return length - bytes_to_buffer; +} + +void mboot_buffer_pad(void) { + if (buffer_length < MICROPY_BOOT_BUFFER_SIZE) { + memset((void *)&fw_buffer[buffer_length], 0, (MICROPY_BOOT_BUFFER_SIZE - buffer_length)); + buffer_length = MICROPY_BOOT_BUFFER_SIZE; + } +} + +void mboot_buffer_reset(void) { + buffer_length = 0UL; +} + +uint8_t *mboot_buffer_data_ptr(void) { + return &fw_buffer[0]; +} + +bool mboot_buffer_is_full(void) { + return (size_t)buffer_length >= MICROPY_BOOT_BUFFER_SIZE; +} + +size_t mboot_buffer_len(void) { + return (size_t)buffer_length; +} diff --git a/ports/mimxrt/mboot/mboot_buffer.h b/ports/mimxrt/mboot/mboot_buffer.h new file mode 100644 index 0000000000000..58bbaf9b3ba04 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_buffer.h @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_BUFFER_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_BUFFER_H + +#include +#include +#include + +// --------------------------------------------------------------------+ +// Defines and Macros +// --------------------------------------------------------------------+ +#ifndef MICROPY_BOOT_BUFFER_SIZE +#define MICROPY_BOOT_BUFFER_SIZE (32 * 1024) // buffer size must be multiple of 4k! +#endif + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ +void mboot_buffer_init(); +size_t mboot_buffer_append(const uint8_t *data, size_t length); +void mboot_buffer_pad(void); +void mboot_buffer_reset(void); +uint8_t *mboot_buffer_data_ptr(void); +bool mboot_buffer_is_full(void); +size_t mboot_buffer_len(void); + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_BUFFER_H diff --git a/ports/mimxrt/mboot/mboot_dfu.c b/ports/mimxrt/mboot/mboot_dfu.c new file mode 100644 index 0000000000000..d88ac56db16ad --- /dev/null +++ b/ports/mimxrt/mboot/mboot_dfu.c @@ -0,0 +1,220 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +// include fsl_clock.h BEFORE including clock configuration due to bug in NXP HAL. +#include "fsl_clock.h" +#include CLOCK_CONFIG_H +#include "mboot_dfu.h" +#include "mboot_memory.h" +#include "mboot_upgrade.h" +#include "mboot_utils.h" +#include "mboot_validate.h" +#include "tusb.h" +#include "tusb_config.h" + +// --------------------------------------------------------------------+ +// Constants +// --------------------------------------------------------------------+ +const uint32_t dfu_finish_delay_time_ms = 500; + +// --------------------------------------------------------------------+ +// Local Variables +// --------------------------------------------------------------------+ +static bool dfu_finished = false; +static int32_t bytes_to_ignore = 0UL; + +// --------------------------------------------------------------------+ +// External Variables +// --------------------------------------------------------------------+ +extern uint32_t __flash_config_start; // Linker symbol +extern uint32_t __firmware_start; // Linker symbol + +// --------------------------------------------------------------------+ +// Local Function Declarations +// --------------------------------------------------------------------+ + +void usb_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn); + +// --------------------------------------------------------------------+ +// Global Functions +// --------------------------------------------------------------------+ + +void mboot_dfu_init(void) { + usb_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN + (void)mboot_upgrade_init(); + tusb_init(); + // --- + dfu_finished = false; + bytes_to_ignore = (int32_t)((uint32_t)MEM_GET_SYMBOL_VALUE(__firmware_start)) - ((uint32_t)MEM_GET_SYMBOL_VALUE(__flash_config_start)); +} + +void mboot_dfu_run(void) { + while (dfu_finished == false) { + tud_task(); // tinyusb device task + } +} + +// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) + + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) + + +// Invoked when a DFU_DETACH request is received +TU_ATTR_WEAK void tud_dfu_detach_cb(void); + +// --------------------------------------------------------------------+ +// Device callbacks +// --------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) { + return; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) { + (void)mboot_upgrade_deinit(); +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wake-up +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) { + (void)remote_wakeup_en; + (void)mboot_upgrade_deinit(); +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) { + (void)mboot_upgrade_deinit(); +} + +// --------------------------------------------------------------------+ +// DFU callbacks +// --------------------------------------------------------------------+ + +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) { + (void)alt; // Todo: Implement handling of alternative option in the future + return 0; +} + +void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length) { + (void)alt; // Todo: Implement handling of alternative option in the future + + + mboot_upgrade_status_t status = BU_STATUS_UNKNOWN_ERROR; + + if (bytes_to_ignore > length) { + bytes_to_ignore -= length; + status = BU_STATUS_OK; + } else { + length = length - bytes_to_ignore; + status = mboot_upgrade_write_data(block_num, data + bytes_to_ignore, length); + bytes_to_ignore = 0; + } + + if (status == BU_STATUS_OK) { + tud_dfu_finish_flashing(DFU_STATUS_OK); + } else { + mboot_upgrade_deinit(); + tud_dfu_finish_flashing(DFU_STATUS_ERR_PROG); + } +} + +void tud_dfu_manifest_cb(uint8_t alt) { + (void)alt; + + dfu_status_t dfu_status = DFU_STATUS_ERR_UNKNOWN; + mboot_upgrade_status_t status = BU_STATUS_UNKNOWN_ERROR; + + status = mboot_upgrade_finalize(); + + if (status == BU_STATUS_OK) { + status = mboot_upgrade_validate(); + if (status == BU_STATUS_OK) { + dfu_status = DFU_STATUS_OK; + } else { + mboot_upgrade_deinit(); + dfu_status = DFU_STATUS_ERR_VERIFY; + } + } else { + mboot_upgrade_deinit(); + dfu_status = DFU_STATUS_ERR_PROG; + } + + tud_dfu_finish_flashing(dfu_status); +} + +void tud_dfu_abort_cb(uint8_t alt) { + (void)alt; // Todo: Implement handling of alternative option in the future + (void)mboot_upgrade_deinit(); +} + +void tud_dfu_detach_cb(void) { + dfu_finished = true; +} + +uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t *data, uint16_t length) { + (void)alt; + (void)block_num; + (void)data; + (void)length; + return 0UL; +} + +// --------------------------------------------------------------------+ +// Helper functions +// --------------------------------------------------------------------+ +void usb_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn) { + #ifdef USBPHY1 + USBPHY_Type *usb_phy = USBPHY1; + #else + USBPHY_Type *usb_phy = USBPHY; + #endif + + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, BOARD_XTAL0_CLK_HZ); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, BOARD_XTAL0_CLK_HZ); + + #if defined(CPU_MIMXRT1176_cm7) + usb_phy->TRIM_OVERRIDE_EN = USBPHY_TRIM_OVERRIDE_EN_TRIM_DIV_SEL_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_ENV_TAIL_ADJ_VD_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_D_CAL_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DP_OVERRIDE(1) | + USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DN_OVERRIDE(1); // Enable override for D_CAL and TXCAL45DP/DN + #endif + usb_phy->PWD = 0U; // Set all bits in PWD register to normal operation + usb_phy->TX = ((usb_phy->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(d_cal) | USBPHY_TX_TXCAL45DP(txcal45dp) | USBPHY_TX_TXCAL45DM(txcal45dn))); // Configure values for D_CAL and TXCAL45DP/DN +} + +void USB_OTG1_IRQHandler(void) { + tud_int_handler(0); + __SEV(); +} diff --git a/ports/mimxrt/mboot/mboot_dfu.h b/ports/mimxrt/mboot/mboot_dfu.h new file mode 100644 index 0000000000000..635337406dff7 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_dfu.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_DFU_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_DFU_H + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ +void mboot_dfu_init(void); +void mboot_dfu_run(void); + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_DFU_H diff --git a/ports/mimxrt/mboot/mboot_memory.h b/ports/mimxrt/mboot/mboot_memory.h new file mode 100644 index 0000000000000..8453f1028e991 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_memory.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_MEMORY_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_MEMORY_H + +#define MEM_AT_SECTION(section_name) __attribute__((section(section_name))) +#define MEM_GET_SYMBOL_VALUE(symbol) & symbol + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_MEMORY_H diff --git a/ports/mimxrt/mboot/mboot_upgrade.c b/ports/mimxrt/mboot/mboot_upgrade.c new file mode 100644 index 0000000000000..36297ee729961 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_upgrade.c @@ -0,0 +1,307 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include "mboot_buffer.h" +#include "mboot_memory.h" +#include "mboot_upgrade.h" +#include "mboot_validate.h" +#include "flash.h" + +// --------------------------------------------------------------------+ +// Type Definitions +// --------------------------------------------------------------------+ +typedef struct _upgrade_session_t +{ + // Available memory range for session + uintptr_t mem_start_addr; + uintptr_t mem_end_addr; + + // Current addresses of write and erase pointer + uintptr_t write_addr; + uintptr_t erase_addr; + + // Number of blocks received for sessions + uint32_t n_blocks; + + // Number of bytes written to flash by session + uint32_t n_bytes_written; + + // Session block download function + mboot_upgrade_status_t (*write_data_handler)(); + + // Session status + status_t status; + mboot_upgrade_status_t upgrade_status; + mboot_validate_status_t verification_status; +} upgrade_session_t; + +// --------------------------------------------------------------------+ +// Local Variables +// --------------------------------------------------------------------+ +static fw_header_t image_header = {}; +static upgrade_session_t session; + +// --------------------------------------------------------------------+ +// External Variables +// --------------------------------------------------------------------+ +extern uintptr_t __firmware_start; +extern uintptr_t __firmware_end; +extern uintptr_t __flash_start; + +// --------------------------------------------------------------------+ +// Local Function Declarations +// --------------------------------------------------------------------+ +static mboot_upgrade_status_t write_initial_block_handler(); +static mboot_upgrade_status_t write_block_handler(); +static mboot_upgrade_status_t write_block(uint8_t *data, uint32_t length, uintptr_t *eaddr, uintptr_t *waddr); + +// --------------------------------------------------------------------+ +// Global Function Definitions +// --------------------------------------------------------------------+ + +// Todo: Add configuration structure +mboot_upgrade_status_t mboot_upgrade_init() { + flash_init(); + + // Initialize firmware upgrade session + session.n_blocks = 0UL; + session.n_bytes_written = 0UL; + session.status = kStatus_Success; + + session.mem_start_addr = ((uintptr_t)MEM_GET_SYMBOL_VALUE(__firmware_start)) - ((uintptr_t)MEM_GET_SYMBOL_VALUE(__flash_start)); + session.mem_end_addr = ((uintptr_t)MEM_GET_SYMBOL_VALUE(__firmware_end)) - ((uintptr_t)MEM_GET_SYMBOL_VALUE(__flash_start)); + session.write_addr = session.mem_start_addr; + session.erase_addr = session.mem_start_addr; + + session.upgrade_status = BU_STATUS_UNKNOWN_ERROR; + session.verification_status = FWV_STATUS_UNKNOWN_ERROR; + + // Initialize session write data handler + session.write_data_handler = write_initial_block_handler; + + // Initialize session data buffer + mboot_buffer_init(); + mboot_buffer_reset(); + + return BU_STATUS_OK; +} + +mboot_upgrade_status_t mboot_upgrade_deinit() { + // De-initialize firmware upgrade session + session.n_blocks = 0UL; + session.n_bytes_written = 0UL; + session.status = kStatus_Success; + + session.mem_start_addr = 0UL; + session.mem_end_addr = 0UL; + session.write_addr = session.mem_start_addr; + session.erase_addr = session.mem_start_addr; + + session.upgrade_status = BU_STATUS_UNKNOWN_ERROR; + session.verification_status = FWV_STATUS_UNKNOWN_ERROR; + + // De-initialize session write data handler + session.write_data_handler = write_initial_block_handler; + + // De-initialize session data buffer + mboot_buffer_reset(); + + return BU_STATUS_OK; +} + +// TODO: Return error when more data is 'written' than available +mboot_upgrade_status_t mboot_upgrade_write_data(uint16_t block_num, const uint8_t *data, uint16_t block_length) { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + session.n_blocks += 1UL; + + do { + // Append data to buffer when not full + if (!mboot_buffer_is_full()) { + uint32_t remaining_data = mboot_buffer_append(data, block_length); + // Update data buffer pointer to point to remaining data and update remaining block length + data += block_length - remaining_data; + block_length = remaining_data; + // --- + ret_status = BU_STATUS_OK; + } + + // Write data to flash when buffer full + if (mboot_buffer_is_full()) { + ret_status = session.write_data_handler(); + + if (ret_status != BU_STATUS_OK) { + break; + } + } + } while (block_length != 0); + + session.upgrade_status = ret_status; + return ret_status; +} + +mboot_upgrade_status_t mboot_upgrade_finalize() { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + + do { + // Pad buffer + mboot_buffer_pad(); + + ret_status = session.write_data_handler(); + if (ret_status != BU_STATUS_OK) { + break; + } + } while (session.write_addr < session.erase_addr); + + session.upgrade_status = ret_status; + return ret_status; +} + +mboot_upgrade_status_t mboot_upgrade_validate() { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + uintptr_t start_addr = ((uintptr_t)MEM_GET_SYMBOL_VALUE(__firmware_start)) + sizeof(fw_header_t); + + do { + mboot_validate_status_t fw_status = mboot_validate_firmware(&image_header, start_addr); + session.verification_status = fw_status; + + // Check if downloaded firmware is valid + if (fw_status != FWV_STATUS_OK) { + ret_status = BU_STATUS_FIRMWARE_INVALID; + break; + } + + // Write image header to flash to validate downloaded firmware + session.status = flash_write_block(session.mem_start_addr, + (uint8_t *)&image_header, + sizeof(image_header)); + if (session.status != kStatus_Success) { + ret_status = BU_STATUS_FLASH_WRITE_ERROR; + break; + } + + // Validation successfull + ret_status = BU_STATUS_OK; + } while (false); + + session.upgrade_status = ret_status; + return ret_status; +} + +// --------------------------------------------------------------------+ +// Local Function Definitions +// --------------------------------------------------------------------+ +static mboot_upgrade_status_t write_initial_block_handler() { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + uint8_t *data = mboot_buffer_data_ptr(); + uint32_t length = mboot_buffer_len(); + + do { + // Check received image header before writing any data to flash + // in order to prevent erasing a valid firmware if user tries to + // download an incompatible firmware image. + if (mboot_validate_header((fw_header_t *)data) != FWV_STATUS_OK) { + ret_status = BU_STATUS_RECEIVED_IMAGE_HEADER_INVALID; + break; + } + + // Store image header for later use in validation step of + // downloaded firmware. + memcpy(&image_header, (void *)data, sizeof(fw_header_t)); + + // Increment data pointer to offset image header. + data = (data + sizeof(fw_header_t)); + // Offset write address to skip image header when writing initial block. + session.write_addr += sizeof(fw_header_t); + + ret_status = write_block(data, length - sizeof(fw_header_t), + &session.erase_addr, + &session.write_addr); + if (ret_status != BU_STATUS_OK) { + break; + } + + // Swap session write handler function if + // initial block has been successfully written to flash memory. + session.write_data_handler = write_block_handler; + } while (false); + + mboot_buffer_reset(); + + return ret_status; +} + +static mboot_upgrade_status_t write_block_handler() { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + uint8_t *data = mboot_buffer_data_ptr(); + uint32_t length = mboot_buffer_len(); + + ret_status = write_block(data, length, + &session.erase_addr, + &session.write_addr); + + mboot_buffer_reset(); + + return ret_status; +} + +static mboot_upgrade_status_t write_block(uint8_t *data, uint32_t length, uintptr_t *eaddr, uintptr_t *waddr) { + mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; + + do { + // Erase block of flash only if write address plus data length + // exceeds already erased area + if (*eaddr < (*waddr + length)) { + do { + session.status = flash_erase_block(*eaddr); + + if (session.status == kStatus_Success) { + *eaddr += BLOCK_SIZE_BYTES; + ret_status = BU_STATUS_OK; + } else { + ret_status = BU_STATUS_FLASH_ERASE_ERROR; + break; // Break write operation in case of erase error + } + } while (*eaddr < (*waddr + length)); + + if (ret_status != BU_STATUS_OK) { + break; // Break write operation in case of erase error + } + } + + // Write block of data to flash + session.status = flash_write_block(*waddr, data, length); + + if (session.status == kStatus_Success) { + *waddr += length; + session.n_bytes_written += length; + ret_status = BU_STATUS_OK; + } else { + ret_status = BU_STATUS_FLASH_WRITE_ERROR; + } + } while (false); + + return ret_status; +} diff --git a/ports/mimxrt/mboot/mboot_upgrade.h b/ports/mimxrt/mboot/mboot_upgrade.h new file mode 100644 index 0000000000000..9ec56ca95095c --- /dev/null +++ b/ports/mimxrt/mboot/mboot_upgrade.h @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_UPGRADE_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_UPGRADE_H + +#include + +typedef enum _mboot_upgrade_status_t { + BU_STATUS_OK = 1, + BU_STATUS_FLASH_ERASE_ERROR = 10, + BU_STATUS_FLASH_WRITE_ERROR = 11, + BU_STATUS_RECEIVED_IMAGE_HEADER_INVALID = 20, + BU_STATUS_FIRMWARE_INVALID = 30, + BU_STATUS_UNKNOWN_ERROR = 99, +} mboot_upgrade_status_t; + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ + +/** + * Initializes firmware upgrade session base don selected configuration. + */ +mboot_upgrade_status_t mboot_upgrade_init(); + +/** + * De-initializes firmware upgrade session. + */ +mboot_upgrade_status_t mboot_upgrade_deinit(); + +/** + * Write block of data to memory. + * Note that data is not immediately written but rather buffered + * and flushed when buffer is full. + **/ +mboot_upgrade_status_t mboot_upgrade_write_data(uint16_t block_num, const uint8_t *data, uint16_t block_length); + +/** + * Finalize firmware upgrade by: + * - flushing remaining data from buffer and write to memory + **/ +mboot_upgrade_status_t mboot_upgrade_finalize(); + +/** + * Check and validate firmware upgrade: + * - check written data + * - valdiate firmware image if check ok + **/ +mboot_upgrade_status_t mboot_upgrade_validate(); + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_UPGRADE_H diff --git a/ports/mimxrt/mboot/mboot_utils.c b/ports/mimxrt/mboot/mboot_utils.c new file mode 100644 index 0000000000000..b6d533e67f025 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_utils.c @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include "mboot_utils.h" +#include CPU_HEADER_H + +void mboot_utils_uid(uint8_t uid[]) { + *(uint32_t *)&uid[0] = OCOTP->CFG0; + *(uint32_t *)&uid[4] = OCOTP->CFG1; +} diff --git a/ports/mimxrt/mboot/mboot_utils.h b/ports/mimxrt/mboot/mboot_utils.h new file mode 100644 index 0000000000000..2f9501dfd9fdb --- /dev/null +++ b/ports/mimxrt/mboot/mboot_utils.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_UTILS_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_UTILS_H + +#include +#include + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ +uint32_t mboot_utils_crc32(uint8_t *data, size_t len); +void mboot_utils_uid(uint8_t uid[]); + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_UTILS_H diff --git a/ports/mimxrt/mboot/mboot_validate.c b/ports/mimxrt/mboot/mboot_validate.c new file mode 100644 index 0000000000000..63cdc34871779 --- /dev/null +++ b/ports/mimxrt/mboot/mboot_validate.c @@ -0,0 +1,130 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include +#include +#include "mboot_validate.h" + +// --------------------------------------------------------------------+ +// Local Variables +// --------------------------------------------------------------------+ +const uint32_t crc_polynomial = 0x04C11DB7; +const uint32_t crc_initial = 0xFFFFFFFF; +const uint32_t crc_final_xor = 0xFFFFFFFF; + +// --------------------------------------------------------------------+ +// Local Function Declarations +// --------------------------------------------------------------------+ +static uint8_t reflect8(uint8_t val); +static uint32_t reflect32(uint32_t val); +static uint32_t crc32(const uint8_t *data, size_t len); + +// --------------------------------------------------------------------+ +// Global Function Definitions +// --------------------------------------------------------------------+ +mboot_validate_status_t mboot_validate_firmware(fw_header_t *img_header, uintptr_t start_addr) { + uint32_t crc_result = 0UL; + mboot_validate_status_t header_status = mboot_validate_header(img_header); + + if (header_status == FWV_STATUS_OK) { + crc_result = crc32((uint8_t *)start_addr, img_header->size - FW_HEADER_SIZE); + + if (crc_result == img_header->crc) { + return FWV_STATUS_OK; + } else { + return FWV_STATUS_IMAGE_INVALID_CRC_ERROR; + } + } else { + return header_status; + } +} + +mboot_validate_status_t mboot_validate_header(fw_header_t *img_header) { + uint32_t crc_result = 0UL; + + if (strncmp(img_header->magic, FW_HEADER_MAGIC, FW_HEADER_MAGIC_SIZE) == 0) { + crc_result = crc32((uint8_t *)img_header, FW_HEADER_SIZE - FW_HEADER_CRC_SIZE); + + if (crc_result == img_header->header_crc) { + return FWV_STATUS_OK; + } else { + return FWV_STATUS_HEADER_INVALID_CRC_ERROR; + } + } else { + return FWV_STATUS_HEADER_INVALID_MAGIC_ERROR; + } +} + +// --------------------------------------------------------------------+ +// Local Function Definitions +// --------------------------------------------------------------------+ +static uint8_t reflect8(uint8_t val) { + uint8_t resVal = 0; + + for (int i = 0; i < 8; i++) + { + if ((val & (1 << i)) != 0) { + resVal |= (uint8_t)(1 << (7 - i)); + } + } + + return resVal; +} + +static uint32_t reflect32(uint32_t val) { + uint32_t resVal = 0; + + for (int i = 0; i < 32; i++) + { + if ((val & (1 << i)) != 0) { + resVal |= (uint32_t)(1 << (31 - i)); + } + } + + return resVal; +} + +uint32_t crc32(const uint8_t *data, size_t len) { + uint32_t crc = crc_initial; + + for (int i = 0; i < len; ++i) + { + uint8_t curByte = reflect8(data[i]); + + crc ^= (uint32_t)(curByte << 24); /* move byte into MSB of 32bit CRC */ + + for (int i = 0; i < 8; i++) + { + if ((crc & 0x80000000) != 0) { /* test for MSB = bit 31 */ + crc = (uint32_t)((crc << 1) ^ crc_polynomial); + } else { + crc <<= 1; + } + } + } + crc = reflect32(crc); + return (uint32_t)(crc ^ crc_final_xor); +} diff --git a/ports/mimxrt/mboot/mboot_validate.h b/ports/mimxrt/mboot/mboot_validate.h new file mode 100644 index 0000000000000..05efe8c47a79c --- /dev/null +++ b/ports/mimxrt/mboot/mboot_validate.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_VALIDATE_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_VALIDATE_H + +#include +#include +#include "fw_header.h" + +typedef enum _mboot_validate_status_t { + FWV_STATUS_OK = 1, + FWV_STATUS_HEADER_INVALID_MAGIC_ERROR = 10, + FWV_STATUS_HEADER_INVALID_CRC_ERROR = 11, + FWV_STATUS_IMAGE_INVALID_CRC_ERROR = 20, + FWV_STATUS_UNKNOWN_ERROR = 99, +} mboot_validate_status_t; + +// --------------------------------------------------------------------+ +// Global Function Declarations +// --------------------------------------------------------------------+ +mboot_validate_status_t mboot_validate_firmware(fw_header_t *img_header, uintptr_t start_addr); +mboot_validate_status_t mboot_validate_header(fw_header_t *img_header); + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_VALIDATE_H diff --git a/ports/mimxrt/mboot/shared/fw_header.h b/ports/mimxrt/mboot/shared/fw_header.h new file mode 100644 index 0000000000000..c498f9954df19 --- /dev/null +++ b/ports/mimxrt/mboot/shared/fw_header.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_FW_HEADER_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_FW_HEADER_H + +#include +#include + +#define FW_HEADER_MAGIC "MPFW" +#define FW_HEADER_MAGIC_SIZE (4) +#define FW_HEADER_SIZE (sizeof(fw_header_t)) +#define FW_HEADER_CRC_SIZE (sizeof(fw_header_crc_t)) + +typedef uint32_t fw_header_crc_t; + +typedef struct _fw_header_t +{ + char magic[FW_HEADER_MAGIC_SIZE]; // 'MPFW' + uint8_t reserved0[4]; + fw_header_crc_t crc; + size_t size; + uintptr_t entry_addr; + uint8_t reserved1[8]; + fw_header_crc_t header_crc; +}fw_header_t; + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_FW_HEADER_H diff --git a/ports/mimxrt/mboot/shared/mboot_command.h b/ports/mimxrt/mboot/shared/mboot_command.h new file mode 100644 index 0000000000000..689ec1fb46764 --- /dev/null +++ b/ports/mimxrt/mboot/shared/mboot_command.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_MBOOT_COMMAND_H +#define MICROPY_INCLUDED_MIMXRT_MBOOT_COMMAND_H + +#define BOOT_COMMAND_MAGIC (0xCAFECAFE) +#define BOOT_COMMAND_RESET_DFU (0xA55A55AA) + +typedef struct _mboot_command_t +{ + uint32_t magic; + uint32_t command; +} mboot_command_t; + +#endif // MICROPY_INCLUDED_MIMXRT_MBOOT_COMMAND_H diff --git a/ports/mimxrt/mboot/tools/patch-binary.py b/ports/mimxrt/mboot/tools/patch-binary.py new file mode 100644 index 0000000000000..5141737a7cc36 --- /dev/null +++ b/ports/mimxrt/mboot/tools/patch-binary.py @@ -0,0 +1,118 @@ +#!/usr/bin/python +import sys +import struct +import argparse +import binascii +from collections import namedtuple +from pprint import pprint + + +FirmwareImageHeader = namedtuple( + "FirmwareImageHeader", + "magic crc size entry_addr header_crc", +) + +format_specifier_header = "<4s4xIII8xI" + + +def convert_size(byte_size): + if byte_size > (1024 * 1024 * 1024): + format_specifier = "GB" + byte_size = byte_size / (1024 * 1024 * 1024) + elif byte_size > (1024 * 1024): + format_specifier = "MB" + byte_size = byte_size / (1024 * 1024) + elif byte_size > 1024: + format_specifier = "KB" + byte_size = byte_size / 1024 + else: + format_specifier = "B" + byte_size = byte_size + + return "{0}{1}".format( + str(round(byte_size, 1) if byte_size % 1 else int(byte_size)), format_specifier + ) + + +def patch_binary(bin_data, offset, fill_to): + format_specifier_header = "<4s4xIII8xI" + format_specifier_header_crc = format_specifier_header[:-1] + header_size = struct.calcsize(format_specifier_header) + # + raw_header = FirmwareImageHeader._make( + struct.unpack(format_specifier_header, bin_data[0:header_size]) + ) + # Set image size attribute + size = len(bin_data) + crc = binascii.crc32(bin_data[header_size:]) & 0xFFFFFFFF + + patched_header = struct.pack( + format_specifier_header_crc, + raw_header.magic, + crc, + size, + raw_header.entry_addr, + ) + header_crc = binascii.crc32(patched_header) + patched_header += struct.pack("= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) { + return NULL; + } + if (index == USBD_STR_SERIAL) { + uint8_t uid[8]; + mboot_utils_uid(uid); + // store it as a hex string + for (len = 0; len < 16; len += 2) { + desc_str[1 + len] = hexchr[uid[len / 2] >> 4]; + desc_str[1 + len + 1] = hexchr[uid[len / 2] & 0x0f]; + } + } else { + const char *str = usbd_desc_str[index]; + for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) { + desc_str[1 + len] = str[len]; + } + } + } + + // first byte is length (including header), second byte is string type + desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2); + + return desc_str; +} From e3dc0033e9837114f2d8b193704cce9370555663 Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Mon, 18 Jul 2022 21:09:18 +0200 Subject: [PATCH 4/6] mimxrt/tusb: Adds runtime DFU descriptor. Adds runtime DFU descriptor to firmware. Allows to reset into DFU bootloader. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/modmachine.c | 9 +++++++++ ports/mimxrt/tusb_config.h | 2 ++ ports/mimxrt/tusb_port.c | 40 +++++++++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c index ad4e4a59412e8..2b04a47525b49 100644 --- a/ports/mimxrt/modmachine.c +++ b/ports/mimxrt/modmachine.c @@ -38,6 +38,7 @@ #include "modmachine.h" #include "fsl_clock.h" #include "fsl_wdog.h" +#include "mboot/shared/mboot_command.h" #if MICROPY_PY_MACHINE @@ -51,6 +52,14 @@ typedef enum { MP_SOFT_RESET } reset_reason_t; +__attribute__((section("._bl_command"))) mboot_command_t bl_command; + +void reset_boot(void) { + bl_command.magic = BOOT_COMMAND_MAGIC; + bl_command.command = BOOT_COMMAND_RESET_DFU; + NVIC_SystemReset(); +} + STATIC mp_obj_t machine_unique_id(void) { unsigned char id[8]; mp_hal_get_unique_id(id); diff --git a/ports/mimxrt/tusb_config.h b/ports/mimxrt/tusb_config.h index 862fb6c52d2e5..1926e02c68d5a 100644 --- a/ports/mimxrt/tusb_config.h +++ b/ports/mimxrt/tusb_config.h @@ -33,4 +33,6 @@ #define CFG_TUD_CDC_RX_BUFSIZE (512) #define CFG_TUD_CDC_TX_BUFSIZE (512) +#define CFG_TUD_DFU_RUNTIME (1) + #endif // MICROPY_INCLUDED_MIMXRT_TUSB_CONFIG_H diff --git a/ports/mimxrt/tusb_port.c b/ports/mimxrt/tusb_port.c index 55855674c6293..d25c1bddf1e37 100644 --- a/ports/mimxrt/tusb_port.c +++ b/ports/mimxrt/tusb_port.c @@ -39,11 +39,16 @@ #define MICROPY_HW_USB_STR_MANUF ("MicroPython") #endif -#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) -#define USBD_MAX_POWER_MA (250) +enum +{ + ITF_NUM_CDC, // needs 2 interfaces + ITF_NUM_CDC_DUMMY, + ITF_NUM_DFU_RT, + ITF_NUM_TOTAL +}; -#define USBD_ITF_CDC (0) // needs 2 interfaces -#define USBD_ITF_MAX (2) +#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_DFU_RT_DESC_LEN) +#define USBD_MAX_POWER_MA (250) #define USBD_CDC_EP_CMD (0x81) #define USBD_CDC_EP_OUT (0x02) @@ -51,11 +56,16 @@ #define USBD_CDC_CMD_MAX_SIZE (8) #define USBD_CDC_IN_OUT_MAX_SIZE (512) -#define USBD_STR_0 (0x00) -#define USBD_STR_MANUF (0x01) -#define USBD_STR_PRODUCT (0x02) -#define USBD_STR_SERIAL (0x03) -#define USBD_STR_CDC (0x04) +enum { + USBD_STR_0, + USBD_STR_MANUF, + USBD_STR_PRODUCT, + USBD_STR_SERIAL, + USBD_STR_CDC, + USBD_STR_DFU, +}; + +extern void reset_boot(void); // Note: descriptors returned from callbacks must exist long enough for transfer to complete @@ -77,11 +87,14 @@ static const tusb_desc_device_t usbd_desc_device = { }; static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { - TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, USBD_STR_0, USBD_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), - TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), + + // Interface number, string index, attributes, detach timeout, transfer size */ + TUD_DFU_RT_DESCRIPTOR(ITF_NUM_DFU_RT, USBD_STR_DFU, 0x0d, 1000, 4096), }; static const char *const usbd_desc_str[] = { @@ -89,6 +102,7 @@ static const char *const usbd_desc_str[] = { [USBD_STR_PRODUCT] = MICROPY_HW_BOARD_NAME, [USBD_STR_SERIAL] = "00000000000000000000", [USBD_STR_CDC] = "Board CDC", + [USBD_STR_DFU] = "Board DFU Runtime" }; const uint8_t *tud_descriptor_device_cb(void) { @@ -136,3 +150,7 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { return desc_str; } + +void tud_dfu_runtime_reboot_to_dfu_cb() { + reset_boot(); +} From 75776fcfac05fa437563a2d86a77e93cc98b3f49 Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Mon, 18 Jul 2022 21:11:56 +0200 Subject: [PATCH 5/6] mimxrt/modmachine: Adds bootloader command. Adds method to jump into DFU bootloader via MicroPython code. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/modmachine.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c index 2b04a47525b49..9e421a6a7617d 100644 --- a/ports/mimxrt/modmachine.c +++ b/ports/mimxrt/modmachine.c @@ -93,6 +93,12 @@ STATIC mp_obj_t machine_reset_cause(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); +STATIC mp_obj_t machine_bootloader(void) { + reset_boot(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); + STATIC mp_obj_t machine_freq(void) { return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq()); } @@ -123,6 +129,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, From 58fa8256c78babf10f8ed0d318a7de13a6d2f872 Mon Sep 17 00:00:00 2001 From: Philipp Ebensberger Date: Mon, 18 Jul 2022 20:17:31 +0200 Subject: [PATCH 6/6] mimxrt/mboot: Fixes code review findings. Fixes code formatting with curly brackets on `for` loops and adds `void` argument to empty function declarations and definitions. Signed-off-by: Philipp Ebensberger --- ports/mimxrt/mboot.mk | 1 + ports/mimxrt/mboot/main.c | 16 +++++++--------- ports/mimxrt/mboot/mboot_buffer.h | 2 +- ports/mimxrt/mboot/mboot_upgrade.c | 12 ++++++------ ports/mimxrt/mboot/mboot_upgrade.h | 8 ++++---- ports/mimxrt/mboot/mboot_validate.c | 12 ++++-------- 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/ports/mimxrt/mboot.mk b/ports/mimxrt/mboot.mk index c6744e4a346fa..40d2d55a43152 100644 --- a/ports/mimxrt/mboot.mk +++ b/ports/mimxrt/mboot.mk @@ -105,6 +105,7 @@ CFLAGS_BL += \ -nostdlib \ -std=c99 \ -Wall \ + -Werror \ -Wdouble-promotion \ -Werror \ -Wfloat-conversion \ diff --git a/ports/mimxrt/mboot/main.c b/ports/mimxrt/mboot/main.c index 7f6bf360c182f..ba803f9dab6f8 100644 --- a/ports/mimxrt/mboot/main.c +++ b/ports/mimxrt/mboot/main.c @@ -67,7 +67,7 @@ extern uint32_t __firmware_start; // Linker symbol // --------------------------------------------------------------------+ // External Function Declarations // --------------------------------------------------------------------+ -extern void SystemInit(); +extern void SystemInit(void); // --------------------------------------------------------------------+ // Local Function Declarations @@ -94,8 +94,7 @@ int main(void) { } // Fatal error occured - wait for power cycle - for (;;) - { + for (;;) { __asm__ ("nop"); } @@ -105,7 +104,7 @@ int main(void) { // --------------------------------------------------------------------+ // Local Function Definitions // --------------------------------------------------------------------+ -static bool reprog_request() { +static bool reprog_request(void) { bool reprogramming_requested = false; if ((bl_command.magic == BOOT_COMMAND_MAGIC) && (bl_command.command == BOOT_COMMAND_RESET_DFU)) { @@ -121,7 +120,7 @@ static bool reprog_request() { return reprogramming_requested; } -static bool valid_fw_available() { +static bool valid_fw_available(void) { fw_header_t *fw_header = (fw_header_t *)MEM_GET_SYMBOL_VALUE(__firmware_start); uintptr_t start_addr = ((uintptr_t)MEM_GET_SYMBOL_VALUE(__firmware_start)) + sizeof(fw_header_t); mboot_validate_status_t fw_status = mboot_validate_firmware(fw_header, start_addr); @@ -135,18 +134,17 @@ static inline firmware_entry_func get_entry_func() { return entry_func; } -static inline void fw_start() { +static inline void fw_start(void) { firmware_entry_func entry_func = get_entry_func(); entry_func(); - for (;;) - { + for (;;) { __asm__ ("nop"); } } -static void board_init() { +static void board_init(void) { // Init clock BOARD_BootClockRUN(); SystemCoreClockUpdate(); diff --git a/ports/mimxrt/mboot/mboot_buffer.h b/ports/mimxrt/mboot/mboot_buffer.h index 58bbaf9b3ba04..ee7e58fb58746 100644 --- a/ports/mimxrt/mboot/mboot_buffer.h +++ b/ports/mimxrt/mboot/mboot_buffer.h @@ -41,7 +41,7 @@ // --------------------------------------------------------------------+ // Global Function Declarations // --------------------------------------------------------------------+ -void mboot_buffer_init(); +void mboot_buffer_init(void); size_t mboot_buffer_append(const uint8_t *data, size_t length); void mboot_buffer_pad(void); void mboot_buffer_reset(void); diff --git a/ports/mimxrt/mboot/mboot_upgrade.c b/ports/mimxrt/mboot/mboot_upgrade.c index 36297ee729961..56fe64adad909 100644 --- a/ports/mimxrt/mboot/mboot_upgrade.c +++ b/ports/mimxrt/mboot/mboot_upgrade.c @@ -74,8 +74,8 @@ extern uintptr_t __flash_start; // --------------------------------------------------------------------+ // Local Function Declarations // --------------------------------------------------------------------+ -static mboot_upgrade_status_t write_initial_block_handler(); -static mboot_upgrade_status_t write_block_handler(); +static mboot_upgrade_status_t write_initial_block_handler(void); +static mboot_upgrade_status_t write_block_handler(void); static mboot_upgrade_status_t write_block(uint8_t *data, uint32_t length, uintptr_t *eaddr, uintptr_t *waddr); // --------------------------------------------------------------------+ @@ -83,7 +83,7 @@ static mboot_upgrade_status_t write_block(uint8_t *data, uint32_t length, uintpt // --------------------------------------------------------------------+ // Todo: Add configuration structure -mboot_upgrade_status_t mboot_upgrade_init() { +mboot_upgrade_status_t mboot_upgrade_init(void) { flash_init(); // Initialize firmware upgrade session @@ -109,7 +109,7 @@ mboot_upgrade_status_t mboot_upgrade_init() { return BU_STATUS_OK; } -mboot_upgrade_status_t mboot_upgrade_deinit() { +mboot_upgrade_status_t mboot_upgrade_deinit(void) { // De-initialize firmware upgrade session session.n_blocks = 0UL; session.n_bytes_written = 0UL; @@ -213,7 +213,7 @@ mboot_upgrade_status_t mboot_upgrade_validate() { // --------------------------------------------------------------------+ // Local Function Definitions // --------------------------------------------------------------------+ -static mboot_upgrade_status_t write_initial_block_handler() { +static mboot_upgrade_status_t write_initial_block_handler(void) { mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; uint8_t *data = mboot_buffer_data_ptr(); uint32_t length = mboot_buffer_len(); @@ -253,7 +253,7 @@ static mboot_upgrade_status_t write_initial_block_handler() { return ret_status; } -static mboot_upgrade_status_t write_block_handler() { +static mboot_upgrade_status_t write_block_handler(void) { mboot_upgrade_status_t ret_status = BU_STATUS_UNKNOWN_ERROR; uint8_t *data = mboot_buffer_data_ptr(); uint32_t length = mboot_buffer_len(); diff --git a/ports/mimxrt/mboot/mboot_upgrade.h b/ports/mimxrt/mboot/mboot_upgrade.h index 9ec56ca95095c..b7efbc13f8168 100644 --- a/ports/mimxrt/mboot/mboot_upgrade.h +++ b/ports/mimxrt/mboot/mboot_upgrade.h @@ -45,12 +45,12 @@ typedef enum _mboot_upgrade_status_t { /** * Initializes firmware upgrade session base don selected configuration. */ -mboot_upgrade_status_t mboot_upgrade_init(); +mboot_upgrade_status_t mboot_upgrade_init(void); /** * De-initializes firmware upgrade session. */ -mboot_upgrade_status_t mboot_upgrade_deinit(); +mboot_upgrade_status_t mboot_upgrade_deinit(void); /** * Write block of data to memory. @@ -63,13 +63,13 @@ mboot_upgrade_status_t mboot_upgrade_write_data(uint16_t block_num, const uint8_ * Finalize firmware upgrade by: * - flushing remaining data from buffer and write to memory **/ -mboot_upgrade_status_t mboot_upgrade_finalize(); +mboot_upgrade_status_t mboot_upgrade_finalize(void); /** * Check and validate firmware upgrade: * - check written data * - valdiate firmware image if check ok **/ -mboot_upgrade_status_t mboot_upgrade_validate(); +mboot_upgrade_status_t mboot_upgrade_validate(void); #endif // MICROPY_INCLUDED_MIMXRT_MBOOT_UPGRADE_H diff --git a/ports/mimxrt/mboot/mboot_validate.c b/ports/mimxrt/mboot/mboot_validate.c index 63cdc34871779..83c03f2a52d3a 100644 --- a/ports/mimxrt/mboot/mboot_validate.c +++ b/ports/mimxrt/mboot/mboot_validate.c @@ -84,8 +84,7 @@ mboot_validate_status_t mboot_validate_header(fw_header_t *img_header) { static uint8_t reflect8(uint8_t val) { uint8_t resVal = 0; - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) { if ((val & (1 << i)) != 0) { resVal |= (uint8_t)(1 << (7 - i)); } @@ -97,8 +96,7 @@ static uint8_t reflect8(uint8_t val) { static uint32_t reflect32(uint32_t val) { uint32_t resVal = 0; - for (int i = 0; i < 32; i++) - { + for (int i = 0; i < 32; i++) { if ((val & (1 << i)) != 0) { resVal |= (uint32_t)(1 << (31 - i)); } @@ -110,14 +108,12 @@ static uint32_t reflect32(uint32_t val) { uint32_t crc32(const uint8_t *data, size_t len) { uint32_t crc = crc_initial; - for (int i = 0; i < len; ++i) - { + for (int i = 0; i < len; ++i) { uint8_t curByte = reflect8(data[i]); crc ^= (uint32_t)(curByte << 24); /* move byte into MSB of 32bit CRC */ - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) { if ((crc & 0x80000000) != 0) { /* test for MSB = bit 31 */ crc = (uint32_t)((crc << 1) ^ crc_polynomial); } else { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy