/* * Copyright 2016-2022 NXP * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o 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. * * o Neither the name of NXP Semiconductor, Inc. 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. */ //------------------------------------------------------------------------------ // See section 8.13.2 in RTR1064 Users Manual regarding FlexSPI NOR API //------------------------------------------------------------------------------ #include "fsl_flexspi.h" #include "fsl_rtwdog.h" #include "fsl_wdog.h" #include "evkmimxrt1064_flexspi_nor_config.h" // Contains definition of flexspi_nor_config_t etc typedef struct { void (*RTWDOG_GetDefaultConfig)(rtwdog_config_t *config); void (*RTWDOG_Init)(RTWDOG_Type *base, const rtwdog_config_t *config); void (*RTWDOG_Deinit)(RTWDOG_Type *base); void (*RTWDOG_Enable)(RTWDOG_Type *base); void (*RTWDOG_Disable)(RTWDOG_Type *base); void (*RTWDOG_EnableInterrupts)(RTWDOG_Type *base, uint32_t mask); void (*RTWDOG_DisableInterrupts)(RTWDOG_Type *base, uint32_t mask); uint32_t (*RTWDOG_GetStatusFlags)(RTWDOG_Type *base); void (*RTWDOG_ClearStatusFlags)(RTWDOG_Type *base, uint32_t mask); void (*RTWDOG_SetTimeoutValue)(RTWDOG_Type *base, uint16_t timeoutCount); void (*RTWDOG_SetWindowValue)(RTWDOG_Type *base, uint16_t windowValue); void (*RTWDOG_Unlock)(RTWDOG_Type *base); void (*RTWDOG_Refresh)(RTWDOG_Type *base); uint16_t (*RTWDOG_GetCounterValue)(RTWDOG_Type *base); } rtwdog_driver_interface_t; typedef struct { void (*WDOG_GetDefaultConfig)(wdog_config_t *config); void (*WDOG_Init)(WDOG_Type *base, const wdog_config_t *config); void (*WDOG_Deinit)(WDOG_Type *base); void (*WDOG_Enable)(WDOG_Type *base); void (*WDOG_Disable)(WDOG_Type *base); void (*WDOG_EnableInterrupts)(WDOG_Type *base, uint16_t mask); uint16_t (*WDOG_GetStatusFlags)(WDOG_Type *base); void (*WDOG_ClearInterruptStatus)(WDOG_Type *base, uint16_t mask); void (*WDOG_SetTimeoutValue)(WDOG_Type *base, uint16_t timeoutCount); void (*WDOG_SetInterrputTimeoutValue)(WDOG_Type *base, uint16_t timeoutCount); void (*WDOG_DisablePowerDownEnable)(WDOG_Type *base); void (*WDOG_Refresh)(WDOG_Type *base); } wdog_driver_interface_t; typedef struct _serial_nor_config_option { union { struct { uint32_t max_freq : 4; //!< Maximum supported Frequency uint32_t misc_mode : 4; //!< miscellaneous mode uint32_t quad_mode_setting : 4; //!< Quad mode setting uint32_t cmd_pads : 4; //!< Command pads uint32_t query_pads : 4; //!< SFDP read pads uint32_t device_type : 4; //!< Device type uint32_t option_size : 4; //!< Option size, in terms of uint32_t, size = (option_size + 1) * 4 uint32_t tag : 4; //!< Tag, must be 0x0E } B; uint32_t U; } option0; union { struct { uint32_t dummy_cycles : 8; //!< Dummy cycles before read uint32_t reserved0 : 8; //!< Reserved for future use uint32_t pinmux_group : 4; //!< The pinmux group selection uint32_t reserved1 : 8; //!< Reserved for future use uint32_t flash_connection : 4; //!< Flash connection option: 0 - Single Flash connected to port A } B; uint32_t U; } option1; } serial_nor_config_option_t; typedef enum _FlexSPIOperationType { kFlexSpiOperation_Command, //!< FlexSPI operation: Only command, both TX and RX buffer are ignored. kFlexSpiOperation_Config, //!< FlexSPI operation: Configure device mode, the TX FIFO size is fixed in LUT. kFlexSpiOperation_Write, //!< FlexSPI operation: Write, only TX buffer is effective kFlexSpiOperation_Read, //!< FlexSPI operation: Read, only Rx Buffer is effective. kFlexSpiOperation_End = kFlexSpiOperation_Read, } flexspi_operation_t; typedef struct _FlexSpiXfer { flexspi_operation_t operation; //!< FlexSPI operation uint32_t baseAddress; //!< FlexSPI operation base address uint32_t seqId; //!< Sequence Id uint32_t seqNum; //!< Sequence Number bool isParallelModeEnable; //!< Is a parallel transfer uint32_t *txBuffer; //!< Tx buffer uint32_t txSize; //!< Tx size in bytes uint32_t *rxBuffer; //!< Rx buffer uint32_t rxSize; //!< Rx size in bytes } flexspi_xfer_t; typedef struct { uint32_t version; status_t (*init)(uint32_t instance, flexspi_nor_config_t *config); status_t (*program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t dst_addr, const uint32_t *src); status_t (*erase_all)(uint32_t instance, flexspi_nor_config_t *config); status_t (*erase)(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t lengthInBytes); status_t (*read)(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t addr, uint32_t lengthInBytes); void (*clear_cache)(uint32_t instance); status_t (*xfer)(uint32_t instance, flexspi_xfer_t *xfer); status_t (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, uint32_t seqNumber); status_t (*get_config)(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option); } flexspi_nor_driver_interface_t; typedef struct { const uint32_t version; //!< Bootloader version number const char *copyright; //!< Bootloader Copyright void (*runBootloader)(void *arg); //!< Function to start the bootloader executing const uint32_t *reserved0; //!< Reserved const flexspi_nor_driver_interface_t *flexSpiNorDriver; //!< FlexSPI NOR Flash API const uint32_t *reserved1[2]; //!< Reserved const rtwdog_driver_interface_t *rtwdogDriver; const wdog_driver_interface_t *wdogDriver; const uint32_t *reserved2; } bootloader_api_entry_t; #define g_bootloaderTree (*(bootloader_api_entry_t**)(0x0020001c)) //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_flash_init(uint32_t instance, flexspi_nor_config_t *config) { return g_bootloaderTree->flexSpiNorDriver->init(instance, config); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_flash_page_program(uint32_t instance, flexspi_nor_config_t*config, uint32_t dstAddr, const uint32_t *src) { return g_bootloaderTree->flexSpiNorDriver->program(instance, config, dstAddr, src); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_flash_erase_all(uint32_t instance, flexspi_nor_config_t *config) { return g_bootloaderTree->flexSpiNorDriver->erase_all(instance, config); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_get_config(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option) { return g_bootloaderTree->flexSpiNorDriver->get_config(instance, config, option); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_flash_erase(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t length) { return g_bootloaderTree->flexSpiNorDriver->erase(instance, config, start, length); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ status_t flexspi_nor_flash_read(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t start, uint32_t bytes) { return g_bootloaderTree->flexSpiNorDriver->read(instance, config, dst, start, bytes); } // Test data static flexspi_nor_config_t config; static serial_nor_config_option_t option; static status_t status; static uint32_t address = 0x00000; // The 256 bytes page we are programming starts at 0x70040000 static uint32_t sector_size = 0x1000; // a sector is 4KB static uint32_t page_buffer[256/ sizeof(uint32_t)]; static uint32_t instance = 1; // Should identify NOR memory instance //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int testIAP(void) { option.option0.U = 0xC0000008; // QuadSPI NOR, Frequency: 133MHz // Need to run with interrupts disabled as all our code is running out of FlexSPI2 (internal NOT flash in RT1064) __disable_irq(); config.memConfig.deviceModeType= 2; status = flexspi_nor_get_config(instance, &config, &option); if (status != kStatus_Success) { __enable_irq(); return status; } status = flexspi_nor_flash_init(instance, &config); if (status != kStatus_Success) { __enable_irq(); return status; } status = flexspi_nor_flash_erase(instance, &config, address , sector_size); // Erase 1 sector if (status != kStatus_Success) { __enable_irq(); return status; } // Fill data into the page_buffer; for (uint32_t i=0; i