diff --git a/lib/bio/debug.c b/lib/bio/debug.c index 631747d5..8f04871f 100644 --- a/lib/bio/debug.c +++ b/lib/bio/debug.c @@ -45,6 +45,8 @@ STATIC_COMMAND_START STATIC_COMMAND("bio", "block io debug commands", &cmd_bio) STATIC_COMMAND_END(bio); +#define DMA_ALIGNMENT (CACHE_LINE) + static int cmd_bio(int argc, const cmd_args *argv) { int rc = 0; @@ -288,7 +290,7 @@ usage: static bool is_valid_block(bdev_t *device, bnum_t block_num, uint8_t* pattern, size_t pattern_length) { - uint8_t *block_contents = malloc(device->block_size); + uint8_t *block_contents = memalign(DMA_ALIGNMENT, device->block_size); ssize_t n_bytes = device->read_block(device, block_contents, block_num, 1); if (n_bytes < 0 || n_bytes != (ssize_t)device->block_size) { @@ -331,13 +333,19 @@ static ssize_t erase_test(bdev_t *device) return num_invalid_blocks; } +static uint8_t get_signature(uint32_t word) +{ + uint8_t* sigptr = (uint8_t*)(&word); + return sigptr[0] ^ sigptr[1] ^ sigptr[2] ^ sigptr[3]; +} + // returns the number of blocks where the write was not successful. static ssize_t write_test(bdev_t *device) { - uint8_t *test_buffer = malloc(device->block_size); + uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size); for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { - memset(test_buffer, (uint8_t)bnum, device->block_size); + memset(test_buffer, get_signature(bnum), device->block_size); ssize_t err = bio_write_block(device, test_buffer, bnum, 1); if (err < 0) { free(test_buffer); @@ -348,7 +356,7 @@ static ssize_t write_test(bdev_t *device) size_t num_errors = 0; uint8_t expected_pattern[1]; for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { - expected_pattern[0] = (uint8_t)bnum; + expected_pattern[0] = get_signature(bnum); if (!is_valid_block(device, bnum, expected_pattern, sizeof(expected_pattern))) { num_errors++; } diff --git a/platform/stm32f7xx/include/platform/n25q512a.h b/platform/stm32f7xx/include/platform/n25q512a.h new file mode 100644 index 00000000..4494679e --- /dev/null +++ b/platform/stm32f7xx/include/platform/n25q512a.h @@ -0,0 +1,261 @@ +/** + ****************************************************************************** + * @file n25q512a.h + * @author MCD Application Team + * @version V1.0.0 + * @date 28-April-2015 + * @brief This file contains all the description of the N25Q512A QSPI memory. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __N25Q512A_H +#define __N25Q512A_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup n25q512a + * @{ + */ + +/** @defgroup N25Q512A_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup N25Q512A_Exported_Constants + * @{ + */ + +/** + * @brief N25Q512A Configuration + */ +#define N25Q512A_FLASH_SIZE 0x4000000 /* 512 MBits => 64MBytes */ +#define N25Q512A_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */ +#define N25Q512A_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ +#define N25Q512A_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ + +#define N25Q512A_DUMMY_CYCLES_READ 8 +#define N25Q512A_DUMMY_CYCLES_READ_QUAD 10 +#define N25Q512A_DUMMY_CYCLES_READ_DTR 6 +#define N25Q512A_DUMMY_CYCLES_READ_QUAD_DTR 8 + +#define N25Q512A_BULK_ERASE_MAX_TIME 480000 +#define N25Q512A_SECTOR_ERASE_MAX_TIME 3000 +#define N25Q512A_SUBSECTOR_ERASE_MAX_TIME 800 + +/** + * @brief N25Q512A Commands + */ +/* Reset Operations */ +#define RESET_ENABLE_CMD 0x66 +#define RESET_MEMORY_CMD 0x99 + +/* Identification Operations */ +#define READ_ID_CMD 0x9E +#define READ_ID_CMD2 0x9F +#define MULTIPLE_IO_READ_ID_CMD 0xAF +#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A + +/* Read Operations */ +#define READ_CMD 0x03 +#define READ_4_BYTE_ADDR_CMD 0x13 + +#define FAST_READ_CMD 0x0B +#define FAST_READ_DTR_CMD 0x0D +#define FAST_READ_4_BYTE_ADDR_CMD 0x0C + +#define DUAL_OUT_FAST_READ_CMD 0x3B +#define DUAL_OUT_FAST_READ_DTR_CMD 0x3D +#define DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x3C + +#define DUAL_INOUT_FAST_READ_CMD 0xBB +#define DUAL_INOUT_FAST_READ_DTR_CMD 0xBD +#define DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xBC + +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_OUT_FAST_READ_DTR_CMD 0x6D +#define QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x6C + +#define QUAD_INOUT_FAST_READ_CMD 0xEB +#define QUAD_INOUT_FAST_READ_DTR_CMD 0xED +#define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xEC + +/* Write Operations */ +#define WRITE_ENABLE_CMD 0x06 +#define WRITE_DISABLE_CMD 0x04 + +/* Register Operations */ +#define READ_STATUS_REG_CMD 0x05 +#define WRITE_STATUS_REG_CMD 0x01 + +#define READ_LOCK_REG_CMD 0xE8 +#define WRITE_LOCK_REG_CMD 0xE5 + +#define READ_FLAG_STATUS_REG_CMD 0x70 +#define CLEAR_FLAG_STATUS_REG_CMD 0x50 + +#define READ_NONVOL_CFG_REG_CMD 0xB5 +#define WRITE_NONVOL_CFG_REG_CMD 0xB1 + +#define READ_VOL_CFG_REG_CMD 0x85 +#define WRITE_VOL_CFG_REG_CMD 0x81 + +#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65 +#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61 + +#define READ_EXT_ADDR_REG_CMD 0xC8 +#define WRITE_EXT_ADDR_REG_CMD 0xC5 + +/* Program Operations */ +#define PAGE_PROG_CMD 0x02 +#define PAGE_PROG_4_BYTE_ADDR_CMD 0x12 + +#define DUAL_IN_FAST_PROG_CMD 0xA2 +#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2 + +#define QUAD_IN_FAST_PROG_CMD 0x32 +#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /*0x38*/ +#define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD 0x34 + +/* Erase Operations */ +#define SUBSECTOR_ERASE_CMD 0x20 +#define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD 0x21 + +#define SECTOR_ERASE_CMD 0xD8 +#define SECTOR_ERASE_4_BYTE_ADDR_CMD 0xDC + +#define BULK_ERASE_CMD 0xC7 + +#define PROG_ERASE_RESUME_CMD 0x7A +#define PROG_ERASE_SUSPEND_CMD 0x75 + +/* One-Time Programmable Operations */ +#define READ_OTP_ARRAY_CMD 0x4B +#define PROG_OTP_ARRAY_CMD 0x42 + +/* 4-byte Address Mode Operations */ +#define ENTER_4_BYTE_ADDR_MODE_CMD 0xB7 +#define EXIT_4_BYTE_ADDR_MODE_CMD 0xE9 + +/* Quad Operations */ +#define ENTER_QUAD_CMD 0x35 +#define EXIT_QUAD_CMD 0xF5 + +/** + * @brief N25Q512A Registers + */ +/* Status Register */ +#define N25Q512A_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ +#define N25Q512A_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ +#define N25Q512A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ +#define N25Q512A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ +#define N25Q512A_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ + +/* Non volatile Configuration Register */ +#define N25Q512A_NVCR_NBADDR ((uint16_t)0x0001) /*!< 3-bytes or 4-bytes addressing */ +#define N25Q512A_NVCR_SEGMENT ((uint16_t)0x0002) /*!< Upper or lower 128Mb segment selected by default */ +#define N25Q512A_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */ +#define N25Q512A_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */ +#define N25Q512A_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */ +#define N25Q512A_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */ +#define N25Q512A_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */ +#define N25Q512A_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */ + +/* Volatile Configuration Register */ +#define N25Q512A_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */ +#define N25Q512A_VCR_XIP ((uint8_t)0x08) /*!< XIP */ +#define N25Q512A_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */ + +/* Extended Address Register */ +#define N25Q512A_EAR_A24 ((uint8_t)0x01) /*!< Select the lower or upper 128Mb segment */ + +/* Enhanced Volatile Configuration Register */ +#define N25Q512A_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */ +#define N25Q512A_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */ +#define N25Q512A_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */ +#define N25Q512A_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */ +#define N25Q512A_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */ + +/* Flag Status Register */ +#define N25Q512A_FSR_NBADDR ((uint8_t)0x01) /*!< 3-bytes or 4-bytes addressing */ +#define N25Q512A_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */ +#define N25Q512A_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */ +#define N25Q512A_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */ +#define N25Q512A_FSR_PGERR ((uint8_t)0x10) /*!< Program error */ +#define N25Q512A_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */ +#define N25Q512A_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */ +#define N25Q512A_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */ + +/** + * @} + */ + +/** @defgroup N25Q512A_Exported_Functions + * @{ + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __N25Q512A_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/platform/stm32f7xx/include/platform/n25qxxa.h b/platform/stm32f7xx/include/platform/n25qxxa.h new file mode 100644 index 00000000..ae10a20a --- /dev/null +++ b/platform/stm32f7xx/include/platform/n25qxxa.h @@ -0,0 +1,216 @@ +/** + ****************************************************************************** + * @file n25qxxa.h + * @author MCD Application Team, Adapted by Gurjant Kalsi + * @version V1.0.0 + * @date 28-April-2015 + * @brief This file contains all the description of the N25QXXA QSPI memory. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __N25QXXA_H +#define __N25QXXA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup n25qXXA + * @{ + */ + +/** @defgroup N25QXXA_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup N25QXXA_Exported_Constants + * @{ + */ + +/** + * @brief N25QXXA Configuration + */ +#define N25QXXA_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */ +#define N25QXXA_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ +#define N25QXXA_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ + +#define N25QXXA_DUMMY_CYCLES_READ 8 +#define N25QXXA_DUMMY_CYCLES_READ_QUAD 10 + +#define N25QXXA_SECTOR_ERASE_MAX_TIME 3000 +#define N25QXXA_SUBSECTOR_ERASE_MAX_TIME 800 + +/** + * @brief N25QXXA Commands + */ +/* Reset Operations */ +#define RESET_ENABLE_CMD 0x66 +#define RESET_MEMORY_CMD 0x99 + +/* Identification Operations */ +#define READ_ID_CMD 0x9E +#define READ_ID_CMD2 0x9F +#define MULTIPLE_IO_READ_ID_CMD 0xAF +#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A + +/* Read Operations */ +#define READ_CMD 0x03 +#define FAST_READ_CMD 0x0B +#define DUAL_OUT_FAST_READ_CMD 0x3B +#define DUAL_INOUT_FAST_READ_CMD 0xBB +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_INOUT_FAST_READ_CMD 0xEB + +/* Write Operations */ +#define WRITE_ENABLE_CMD 0x06 +#define WRITE_DISABLE_CMD 0x04 + +/* Register Operations */ +#define READ_STATUS_REG_CMD 0x05 +#define WRITE_STATUS_REG_CMD 0x01 + +#define READ_LOCK_REG_CMD 0xE8 +#define WRITE_LOCK_REG_CMD 0xE5 + +#define READ_FLAG_STATUS_REG_CMD 0x70 +#define CLEAR_FLAG_STATUS_REG_CMD 0x50 + +#define READ_NONVOL_CFG_REG_CMD 0xB5 +#define WRITE_NONVOL_CFG_REG_CMD 0xB1 + +#define READ_VOL_CFG_REG_CMD 0x85 +#define WRITE_VOL_CFG_REG_CMD 0x81 + +#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65 +#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61 + +/* Program Operations */ +#define PAGE_PROG_CMD 0x02 +#define DUAL_IN_FAST_PROG_CMD 0xA2 +#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2 +#define QUAD_IN_FAST_PROG_CMD 0x32 +#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /*0x38*/ + +/* Erase Operations */ +#define SUBSECTOR_ERASE_CMD 0x20 +#define SECTOR_ERASE_CMD 0xD8 +#define BULK_ERASE_CMD 0xC7 + +#define PROG_ERASE_RESUME_CMD 0x7A +#define PROG_ERASE_SUSPEND_CMD 0x75 + +/* One-Time Programmable Operations */ +#define READ_OTP_ARRAY_CMD 0x4B +#define PROG_OTP_ARRAY_CMD 0x42 + +/** + * @brief N25QXXA Registers + */ +/* Status Register */ +#define N25QXXA_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ +#define N25QXXA_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ +#define N25QXXA_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ +#define N25QXXA_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ +#define N25QXXA_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ + +/* Non volatile Configuration Register */ +#define N25QXXA_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */ +#define N25QXXA_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */ +#define N25QXXA_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */ +#define N25QXXA_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */ +#define N25QXXA_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */ +#define N25QXXA_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */ + +/* Volatile Configuration Register */ +#define N25QXXA_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */ +#define N25QXXA_VCR_XIP ((uint8_t)0x08) /*!< XIP */ +#define N25QXXA_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */ + +/* Enhanced Volatile Configuration Register */ +#define N25QXXA_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */ +#define N25QXXA_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */ +#define N25QXXA_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */ +#define N25QXXA_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */ +#define N25QXXA_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */ + +/* Flag Status Register */ +#define N25QXXA_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */ +#define N25QXXA_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */ +#define N25QXXA_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */ +#define N25QXXA_FSR_PGERR ((uint8_t)0x10) /*!< Program error */ +#define N25QXXA_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */ +#define N25QXXA_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */ +#define N25QXXA_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */ + +/** + * @} + */ + +/** @defgroup N25QXXA_Exported_Functions + * @{ + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __N25QXXA_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/platform/stm32f7xx/include/platform/qspi.h b/platform/stm32f7xx/include/platform/qspi.h index cb24fe4c..818aa69d 100644 --- a/platform/stm32f7xx/include/platform/qspi.h +++ b/platform/stm32f7xx/include/platform/qspi.h @@ -27,6 +27,6 @@ #include // Initialize the QSPI Flash device. -status_t qspi_flash_init(void); +status_t qspi_flash_init(size_t flash_size); #endif // __PLATFORM_STM32_QSPI_H diff --git a/platform/stm32f7xx/qspi.c b/platform/stm32f7xx/qspi.c index 49755f90..ba536801 100644 --- a/platform/stm32f7xx/qspi.c +++ b/platform/stm32f7xx/qspi.c @@ -29,9 +29,12 @@ #include #include #include -#include +#include +#include #include +#define FOUR_BYTE_ADDR_THRESHOLD (1 << 24) + static QSPI_HandleTypeDef qspi_handle; static DMA_HandleTypeDef hdma; @@ -50,10 +53,10 @@ static int spiflash_ioctl(struct bdev* device, int request, void* argp); static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data); -static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction); -static ssize_t qspi_bulk_erase(void); -static ssize_t qspi_erase_sector(uint32_t block_addr); -static ssize_t qspi_erase_subsector(uint32_t block_addr); +static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction); +static ssize_t qspi_bulk_erase(bdev_t *device); +static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr); +static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr); static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*); static HAL_StatusTypeDef qspi_tx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*, uint8_t*); @@ -61,6 +64,9 @@ static HAL_StatusTypeDef qspi_rx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*, status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi); +static uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address); +static uint32_t get_address_size(uint32_t address); + static event_t cmd_event; static event_t rx_event; static event_t tx_event; @@ -91,8 +97,8 @@ static status_t qspi_write_enable_unsafe(QSPI_HandleTypeDef* hqspi) } /* Configure automatic polling mode to wait for write enabling */ - s_config.Match = N25Q128A_SR_WREN; - s_config.Mask = N25Q128A_SR_WREN; + s_config.Match = N25QXXA_SR_WREN; + s_config.Mask = N25QXXA_SR_WREN; s_config.MatchMode = QSPI_MATCH_MODE_AND; s_config.StatusBytesSize = 1; s_config.Interval = 0x10; @@ -149,8 +155,8 @@ static status_t qspi_dummy_cycles_cfg_unsafe(QSPI_HandleTypeDef* hqspi) /* Update volatile configuration register (with new dummy cycles) */ s_command.Instruction = WRITE_VOL_CFG_REG_CMD; MODIFY_REG( - reg, N25Q128A_VCR_NB_DUMMY, - (N25Q128A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q128A_VCR_NB_DUMMY))); + reg, N25QXXA_VCR_NB_DUMMY, + (N25QXXA_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25QXXA_VCR_NB_DUMMY))); /* Configure the write volatile configuration register command */ status = HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); @@ -186,7 +192,7 @@ static status_t qspi_auto_polling_mem_ready_unsafe(QSPI_HandleTypeDef* hqspi) s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; s_config.Match = 0; - s_config.Mask = N25Q128A_SR_WIP; + s_config.Mask = N25QXXA_SR_WIP; s_config.MatchMode = QSPI_MATCH_MODE_AND; s_config.StatusBytesSize = 1; s_config.Interval = 0x10; @@ -251,12 +257,12 @@ static ssize_t spiflash_bdev_read(struct bdev* device, void* buf, off_t offset, // /* Initialize the read command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; - s_command.Instruction = QUAD_OUT_FAST_READ_CMD; + s_command.Instruction = get_specialized_instruction(QUAD_OUT_FAST_READ_CMD, offset); s_command.AddressMode = QSPI_ADDRESS_1_LINE; - s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AddressSize = get_address_size(offset); s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; - s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; + s_command.DummyCycles = N25QXXA_DUMMY_CYCLES_READ_QUAD; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; @@ -311,14 +317,14 @@ static ssize_t spiflash_bdev_write_block(struct bdev* device, const void* _buf, ssize_t total_bytes_written = 0; for (; count > 0; count--, block++) { - ssize_t bytes_written = qspi_write_page_unsafe(block * N25Q128A_PAGE_SIZE, buf); + ssize_t bytes_written = qspi_write_page_unsafe(block * N25QXXA_PAGE_SIZE, buf); if (bytes_written < 0) { printf("qspi_write_page_unsafe failed\n"); total_bytes_written = bytes_written; goto err; } - buf += N25Q128A_PAGE_SIZE; + buf += N25QXXA_PAGE_SIZE; total_bytes_written += bytes_written; } @@ -340,16 +346,16 @@ static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset, mutex_acquire(&spiflash_mutex); // Choose an erase strategy based on the number of bytes being erased. - if (len == N25Q128A_FLASH_SIZE && offset == 0) { + if (len == device->total_size && offset == 0) { // Bulk erase the whole flash. - total_erased = qspi_bulk_erase(); + total_erased = qspi_bulk_erase(device); goto finish; } // Erase as many sectors as necessary, then switch to subsector erase for // more fine grained erasure. - while (((ssize_t)len - total_erased) >= N25Q128A_SECTOR_SIZE) { - ssize_t erased = qspi_erase_sector(offset); + while (((ssize_t)len - total_erased) >= N25QXXA_SECTOR_SIZE) { + ssize_t erased = qspi_erase_sector(device, offset); if (erased < 0) { total_erased = erased; goto finish; @@ -359,7 +365,7 @@ static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset, } while (total_erased < (ssize_t)len) { - ssize_t erased = qspi_erase_subsector(offset); + ssize_t erased = qspi_erase_subsector(device, offset); if (erased < 0) { total_erased = erased; goto finish; @@ -380,7 +386,7 @@ static int spiflash_ioctl(struct bdev* device, int request, void* argp) static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data) { - if (!IS_ALIGNED(addr, N25Q128A_PAGE_SIZE)) { + if (!IS_ALIGNED(addr, N25QXXA_PAGE_SIZE)) { return ERR_INVALID_ARGS; } @@ -388,9 +394,9 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data) QSPI_CommandTypeDef s_command = { .InstructionMode = QSPI_INSTRUCTION_1_LINE, - .Instruction = QUAD_IN_FAST_PROG_CMD, + .Instruction = get_specialized_instruction(QUAD_IN_FAST_PROG_CMD, addr), .AddressMode = QSPI_ADDRESS_1_LINE, - .AddressSize = QSPI_ADDRESS_24_BITS, + .AddressSize = get_address_size(addr), .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, .DataMode = QSPI_DATA_4_LINES, .DummyCycles = 0, @@ -398,7 +404,7 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data) .DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY, .SIOOMode = QSPI_SIOO_INST_EVERY_CMD, .Address = addr, - .NbData = N25Q128A_PAGE_SIZE + .NbData = N25QXXA_PAGE_SIZE }; status_t write_enable_result = qspi_write_enable_unsafe(&qspi_handle); @@ -422,11 +428,11 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data) return auto_polling_mem_ready_result; } - return N25Q128A_PAGE_SIZE; + return N25QXXA_PAGE_SIZE; } -status_t qspi_flash_init(void) +status_t qspi_flash_init(size_t flash_size) { status_t result = NO_ERROR; @@ -455,7 +461,7 @@ status_t qspi_flash_init(void) qspi_handle.Init.ClockPrescaler = 1; qspi_handle.Init.FifoThreshold = 4; qspi_handle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; - qspi_handle.Init.FlashSize = POSITION_VAL(N25Q128A_FLASH_SIZE) - 1; + qspi_handle.Init.FlashSize = POSITION_VAL(flash_size) - 1; qspi_handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE; qspi_handle.Init.ClockMode = QSPI_CLOCK_MODE_0; qspi_handle.Init.FlashID = QSPI_FLASH_ID_1; @@ -486,13 +492,13 @@ status_t qspi_flash_init(void) } // Initialize the QSPI Flash and register it as a Block I/O device. - geometry.erase_size = log2_uint(N25Q128A_SUBSECTOR_SIZE); - geometry.erase_shift = log2_uint(N25Q128A_SUBSECTOR_SIZE); + geometry.erase_size = log2_uint(N25QXXA_SUBSECTOR_SIZE); + geometry.erase_shift = log2_uint(N25QXXA_SUBSECTOR_SIZE); geometry.start = 0; - geometry.size = N25Q128A_FLASH_SIZE; + geometry.size = flash_size; - bio_initialize_bdev(&qspi_flash_device, device_name, N25Q128A_PAGE_SIZE, - (N25Q128A_FLASH_SIZE / N25Q128A_PAGE_SIZE), 1, &geometry); + bio_initialize_bdev(&qspi_flash_device, device_name, N25QXXA_PAGE_SIZE, + (flash_size / N25QXXA_PAGE_SIZE), 1, &geometry); qspi_flash_device.read = &spiflash_bdev_read; qspi_flash_device.read_block = &spiflash_bdev_read_block; @@ -527,7 +533,7 @@ status_t hal_error_to_status(HAL_StatusTypeDef hal_status) } } -static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction) +static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction) { if (instruction == BULK_ERASE_CMD && block_addr != 0) { // This call was probably not what the user intended since the @@ -540,18 +546,21 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction) ssize_t num_erased_bytes; switch (instruction) { case SUBSECTOR_ERASE_CMD: { - num_erased_bytes = N25Q128A_SUBSECTOR_SIZE; - erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE; + num_erased_bytes = N25QXXA_SUBSECTOR_SIZE; + erase_cmd.AddressMode = get_address_size(block_addr); + erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr); break; } case SECTOR_ERASE_CMD: { - num_erased_bytes = N25Q128A_SECTOR_SIZE; - erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE; + num_erased_bytes = N25QXXA_SECTOR_SIZE; + erase_cmd.AddressMode = get_address_size(block_addr); + erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr); break; } case BULK_ERASE_CMD: { - num_erased_bytes = N25Q128A_FLASH_SIZE; + num_erased_bytes = device->total_size; erase_cmd.AddressMode = QSPI_ADDRESS_NONE; + erase_cmd.Instruction = instruction; break; } default: { @@ -570,8 +579,6 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction) erase_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; erase_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; - erase_cmd.Instruction = instruction; - /* Enable write operations */ status_t qspi_write_enable_result = qspi_write_enable_unsafe(&qspi_handle); @@ -594,19 +601,19 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction) return num_erased_bytes; } -static ssize_t qspi_bulk_erase(void) +static ssize_t qspi_bulk_erase(bdev_t *device) { - return qspi_erase(0, BULK_ERASE_CMD); + return qspi_erase(device, 0, BULK_ERASE_CMD); } -static ssize_t qspi_erase_sector(uint32_t block_addr) +static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr) { - return qspi_erase(block_addr, SECTOR_ERASE_CMD); + return qspi_erase(device, block_addr, SECTOR_ERASE_CMD); } -static ssize_t qspi_erase_subsector(uint32_t block_addr) +static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr) { - return qspi_erase(block_addr, SUBSECTOR_ERASE_CMD); + return qspi_erase(device, block_addr, SUBSECTOR_ERASE_CMD); } static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef* qspi_handle, @@ -708,4 +715,45 @@ status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi) HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn); return NO_ERROR; -} \ No newline at end of file +} + +uint32_t get_address_size(uint32_t address) +{ + if (address >= FOUR_BYTE_ADDR_THRESHOLD) { + return QSPI_ADDRESS_32_BITS; + } + return QSPI_ADDRESS_24_BITS; +} + +// Converts a 3 byte instruction into a 4 byte instruction if necessary. +uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address) +{ + if (address < FOUR_BYTE_ADDR_THRESHOLD) { + return instruction; + } + + switch (instruction) { + case READ_CMD: + return READ_4_BYTE_ADDR_CMD; + case FAST_READ_CMD: + return FAST_READ_4_BYTE_ADDR_CMD; + case DUAL_OUT_FAST_READ_CMD: + return DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD; + case DUAL_INOUT_FAST_READ_CMD: + return DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD; + case QUAD_OUT_FAST_READ_CMD: + return QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD; + case QUAD_INOUT_FAST_READ_CMD: + return QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; + case PAGE_PROG_CMD: + return PAGE_PROG_4_BYTE_ADDR_CMD; + case QUAD_IN_FAST_PROG_CMD: + return QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; + case SUBSECTOR_ERASE_CMD: + return SUBSECTOR_ERASE_4_BYTE_ADDR_CMD; + case SECTOR_ERASE_CMD: + return SECTOR_ERASE_4_BYTE_ADDR_CMD; + } + + return instruction; +} diff --git a/target/stm32746g-eval2/init.c b/target/stm32746g-eval2/init.c index d71c2e4c..8c34e85c 100644 --- a/target/stm32746g-eval2/init.c +++ b/target/stm32746g-eval2/init.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,7 @@ void target_init(void) TRACE_ENTRY; stm32_debug_init(); - qspi_flash_init(); + qspi_flash_init(N25Q512A_FLASH_SIZE); #if WITH_LIB_MINIP uint8_t mac_addr[6]; diff --git a/target/stm32f746g-disco/init.c b/target/stm32f746g-disco/init.c index 48c95fb4..a5932cf7 100644 --- a/target/stm32f746g-disco/init.c +++ b/target/stm32f746g-disco/init.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ void target_init(void) { stm32_debug_init(); - qspi_flash_init(); + qspi_flash_init(N25Q128A_FLASH_SIZE); #if WITH_LIB_MINIP uint8_t mac_addr[6];