mimxrt/flash: Separate low level driver code from flash object.

Separate low level flash access from mimxrt flash driver object.  Allows
better abstraction from hardware for testing and reuse in other areas (e.g.
bootloader).

Signed-off-by: Philipp Ebensberger <philipp.ebensberger@3bricks-software.de>
pull/11071/head
Philipp Ebensberger 2022-07-18 20:51:43 +02:00 zatwierdzone przez Damien George
rodzic 7333c06d05
commit a3f3b9045c
10 zmienionych plików z 235 dodań i 77 usunięć

Wyświetl plik

@ -183,6 +183,7 @@ SRC_C += \
drivers/dht/dht.c \
eth.c \
fatfs_port.c \
flash.c \
hal/pwm_backport.c \
led.c \
machine_adc.c \

Wyświetl plik

@ -0,0 +1,123 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 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"
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(BOARD_FLEX_SPI, 0,
qspiflash_config.memConfig.lookupTable,
ARRAY_SIZE(qspiflash_config.memConfig.lookupTable));
// Configure FLEXSPI IP FIFO access.
BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK);
BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ATDFEN_MASK);
BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ARDFEN(0);
BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ATDFEN(0);
}
// flash_erase_block(erase_addr)
// erases the block starting at addr. Block size according to the flash properties.
__attribute__((section(".ram_functions"))) 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(BOARD_FLEX_SPI, 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.
__attribute__((section(".ram_functions"))) 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(BOARD_FLEX_SPI, 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
__attribute__((section(".ram_functions"))) status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) {
status_t status = kStatus_Fail;
uint32_t write_length;
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
do {
next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary
write_length = next_addr - dest_addr; // calculate write length based on destination address and subsequent page boundary.
if (write_length > length) { // compare possible write_length against remaining data length
write_length = length;
}
__disable_irq();
status = flexspi_nor_flash_page_program(BOARD_FLEX_SPI, dest_addr, (uint32_t *)src, write_length);
__enable_irq();
// Update remaining data length
length -= write_length;
// Move source and destination pointer
src += write_length;
dest_addr += write_length;
} while ((length > 0) && (status == kStatus_Success));
SCB_EnableDCache();
}
return status;
}
// flash_read_block(flash_src_addr_bytes, data_dest, length_bytes)
// read length_byte data to the source address
// It is just a shim to provide the same structure for read_block and write_block.
__attribute__((section(".ram_functions"))) void flash_read_block(uint32_t src_addr, uint8_t *dest, uint32_t length) {
memcpy(dest, (const uint8_t *)(BOARD_FLEX_SPI_ADDR_BASE + src_addr), length);
}

Wyświetl plik

@ -0,0 +1,58 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 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
#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
#define BLOCK_SIZE_BYTES (qspiflash_config.blockSize)
#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
#ifndef MICROPY_HW_FLASH_STORAGE_BYTES
#define MICROPY_HW_FLASH_STORAGE_BYTES (((uint32_t)&__vfs_end) - ((uint32_t)&__vfs_start))
#endif
#ifndef MICROPY_HW_FLASH_STORAGE_BASE
#define MICROPY_HW_FLASH_STORAGE_BASE (((uint32_t)&__vfs_start) - ((uint32_t)&__flash_start))
#endif
// Linker symbols
extern uint8_t __vfs_start;
extern uint8_t __vfs_end;
extern uint8_t __flash_start;
void flash_init(void);
status_t flash_erase_sector(uint32_t erase_addr);
status_t flash_erase_block(uint32_t erase_addr);
void flash_read_block(uint32_t src_addr, uint8_t *dest, uint32_t length);
status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length);
#endif // MICROPY_INCLUDED_MIMXRT_FLASH_H

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -49,6 +49,7 @@ status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base);
void flexspi_hyper_flash_init(void);
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) {

Wyświetl plik

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

Wyświetl plik

@ -48,6 +48,7 @@ status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId);
status_t flexspi_nor_init(void);
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);
#endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_NOR_FLASH_H

Wyświetl plik

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

Wyświetl plik

@ -4,7 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020-2021 Damien P. George
* Copyright (c) 2021 Philipp Ebensberger
* Copyright (c) 2021-2023 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
@ -30,23 +30,9 @@
#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)
#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
#ifndef MICROPY_HW_FLASH_STORAGE_BYTES
#define MICROPY_HW_FLASH_STORAGE_BYTES (((uint32_t)&__vfs_end) - ((uint32_t)&__vfs_start))
#endif
#ifndef MICROPY_HW_FLASH_STORAGE_BASE
#define MICROPY_HW_FLASH_STORAGE_BASE (((uint32_t)&__vfs_start) - ((uint32_t)&__flash_start))
#endif
// Linker symbols
extern uint8_t __vfs_start;
extern uint8_t __vfs_end;
extern uint8_t __flash_start;
extern flexspi_nor_config_t qspiflash_config;
@ -60,67 +46,11 @@ 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(BOARD_FLEX_SPI, 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(BOARD_FLEX_SPI, 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);
// Upload the custom flash configuration
// This should be performed by the boot ROM but for some reason it is not.
FLEXSPI_UpdateLUT(BOARD_FLEX_SPI, 0,
qspiflash_config.memConfig.lookupTable,
ARRAY_SIZE(qspiflash_config.memConfig.lookupTable));
// Configure BOARD_FLEX_SPI IP FIFO access.
BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK);
BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ATDFEN_MASK);
BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ARDFEN(0);
BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ATDFEN(0);
flash_init();
// Update information based on linker symbols.
mimxrt_flash_obj.flash_base = MICROPY_HW_FLASH_STORAGE_BASE;
@ -142,7 +72,8 @@ STATIC mp_obj_t mimxrt_flash_readblocks(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) {
offset += mp_obj_get_int(args[3]);
}
memcpy(bufinfo.buf, (uint8_t *)(BOARD_FLEX_SPI_ADDR_BASE + self->flash_base + offset), bufinfo.len);
flash_read_block((self->flash_base + offset), (uint8_t *)bufinfo.buf, (uint32_t)bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mimxrt_flash_readblocks_obj, 3, 4, mimxrt_flash_readblocks);
@ -161,7 +92,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 +130,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: