/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2023 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPEL™ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK. Lattice grants permission to use this code pursuant to the terms of the Lattice Propel License Agreement. DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "qspi_flash_cntl.h" #include "reg_access.h" #include static volatile qspi_flash_cntl_reg_t *flash_cntl; unsigned int temp_read; /** * @brief Function to print the configuration registers values. * * This function to print the configuration registers values according to the input parameters. * * @param dbg_val Content to be printed on UART output. * @return N/A */ void print_config_reg(config_output_type_t dbg_val){ temp_read = 0; reg_32b_read((unsigned int)(&(flash_cntl->REG_QSPI_CONFIG_0)), &temp_read); if (dbg_val == PRINT_ALL || dbg_val == PRINT_ONLY_CONFIG){ printf("INFO: QSPI Configuration 0 information \r\n"); printf("First Bit Transfer: 0x%X\r\n",temp_read & FIRST_BIT_TRF_BIT); printf("CPOL: 0x%X\r\n",((temp_read & CPOL_BIT) >> 1)); printf("CPHA: 0x%X\r\n",((temp_read & CPHA_BIT) >> 2)); printf("Clock Divider: 0x%X\r\n",((temp_read & SCK_RATE_BIT) >> 8)); printf("Data Endianess: 0x%X\r\n",((temp_read & DATA_ENDIAN_BIT) >> 13)); printf("Enable frame end counter: 0x%X\r\n",((temp_read & EN_FRAME_END_DONE_CNT_BIT) >> 15)); printf("Flash Map Write Command (All): 0x%X\r\n",((temp_read & FLASH_MAP_EN_WR_ACCESS_BIT) >> 16)); printf("Flash Map Read Command (All): 0x%X\r\n",((temp_read & FLASH_MAP_EN_RD_ACCESS_BIT) >> 19)); printf("Dummy Clock Cycle: 0x%X\r\n",((temp_read & DUMMY_CLK_CYCLE_BIT) >> 22)); printf("Xip Address Width: 0x%X\r\n",((temp_read & XIP_ADDR_WIDTH_BIT) >> 25)); printf("Command Lane Width: 0x%X\r\n",((temp_read & CMD_LANE_WIDTH_BIT) >> 26)); printf("Address Lane Width: 0x%X\r\n",((temp_read & ADDR_LANE_WIDTH_BIT) >> 28)); printf("Data Lane Width: 0x%X\r\n",((temp_read & DAT_LANE_WIDTH_BIT) >> 30)); printf("\r\n"); } if (dbg_val == PRINT_ALL || dbg_val == PRINT_ONLY_HDR_DATA){ printf("\r\nINFO: CONFIG, Header and Data Registers\r\n"); printf("REG_QSPI_CONFIG_0 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_QSPI_CONFIG_1)), &temp_read); printf("REG_QSPI_CONFIG_1 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_HDR_0)), &temp_read); printf("REG_PACKET_HDR_0 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_HDR_1)), &temp_read); printf("REG_PACKET_HDR_1 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_HDR_2)), &temp_read); printf("REG_PACKET_HDR_2 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_HDR_3)), &temp_read); printf("REG_PACKET_HDR_3 0x%X\r\n\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_DATA_0)), &temp_read); printf("REG_PACKET_DATA_0 0x%X\r\n",temp_read); reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_DATA_1)), &temp_read); printf("REG_PACKET_DATA_1 0x%X\r\n\n",temp_read); } } /** * @brief Initializes the QSPI flash controller instance with the provided base address and status. * * This function initializes the QSPI flash controller instance pointed by 'this_qspi_flash_cntl' * with the given 'base_addr'. It also sets the status of the flash controller * to 'IDLE'. * * @param this_qspi_flash_cntl Pointer to the QSPI flash controller instance. * @param base_addr The base address of the QSPI flash controller registers. * @return Returns 'SUCCESS' (0) on successful initialization, or 'FAILURE' (1) if 'this_qspi_flash_cntl' is NULL. */ unsigned char qspi_flash_cntl_init(struct qspi_flash_cntl_instance_t *this_qspi_flash_cntl) { if(this_qspi_flash_cntl == IS_NULL) { return RET_FAILURE; } flash_cntl = (volatile qspi_flash_cntl_reg_t *)this_qspi_flash_cntl->base_address; flash_cntl->REG_QSPI_CONFIG_0 = this_qspi_flash_cntl->config_0; flash_cntl->REG_QSPI_CONFIG_1 = this_qspi_flash_cntl->config_1; print_config_reg(PRINT_ONLY_CONFIG); this_qspi_flash_cntl->status = IDLE; return RET_SUCCESS; } /** * @brief Initiate the SPI transaction * * This function inititate the SPI transaction by configure the start transaction register (0x220) * * @return Returns 'SUCCESS' (0) on successful transaction. */ unsigned char qspi_trans_start(void){ unsigned int sts = 1; flash_cntl->REG_START_TRANS = START_TRANS_VAL; while (sts & CHECK_ONE != 0){ reg_32b_read((unsigned int)(&(flash_cntl->REG_TRANS_STATUS)), &sts); } return RET_SUCCESS; } /** * @brief Reads the value from the specified register. * * This function reads the value from the QSPI flash controller registers * specified by 'index' and stores the result in the 'reg_data' pointer. * * @param this_qspi_flash_cntl Pointer to the QSPI flash controller instance. * @param index The index of the QSPI configuration register to read. * @param reg_data Pointer to a variable where the read register value will be stored. * @return Returns 'SUCCESS' (0) on successful read, or 'FAILURE' (1) if 'this_qspi_flash_cntl' is NULL. */ unsigned char qspi_flash_cntl_read(struct qspi_flash_cntl_instance_t *this_qspi_flash_cntl, qspi_reg_type_t index, unsigned int *reg_data) { if(this_qspi_flash_cntl == IS_NULL) { return RET_FAILURE; } volatile unsigned int base_addr = (unsigned int)(this_qspi_flash_cntl->base_address); volatile unsigned int *read_reg = (unsigned int *)(base_addr + (index<base_address); volatile unsigned int *write_reg = (unsigned int *)(base_addr + (index<REG_START_TRANS = 0; qspi_params.params_ext_t.flash_addr_width = FLASH_24BIT_ADDR; qspi_params.params_ext_t.flash_addr_LSB = 0x00000000; /* Configure packet header */ qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_READ_ID; printf("INFO: Sending command: FLASH_CMD_CODE_MULTIPLE_IO_READ_ID\r\n"); qspi_params.params_ext_t.buff_length = 4; qspi_params.params_ext_t.with_payload = 0; /* Single target support */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* No dummy cycles winbond */ qspi_params.params_ext_t.num_wait_cycle = 0; /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(&qspi_params); flash_cntl->REG_INT_STATUS = (INT_REG_RD_PKT_DATA_0_NOT_EMPTY | INT_REG_RD_PKT_DATA_1_NOT_EMPTY); /* Start transaction */ qspi_trans_start(); /* Clear start interupt register */ flash_cntl->REG_INT_STATUS = INT_REG_RD_PKT_DATA_0_NOT_EMPTY; reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_DATA_0)), &temp_read); /* Big Endian */ /* Read the data packet */ buffer[0] = (temp_read >> 24) & 0xFF; buffer[1] = (temp_read >> 16) & 0xFF; buffer[2] = (temp_read >> 8) & 0xFF; /* Clear start transaction register */ flash_cntl->REG_START_TRANS = CLR_START_TRANS; #if (DEBUG_EN == 1) printf("RET_SUCCESS(%s): buffer[0] 0x%02X buffer[1] 0x%02X buffer[2] 0x%02X buffer[3] 0x%02X\r\n", __func__, buffer[0], buffer[1],buffer[2],buffer[3]); #endif return RET_SUCCESS; } /** * @brief Write/Erase Flash Memory Data with QSPI Flash Controller when fifo is enable. * *This function is used to write/erase the data to the flash memory using TX FIFO. * * @param this_qspi_fifo Pointer to the to the structure qspi_params_t. * @param buffer Pointer to the buffer containing data to be written. * @return Returns 'SUCCESS' (0) on successful write, or 'FAILURE' (1) if 'buffer' is NULL. */ unsigned char qspi_flash_cntl_write_erase_fifo_en(qspi_params_t *this_qspi_fifo ,unsigned int *buffer) { unsigned int count_wr_fifo = 0; unsigned int irq_sts = 0; if (buffer == IS_NULL) { return RET_FAILURE; } flash_cntl->REG_INT_ENABLE = INT_EN_VAL; // enable interrupt qspi_flash_cntl_set_tx_fifo(this_qspi_fifo); while (count_wr_fifo < ((this_qspi_fifo->params_ext_t.buff_length)>>REG_GAP)) { flash_cntl->REG_TX_FIFO_MAP = buffer[count_wr_fifo++]; // write the data } flash_cntl->REG_START_TRANS = START_TRANS_VAL; // start transaction while ((irq_sts & CHECK_ONE) == IRQ_WR_FIFO_EN) // check interrupt { reg_32b_read((unsigned int)(&(flash_cntl->REG_INT_STATUS)), &irq_sts); } flash_cntl->REG_START_TRANS = CLR_START_TRANS; return RET_SUCCESS; } /** * @brief Reads data from RX FIFO with QSPI flash controller with FIFO enable. * * This function is used to read the data from the flash memory using RX FIFO. * * @param buffer Pointer to the buffer to store the read data. * @param this_qspi_fifo Pointer to the structure qspi_params_t. */ void qspi_flash_cntl_read_fifo_en(qspi_params_t *this_qspi_fifo ,unsigned int *buffer) { unsigned int count_read_fifo = 0; temp_read = 0; qspi_flash_cntl_set_tx_fifo(this_qspi_fifo); flash_cntl->REG_START_TRANS = START_TRANS_VAL; // start transaction while(((flash_cntl->REG_INT_STATUS>>SHIFT_FOUR) & CHECK_ONE) == IRQ_RD_FIFO_EN); flash_cntl->REG_INT_STATUS = CLR_INTERRUPT; // clear interrupt while(count_read_fifo < ((this_qspi_fifo->params_ext_t.buff_length)>>REG_GAP)) { reg_32b_read((unsigned int)(&(flash_cntl->REG_RX_FIFO_MAP)), &temp_read); buffer[count_read_fifo++] = temp_read; // read the data printf("INFO: flash_cntl->REG_RX_FIFO_MAP = 0x%x",temp_read); } flash_cntl->REG_START_TRANS = CLR_START_TRANS; } /** * @brief Erases the specified amount of flash at the specified address * * This function writes the value 'reg_data' to the QSPI flash controller register * specified by 'index'. * * @param flash_addr Address of the SPI flash to be erased * @param flash_addr Address mode, 3-byte, 4-byte (no bytes for chip erase) * @param erase_type Type of erase operation to perform, 4KB, 32KB, 64KB, chip * @return Returns 'SUCCESS' (0) on successful erase, or 'FAILURE' (1) */ unsigned char qspi_flash_cntl_erase(unsigned int flash_addr, unsigned int flash_addr_width, unsigned int spi_mode, unsigned int erase_type) { unsigned int trans_stat; unsigned int idx = 0; qspi_params_t qspi_params = { 0, 0, 0, 0 }; /* Clear start transaction register */ flash_cntl->REG_START_TRANS = 0; /* Configure packet header */ qspi_params.params_ext_t.flash_addr_width = flash_addr_width; if (flash_addr_width == FLASH_24BIT_ADDR) { qspi_params.params_ext_t.flash_addr_LSB = flash_addr << 8; } else { qspi_params.params_ext_t.flash_addr_LSB = flash_addr; } qspi_params.params_ext_t.flash_addr_MSB = 0x00000000; if (spi_mode == FLASH_CNTL_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; } else if (spi_mode == FLASH_CNTL_EXTENDED_SPI_MODE || spi_mode == FLASH_CNTL_QSPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; } /* Single target support */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* No dummy cycles for flash program operations */ qspi_params.params_ext_t.num_wait_cycle = 0; if (flash_addr_width == FLASH_24BIT_ADDR) { flash_cntl->REG_QSPI_FLASH_CMD_CODE_4 = (OPCODE_3BYTE_BLOCK_ERASE_1 << 24) | (OPCODE_3BYTE_BLOCK_ERASE_2 << 16) | (OPCODE_3BYTE_BLOCK_ERASE_3 << 8) | (OPCODE_CHIP_ERASE << 0); } else if (flash_addr_width == FLASH_32BIT_ADDR) { flash_cntl->REG_QSPI_FLASH_CMD_CODE_4 = (OPCODE_4BYTE_BLOCK_ERASE_1 << 24) | (OPCODE_4BYTE_BLOCK_ERASE_2 << 16) | (OPCODE_4BYTE_BLOCK_ERASE_3 << 8) | (OPCODE_CHIP_ERASE << 0); } switch (erase_type) { case ERASE_TYPE_4K: qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_BLOCK_ERASE_TYPE_1; printf("INFO: Sending command: FLASH_CMD_CODE_BLOCK_ERASE_TYPE_1\r\n"); break; case ERASE_TYPE_32K: qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_BLOCK_ERASE_TYPE_2; printf("INFO: Sending command: FLASH_CMD_CODE_BLOCK_ERASE_TYPE_2\r\n"); break; case ERASE_TYPE_64K: qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_BLOCK_ERASE_TYPE_3; printf("INFO: Sending command: FLASH_CMD_CODE_BLOCK_ERASE_TYPE_3\r\n"); break; case ERASE_TYPE_CHIP: qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_CHIP_ERASE; printf("INFO: Sending command: FLASH_CMD_CODE_CHIP_ERASE\r\n"); break; default: qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_BLOCK_ERASE_TYPE_1; printf("INFO: Sending command: FLASH_CMD_CODE_BLOCK_ERASE_TYPE_1\r\n"); break; } /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(&qspi_params); /* Start transaction */ qspi_trans_start(); /* Clear start transaction register */ flash_cntl->REG_START_TRANS = CLR_START_TRANS; return RET_SUCCESS; } /** * @brief Writes the data to the flash memory with QSPI flash controller when FIFO is disable. * * This function is used to write/erase the data to the flash memory using Data Packet registers when fifo is disable. * * @param flash_addr Address in flash memory to be written to * @param flash_addr_width Width of address field to SPI flash (e.g. 3-bytes, 4-bytes) * @param buffer Pointer to the buffer containing data to be written. * @param buffer_len Length of the buffer in bytes * * @return Returns 'SUCCESS' (0) on successful write, or 'FAILURE' (1) if buffer is NULL */ unsigned char qspi_flash_cntl_write_fifo_dis( unsigned int flash_addr, unsigned int flash_addr_width, unsigned int spi_mode, unsigned int *buffer, unsigned int buffer_len) { unsigned int irq_sts = 0; unsigned int trans_stat; unsigned int idx = 0; qspi_params_t qspi_params = { 0, 0, 0, 0 }; unsigned int *buf_ptr = (unsigned int *) buffer; if ( buffer == NULL ) { return RET_FAILURE; } /* Clear start transaction register */ flash_cntl->REG_START_TRANS = 0; /* Configure packet header */ qspi_params.params_ext_t.flash_addr_width = flash_addr_width; if (flash_addr_width == FLASH_24BIT_ADDR) { qspi_params.params_ext_t.flash_addr_LSB = flash_addr << 8; } else { qspi_params.params_ext_t.flash_addr_LSB = flash_addr; } qspi_params.params_ext_t.flash_addr_MSB = 0x00000000; if (spi_mode == FLASH_CNTL_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_PAGE_PROGRAM; printf("INFO: Sending command: FLASH_CMD_CODE_PAGE_PROGRAM\r\n"); } else if (spi_mode == FLASH_CNTL_QSPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_QUAD_INPUT_FAST_PROGRAM; printf("INFO: Sending command: FLASH_CMD_CODE_EXTENDED_QUAD_INPUT_FAST_PROGRAM\r\n"); } else if (spi_mode == FLASH_CNTL_EXTENDED_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_EXTENDED_QUAD_INPUT_FAST_PROGRAM; printf("INFO: Sending command: FLASH_CMD_CODE_EXTENDED_QUAD_INPUT_FAST_PROGRAM\r\n"); } /* No dummy cycles for flash program operations */ qspi_params.params_ext_t.num_wait_cycle = 0; qspi_params.params_ext_t.buff_length = buffer_len; /* Write data is the payload */ qspi_params.params_ext_t.with_payload = 1; /* Single target support */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(&qspi_params); flash_cntl->REG_INT_STATUS = (INT_REG_WR_PKT_DATA_0_EMPTY | INT_REG_WR_PKT_DATA_1_EMPTY); // clear interrupts /* Start transaction */ qspi_trans_start(); while ( idx < (qspi_params.params_ext_t.buff_length/sizeof(unsigned int)) ) { flash_cntl->REG_PACKET_DATA_0 = buf_ptr[idx]; // write the data flash_cntl->REG_PACKET_DATA_1 = buf_ptr[idx+1]; do { reg_32b_read((unsigned int)(&(flash_cntl->REG_INT_STATUS)), &irq_sts); } while ( !(irq_sts & INT_REG_WR_PKT_DATA_0_EMPTY) || !(irq_sts & INT_REG_WR_PKT_DATA_1_EMPTY) ); flash_cntl->REG_INT_STATUS = (INT_REG_WR_PKT_DATA_0_EMPTY | INT_REG_WR_PKT_DATA_1_EMPTY); // clear interrupts idx = idx + 2; } /* Clear start transaction register */ flash_cntl->REG_START_TRANS = CLR_START_TRANS; return RET_SUCCESS; } /** * @brief Function to convert Big Endian to Little Endian (32bit). * * This function is used to convert 32 bit data from Big Endian to Little Endian. * * @param input Data input. * @return Little Endian as return data * */ unsigned int convert_endian(unsigned int input) { return (((input & 0xFF) << 24) | ((input & 0xFF00) << 8) | ((input >> 8) & 0xFF00) | (input >> 24)); } /** * @brief Reads data from the flash memory with QSPI flash controller when FIFO is disabled. * * This function is used to read the data from the flash memory using Data Packet register when fifo is disable. * * @param flash_addr Starting flash address to read from. * @param flash_addr_width Width of the flash address. * @param spi_mode SPI mode to use (Dual,Quad). * @param *buffer Pointer to the buffer to store the read data. * @param buffer_len Buffer length in Header 0. * @param manufacturer_id Manufacturer ID. * @return Returns 'SUCCESS' (0) on successful write, or 'FAILURE' (1) if 'buffer' is NULL. * */ unsigned char qspi_flash_cntl_read_fifo_dis( unsigned int flash_addr, unsigned int flash_addr_width, unsigned int spi_mode, unsigned int *buffer, unsigned int buffer_len, unsigned int manufacturer_id) { unsigned int len = 0; unsigned int trans_stat; uint32_t temp_read; if (buffer == NULL) return RET_FAILURE; qspi_params_t qspi_params = { 0, 0, 0, 0 }; flash_cntl->REG_START_TRANS = 0; /* Configure packet header */ qspi_params.params_ext_t.flash_addr_width = flash_addr_width; if (flash_addr_width == FLASH_24BIT_ADDR) { qspi_params.params_ext_t.flash_addr_LSB = flash_addr << 8; } else { qspi_params.params_ext_t.flash_addr_LSB = flash_addr; } qspi_params.params_ext_t.flash_addr_MSB = 0x00000000; if (spi_mode == FLASH_CNTL_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_FAST_READ; printf("INFO: Sending command: FLASH_CMD_CODE_FAST_READ\r\n"); /* 8 dummy clock cycles for basic Fast Read command */ qspi_params.params_ext_t.num_wait_cycle = 8; } else if (spi_mode == FLASH_CNTL_QSPI_MODE) { /* _________________________________ * | Manufacturer | Cmd Lane Width | * |--------------|----------------| * | Winbond | LANE_WIDTH_X1 | * | Macronix | LANE_WIDTH_X4 | * | Micron | LANE_WIDTH_X4 | * --------------------------------- */ if (manufacturer_id == JEDEC_MANUFACTURER_ID_WINBOND) qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; else qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_QUAD_INPUT_OUTPUT_FAST_READ; printf("INFO: Sending command: FLASH_CMD_CODE_QUAD_INPUT_OUTPUT_FAST_READ\r\n"); /* 6 dummy clock cycles (winbond) for Quad I/O Fast Read */ qspi_params.params_ext_t.num_wait_cycle = 6; } qspi_params.params_ext_t.buff_length = buffer_len; qspi_params.params_ext_t.with_payload = 0; /* Single flash target */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; /* Write packet headers */ #if (DEBUG_EN == 1) printf("INFO: Quad I/O fast read packet header\n\r"); #endif qspi_flash_cntl_set_pkt_hdr(&qspi_params); /* Enable interrupt */ flash_cntl->REG_INT_ENABLE = INT_EN_VAL; /* Start SPI transaction*/ flash_cntl->REG_START_TRANS = START_TRANS_VAL; for (len = IDX_ZERO; len < ((buffer_len)>>REG_GAP); len++) { /* Check the interrupt */ while (((flash_cntl->REG_INT_STATUS >> SHIFT_FOUR) & CHECK_ONE) == IRQ_RD_FIFO_DIS); /* Clear interrupt */ flash_cntl->REG_INT_STATUS = CLR_INTERRUPT; reg_32b_read(&(flash_cntl->REG_PACKET_DATA_0), &temp_read); #if (DEBUG_EN == 1) printf("INFO: flash_cntl->REG_PACKET_DATA_0: 0x%x \r\n",temp_read); #endif /* Check data endianess and store the data from DATA_0 */ #ifndef USE_BIG_ENDIAN *(buffer+len) = temp_read; #else *(buffer+len) = convert_endian(temp_read); #endif } /* Checking transaction status */ do { trans_stat = flash_cntl->REG_TRANS_STATUS; } while (trans_stat & (1 << 4)); /* Clear transaction bit */ flash_cntl->REG_START_TRANS = 0; return RET_SUCCESS; } /** * @brief Set Packet Header for QSPI Flash Controller Transaction. * * This function set the packet header registers based on the provided parameters. * * @param this_pkt_hdr Pointer to the structure qspi_params_t containing the desired variables. * */ void qspi_flash_cntl_set_pkt_hdr(qspi_params_t *this_pkt_hdr) { flash_cntl->REG_PACKET_HDR_0 = this_pkt_hdr->params_reg_t.packet_header0; flash_cntl->REG_PACKET_HDR_1 = this_pkt_hdr->params_reg_t.packet_header1; flash_cntl->REG_PACKET_HDR_2 = this_pkt_hdr->params_reg_t.packet_header2; flash_cntl->REG_PACKET_HDR_3 = this_pkt_hdr->params_reg_t.packet_header3; #if (DEBUG_EN == 1) printf("REG_PACKET_HDR_0 0x%X\r\n",this_pkt_hdr->params_reg_t.packet_header0); printf("REG_PACKET_HDR_1 0x%X\r\n",this_pkt_hdr->params_reg_t.packet_header1); printf("REG_PACKET_HDR_2 0x%X\r\n",this_pkt_hdr->params_reg_t.packet_header2); printf("REG_PACKET_HDR_3 0x%X\r\n\n",this_pkt_hdr->params_reg_t.packet_header3); #endif } /** * @brief - Set up and transmit data to the QSPI flash controller TX FIFO. * * This Function configure the TX FIFO for the write/erase and read apis when fifo is enabled. * * @param this_tx_fifo Pointer to the structure qspi_params_t containing the desired variables. */ void qspi_flash_cntl_set_tx_fifo(qspi_params_t *this_tx_fifo) { flash_cntl->REG_TX_FIFO_MAP = this_tx_fifo->params_reg_t.packet_header0; flash_cntl->REG_TX_FIFO_MAP = this_tx_fifo->params_reg_t.packet_header1; flash_cntl->REG_TX_FIFO_MAP = this_tx_fifo->params_reg_t.packet_header2; } unsigned char quad_mode(unsigned short en_mode) { unsigned int trans_stat; qspi_params_t qspi_params = { 0, 0, 0, 0 }; flash_cntl->REG_START_TRANS = 0; /* configure packet header */ qspi_params.params_ext_t.flash_addr_width = FLASH_NO_ADDR; // single byte command, no address if (en_mode == 1) { printf("INFO: Enter quad_mode\n\r"); flash_cntl->REG_QSPI_FLASH_CMD_CODE_7 = FLASH_CMD_CODE_7_REG_CMD_QUAD_EN; qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; // no point in having a quad mode version qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; } else { printf("INFO: Exit quad_mode\n\r"); flash_cntl->REG_QSPI_FLASH_CMD_CODE_7 = FLASH_CMD_CODE_7_REG_CMD_QUAD_RST; qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X4; // always send as quad command qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; } qspi_params.params_ext_t.mult_flash_tgt = 0; // single target support qspi_params.params_ext_t.num_wait_cycle = 0; // no dummy cycles for flash program operations qspi_params.params_ext_t.supp_flash_cmd = 1; // supported command if (en_mode == 1) qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_ENTER_QUAD_INPUT_OUTPUT_MODE; else qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_EXIT_QUAD_INPUT_OUTPUT_MODE; qspi_params.params_ext_t.buff_length = 0; /* Write packet headers */ #if (DEBUG_EN == 1) printf("INFO: Quad_mode packet header\n\r"); #endif qspi_flash_cntl_set_pkt_hdr(&qspi_params); /* Start SPI transaction*/ qspi_trans_start(); return RET_SUCCESS; } /** * @brief Write Enable (WREN) command: WREN command is required to set the Write Enable Latch bit (WEL) before other commands to change data * * @param spi_mode SPI mode to use. * @param en_mode 0: Exit 4-byte mode 1: Enter 4-byte mode * @return Returns 'SUCCESS' (0) on successful erase, or 'FAILURE' (1) */ unsigned char latch_set_clear(unsigned short spi_mode, unsigned short en_mode) { unsigned int trans_stat; qspi_params_t qspi_params = { 0, 0, 0, 0 }; flash_cntl->REG_START_TRANS = 0; if (spi_mode == FLASH_CNTL_SPI_MODE || spi_mode == FLASH_CNTL_EXTENDED_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; } else { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; } /* Single byte command, no address */ qspi_params.params_ext_t.flash_addr_width = FLASH_NO_ADDR; /* Single target support */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* No dummy cycles for flash program operations */ qspi_params.params_ext_t.num_wait_cycle = 0; /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; if (en_mode == 1) { printf("INFO: Sending command: FLASH_CMD_CODE_WRITE_ENABLE \r\n"); qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_WRITE_ENABLE; } else { printf("INFO: Sending command: FLASH_CMD_CODE_WRITE_DISBLE \r\n"); qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_WRITE_DISABLE; } qspi_params.params_ext_t.buff_length = 0; /* Write packet headers */ #if (DEBUG_EN == 1) printf("INFO: Latch_set_clear packet header\n\r"); #endif qspi_flash_cntl_set_pkt_hdr(&qspi_params); /* Start SPI transaction*/ qspi_trans_start(); return RET_SUCCESS; } /** * @brief Send the enter 4 byte addressing mode command * * @param spi_mode SPI mode to use. * @param en_mode 0: Exit 4-byte mode 1: Enter 4-byte mode * @return Returns 'SUCCESS' (0) on successful erase, or 'FAILURE' (1) */ unsigned char four_byte_mode(unsigned short spi_mode, unsigned short en_mode) { unsigned int trans_stat; qspi_params_t qspi_params = { 0, 0, 0, 0 }; latch_set_clear(spi_mode, 1); flash_cntl->REG_START_TRANS = 0; if (spi_mode == FLASH_CNTL_SPI_MODE || spi_mode == FLASH_CNTL_EXTENDED_SPI_MODE) { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X1; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X1; } else { qspi_params.params_ext_t.cmd_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.addr_lane_width = LANE_WIDTH_X4; qspi_params.params_ext_t.data_lane_width = LANE_WIDTH_X4; } /* Single byte command, no address */ qspi_params.params_ext_t.flash_addr_width = FLASH_NO_ADDR; /* Single target support */ qspi_params.params_ext_t.mult_flash_tgt = 0; /* No dummy cycles for flash program operations */ qspi_params.params_ext_t.num_wait_cycle = 0; /* Supported command */ qspi_params.params_ext_t.supp_flash_cmd = 1; if (en_mode == 1) { printf("INFO: Sending command: FLASH_CMD_CODE_ENTER_4_BYTE_ADDRESS_MODE \r\n"); qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_ENTER_4_BYTE_ADDRESS_MODE; } else { printf("INFO: Sending command: FLASH_CMD_CODE_EXIT_4_BYTE_ADDRESS_MODE \r\n"); qspi_params.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_EXIT_4_BYTE_ADDRESS_MODE; } qspi_params.params_ext_t.buff_length = 0; /* Write packet headers */ #if (DEBUG_EN == 1) printf("INFO: Four_byte_mode packet header\n\r"); #endif qspi_flash_cntl_set_pkt_hdr(&qspi_params); /* Start SPI transaction*/ qspi_trans_start(); latch_set_clear(spi_mode, 0); return RET_SUCCESS; } /** * enable_xip_mode - Enable XiP Mode for the QSPI flash controller. * * @brief - This function sets up the necessary registers to enable XiP Mode for the QSPI flash controller. * * @param mode XiP mode (1 for enable, 0 for disable). * */ void enable_xip_mode(unsigned int mode) { unsigned int trans_sts = 1; unsigned int temp_read; uint32_t data0, data1; qspi_params_t params_unsupp_t = { 0, 0, 0, 0 }; printf("INFO: Enabling XiP... \r\n"); flash_cntl->REG_START_TRANS = CLR_START_TRANS; /* Enable interrupt */ flash_cntl->REG_INT_ENABLE = INT_EN_VAL; /* Clear interrupt */ flash_cntl->REG_INT_STATUS = CLR_INTERRUPT; reg_32b_read((unsigned int)(&(flash_cntl->REG_QSPI_CONFIG_0)), &temp_read); /* Initiate a non-XiP generic transaction for the first Quad Input/Output Fast Read operation * with 8’hEB opcode to enable the XiP mode of the Winbond flash for the succeeding reads */ if (mode == ENABLE) { /* For Winbond */ params_unsupp_t.params_unsupp_t.supp_flash_cmd = 0; params_unsupp_t.params_unsupp_t.cmd_type = 1; params_unsupp_t.params_unsupp_t.lane_width = 0; params_unsupp_t.params_unsupp_t.data_rate = 0; params_unsupp_t.params_unsupp_t.frm_start = 1; params_unsupp_t.params_unsupp_t.frm_end = 0; params_unsupp_t.params_unsupp_t.multi_tgt = 0; params_unsupp_t.params_unsupp_t.tgt_cs = 0; params_unsupp_t.params_unsupp_t.num_wait_sck = 0; params_unsupp_t.params_unsupp_t.xfer_len_bytes = 1; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(¶ms_unsupp_t); if (temp_read & DATA_ENDIAN_BIT == 0x0) flash_cntl->REG_PACKET_DATA_0 = 0xEB; else flash_cntl->REG_PACKET_DATA_0 = 0xEB000000; flash_cntl->REG_PACKET_DATA_1 = 0x0; #if (DEBUG_EN == 1) print_config_reg(PRINT_ONLY_HDR_DATA); #endif /* Start SPI transaction*/ qspi_trans_start(); /* Clear start transaction register*/ flash_cntl->REG_START_TRANS = 0; params_unsupp_t.params_unsupp_t.supp_flash_cmd = 0; params_unsupp_t.params_unsupp_t.cmd_type = 1; params_unsupp_t.params_unsupp_t.lane_width = 2; params_unsupp_t.params_unsupp_t.data_rate = 0; params_unsupp_t.params_unsupp_t.frm_start = 0; params_unsupp_t.params_unsupp_t.frm_end = 0; params_unsupp_t.params_unsupp_t.multi_tgt = 0; params_unsupp_t.params_unsupp_t.tgt_cs = 0; params_unsupp_t.params_unsupp_t.num_wait_sck = 0; params_unsupp_t.params_unsupp_t.xfer_len_bytes = 4; flash_cntl->REG_PACKET_DATA_0 = 0x0; flash_cntl->REG_PACKET_DATA_1 = 0x0; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(¶ms_unsupp_t); #if (DEBUG_EN == 1) print_config_reg(PRINT_ONLY_HDR_DATA); #endif /* Start SPI transaction*/ qspi_trans_start(); /* Clear start transaction register*/ flash_cntl->REG_START_TRANS = 0; params_unsupp_t.params_unsupp_t.supp_flash_cmd = 0; params_unsupp_t.params_unsupp_t.cmd_type = 1; params_unsupp_t.params_unsupp_t.lane_width = 2; params_unsupp_t.params_unsupp_t.data_rate = 0; params_unsupp_t.params_unsupp_t.frm_start = 0; params_unsupp_t.params_unsupp_t.frm_end = 0; params_unsupp_t.params_unsupp_t.multi_tgt = 0; params_unsupp_t.params_unsupp_t.tgt_cs = 0; params_unsupp_t.params_unsupp_t.num_wait_sck = 4; params_unsupp_t.params_unsupp_t.xfer_len_bytes = 1; if (temp_read & DATA_ENDIAN_BIT == 0x0) flash_cntl->REG_PACKET_DATA_0 = 0xA5; else flash_cntl->REG_PACKET_DATA_0 = 0xA5000000; flash_cntl->REG_PACKET_DATA_1 = 0x0; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(¶ms_unsupp_t); #if (DEBUG_EN == 1) print_config_reg(PRINT_ONLY_HDR_DATA); #endif /* Start SPI transaction*/ qspi_trans_start(); /* Clear start transaction register*/ flash_cntl->REG_START_TRANS = 0; params_unsupp_t.params_unsupp_t.supp_flash_cmd = 0; params_unsupp_t.params_unsupp_t.cmd_type = 0; params_unsupp_t.params_unsupp_t.lane_width = 2; params_unsupp_t.params_unsupp_t.data_rate = 0; params_unsupp_t.params_unsupp_t.frm_start = 0; params_unsupp_t.params_unsupp_t.frm_end = 1; params_unsupp_t.params_unsupp_t.multi_tgt = 0; params_unsupp_t.params_unsupp_t.tgt_cs = 0; params_unsupp_t.params_unsupp_t.num_wait_sck = 0; params_unsupp_t.params_unsupp_t.xfer_len_bytes = 4; flash_cntl->REG_PACKET_DATA_0 = 0x0; flash_cntl->REG_PACKET_DATA_1 = 0x0; /* Write packet headers */ qspi_flash_cntl_set_pkt_hdr(¶ms_unsupp_t); #if (DEBUG_EN == 1) print_config_reg(PRINT_ONLY_HDR_DATA); #endif /* Start SPI transaction*/ qspi_trans_start(); /* Clear start transaction register*/ flash_cntl->REG_START_TRANS = 0; printf("INFO: Checking rx_fifo_empty_int_stat interrupt...\r\n"); /* Check the interrupt */ do { reg_32b_read((unsigned int)(&(flash_cntl->REG_INT_STATUS)), &temp_read); } while (((temp_read >> SHIFT_FOUR) & CHECK_ONE) == IRQ_RD_FIFO_DIS); /* Clear interrupt */ flash_cntl->REG_INT_STATUS = CLR_INTERRUPT; reg_32b_read((unsigned int)(&(flash_cntl->REG_PACKET_DATA_0)), &temp_read); } else { /* Disabling the XiP mode is same with enabling steps with xfer_len_bytes changed to 16’h6 * since command will not be sent during XiP enabled access and the * 2-byte pattern will change to 16’hAA55 or 16’hFF00 */ flash_cntl->REG_PACKET_HDR_0 = PKT_HDR_0_XIP_DISABLE; flash_cntl->REG_PACKET_DATA_1 = PKT_DATA_0_XIP_DISABLE; } /*Enable XiP bit in trans register*/ if (mode == ENABLE) { printf("INFO: Enabling ENABLE_XIP_TRANS_BIT in REG_START_TRANS\r\n"); flash_cntl->REG_START_TRANS = ENABLE_XIP_TRANS_BIT; } } /** * qspi_flash_cntl_read_write_config_reg - Read/Write SPI flash configuration registers. * * @brief - This function provide the interface to Read/Write SPI flash configuration registers. * * @param mode Read = 0, Write = 1 * @param config Config value to write in DATA0 * */ void qspi_flash_cntl_read_write_config_reg(unsigned short mode, unsigned int config){ qspi_params_t this_pkt_hdr = { 0, 0, 0, 0 }; unsigned int temp_data; unsigned int irq_sts; #if (DEBUG_EN == 1) printf("INFO: flash_cntl->REG_QSPI_CONFIG_0 0x%x\r\n",flash_cntl->REG_QSPI_CONFIG_0); printf("INFO: flash_cntl->REG_QSPI_CONFIG_1 0x%x\r\n",flash_cntl->REG_QSPI_CONFIG_1); #endif this_pkt_hdr.params_ext_t.cmd_lane_width = LANE_WIDTH_X1; this_pkt_hdr.params_ext_t.addr_lane_width = LANE_WIDTH_X1; this_pkt_hdr.params_ext_t.data_lane_width = LANE_WIDTH_X1; this_pkt_hdr.params_ext_t.buff_length = 1; this_pkt_hdr.params_ext_t.mult_flash_tgt = 0; this_pkt_hdr.params_ext_t.num_wait_cycle = 0; this_pkt_hdr.params_ext_t.supp_flash_cmd = 1; flash_cntl->REG_START_TRANS = CLR_START_TRANS; if (mode == WRITE_MODE) { flash_cntl->REG_QSPI_FLASH_CMD_CODE_5 = (WRITE_EN_CMD_CODE | WRITE_DIS_CMD_CODE | WRITE_STS_CONFIG_REG_CMD_CODE | PAGE_PROG_CMD_CODE);; this_pkt_hdr.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_WRITE_STATUS_CONFIG_REGISTER;; this_pkt_hdr.params_ext_t.with_payload = 1; flash_cntl->REG_PACKET_DATA_0 = config; } else { this_pkt_hdr.params_ext_t.flash_cmd_code = FLASH_CMD_CODE_READ_STATUS_REGISTER_2;//0x1; this_pkt_hdr.params_ext_t.with_payload = 0; } qspi_flash_cntl_set_pkt_hdr(&this_pkt_hdr); /* Start SPI transaction */ qspi_trans_start(); if (mode == READ_MODE) { /* check the interrupt */ do { reg_32b_read((unsigned int)(&(flash_cntl->REG_INT_STATUS)), &irq_sts); } while ( !(irq_sts & (INT_REG_RD_PKT_DATA_0_NOT_EMPTY)) ); /* clear the interrupt */ flash_cntl->REG_INT_STATUS = (INT_REG_RD_PKT_DATA_0_NOT_EMPTY); } flash_cntl->REG_INT_STATUS = CLR_INTERRUPT; flash_cntl->REG_START_TRANS = CLR_START_TRANS; }