/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2020 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"ifc.h" #include"hal.h" void ifc_isr(struct ifc_instance *this_ifc) { uint8_t fifo_status; uint8_t int_status; if (NULL == this_ifc) { return; } reg_8b_read(this_ifc->base_addr | INT_STATUS, &int_status); if (int_status & TRANS_DONE) { reg_32b_write(this_ifc->base_addr | INT_STATUS, TRANS_DONE); this_ifc->status = IFC_IDLE; } } static uint8_t ifc_fifo_reset(struct ifc_instance *this_ifc, uint8_t fifo) { if (NULL == this_ifc) { return PTR_ERROR; } reg_32b_write(this_ifc->base_addr | FIFO_CTRL, fifo); //Flush fifos return SUCCESS; } uint8_t ifc_status_get(struct ifc_instance * this_ifc, uint8_t * status) { if (this_ifc == NULL) return PTR_ERROR; *status = this_ifc->status; return SUCCESS; } uint8_t ifc_cfg_page_write(struct ifc_instance * this_ifc, uint8_t cfg_num, uint32_t * wr_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t data_sent; uint32_t idx; uint8_t words_num; uint8_t depth_32b; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_WRITE_ERROR; //max for write access } if (!((cfg_num == CFG0) || (cfg_num == CFG1) || (cfg_num == CFG2))) { return CFG_ACCESS_FAILED; } depth_32b = this_ifc->wr_fifo_depth * 4; //fifo depth in bytes data_sent = (this_ifc->wr_fifo_depth - this_ifc->wr_fifo_aempty_flag) * 4; //number of bytes written when the fifo is almost empty addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (cfg_num << 24) | addr_offest); ifc_fifo_reset(this_ifc, WR_FIFO_FLUSH); if (length <= this_ifc->wr_fifo_depth) //all the data to be written is sent before starting the write access { for (int i = 0; i < length; i++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, wr_buf[i]); } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans } else //not all the data is sent before starting the write accss { for (idx = 0; idx < depth_32b; idx++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans while (idx < length) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); if (fifo_status & WR_FIFO_AEMPTY) //continue transferring the remaining data when the fifo is almost empty { reg_32b_write(this_ifc->base_addr | FIFO_STATUS, WR_FIFO_AEMPTY); for (; idx < data_sent; idx++) { if (idx == length) break; reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } } } } return SUCCESS; } uint8_t ifc_cfg_page_read(struct ifc_instance * this_ifc, uint8_t cfg_num, uint32_t * rd_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t idx = 0; uint8_t words_num; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (!((cfg_num == CFG0) || (cfg_num == CFG1) || (cfg_num == CFG2))) { return CFG_ACCESS_FAILED; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_READ_ERROR; //max for read access } addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (cfg_num << 24) | addr_offest); //set the transaction partition ifc_fifo_reset(this_ifc, RD_FIFO_FLUSH); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | READ_ACCESS | (words_num << 4)); //start trans reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); while (fifo_status & RD_FIFO_EMPTY) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } while (!(fifo_status & RD_FIFO_EMPTY)) //continuously read 4 bytes of data until fifo is empty { for (int i = 0; i < 4; i++) { reg_32b_read(this_ifc->base_addr | RD_FIFO_DATA, &rd_buf[i]); idx++; if (idx == length) { break; } } reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } return SUCCESS; } uint8_t ifc_cfg_block_erase(struct ifc_instance * this_ifc, uint8_t cfg_num, uint32_t block) { uint32_t addr_offest; uint8_t fifo_status; uint8_t words_num; if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (NULL == this_ifc) { return PTR_ERROR; } if (!((cfg_num == CFG0) || (cfg_num == CFG1) || (cfg_num == CFG2))) { return CFG_ACCESS_FAILED; } addr_offest = block * BLOCK_SIZE; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (cfg_num << 24) | addr_offest); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | ERASE_ACCESS); //start erase this_ifc->status = IFC_BUSY; //unable to operate IFC during erase return SUCCESS; } uint8_t ifc_ufm_page_write(struct ifc_instance * this_ifc, uint8_t ufm_num, uint32_t * wr_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t data_sent; uint32_t idx; uint8_t words_num; uint8_t depth_32b; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_WRITE_ERROR; } if (!((ufm_num == UFM0) || (ufm_num == UFM1) || (ufm_num == UFM2))) { return UFM_ACCESS_FAILED; } depth_32b = this_ifc->wr_fifo_depth * 4; //fifo depth in bytes data_sent = (this_ifc->wr_fifo_depth - this_ifc->wr_fifo_aempty_flag) * 4; //number of bytes written when the memory is almost empty addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (ufm_num << 24) | addr_offest); ifc_fifo_reset(this_ifc, WR_FIFO_FLUSH); if (length <= this_ifc->wr_fifo_depth) //all the data to be written is sent before starting the write access { for (int i = 0; i < length; i++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, wr_buf[i]); } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans } else //not all the data is sent before starting the write accss { for (idx = 0; idx < depth_32b; idx++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans while (idx < length) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); if (fifo_status & WR_FIFO_AEMPTY) //continue transferring the remaining data when the memory is almost empty { reg_32b_write(this_ifc->base_addr | FIFO_STATUS, WR_FIFO_AEMPTY); for (; idx < data_sent; idx++) { if (idx == length) break; reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } } } } return SUCCESS; } uint8_t ifc_ufm_page_read(struct ifc_instance * this_ifc, uint8_t ufm_num, uint32_t * rd_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t idx = 0; uint8_t words_num; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (!((ufm_num == UFM0) || (ufm_num == UFM1) || (ufm_num == UFM2))) { return UFM_ACCESS_FAILED; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_READ_ERROR; //max for read access } addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (ufm_num << 24) | addr_offest); //set the transaction partition ifc_fifo_reset(this_ifc, RD_FIFO_FLUSH); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | READ_ACCESS | (words_num << 4)); //start trans reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); while (fifo_status & RD_FIFO_EMPTY) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } while (!(fifo_status & RD_FIFO_EMPTY)) //continuously read 4 bytes of data until fifo is empty { for (int i = 0; i < 4; i++) { reg_32b_read(this_ifc->base_addr | RD_FIFO_DATA, &rd_buf[i]); idx++; if (idx == length) { break; } } reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } return SUCCESS; } uint8_t ifc_ufm_block_erase(struct ifc_instance * this_ifc, uint8_t ufm_num, uint32_t block) { uint32_t addr_offest; uint32_t fifo_status; uint8_t words_num; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (!((ufm_num == UFM0) || (ufm_num == UFM1) || (ufm_num == UFM2))) { return UFM_ACCESS_FAILED; } addr_offest = block * BLOCK_SIZE; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (ufm_num << 24) | addr_offest); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | ERASE_ACCESS); //start erase this_ifc->status = IFC_BUSY; ////unable to operate IFC during erase return SUCCESS; } uint8_t ifc_userdata_page_write(struct ifc_instance * this_ifc, uint8_t userdata_num, uint32_t * wr_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t data_sent; uint32_t idx; uint8_t words_num; uint8_t depth_32b; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_WRITE_ERROR; } if (userdata_num > MAX_USERDATA_NUM || userdata_num < MIN_USERDATA_NUM) { return USERDATA_ACCESS_FAILED; } depth_32b = this_ifc->wr_fifo_depth * 4; //fifo depth in bytes data_sent = (this_ifc->wr_fifo_depth - this_ifc->wr_fifo_aempty_flag) * 4; //number of bytes written when the memory is almost empty addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (userdata_num << 24) | addr_offest); ifc_fifo_reset(this_ifc, WR_FIFO_FLUSH); if (length <= this_ifc->wr_fifo_depth) //all the data to be written is sent before starting the write access { for (int i = 0; i < length; i++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, wr_buf[i]); } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans } else //not all the data is sent before starting the write accss { for (idx = 0; idx < depth_32b; idx++) { reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | WRITE_ACCESS | (words_num << 4)); //start trans while (idx < length) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); if (fifo_status & WR_FIFO_AEMPTY) //continue transferring the remaining data when the memory is almost empty { reg_32b_write(this_ifc->base_addr | FIFO_STATUS, WR_FIFO_AEMPTY); for (; idx < data_sent; idx++) { if (idx == length) break; reg_32b_write(this_ifc->base_addr | WR_FIFO_DATA, *wr_buf); wr_buf++; } } } } return SUCCESS; } uint8_t ifc_userdata_page_read(struct ifc_instance * this_ifc, uint8_t userdata_num, uint32_t * rd_buf, uint32_t length, uint32_t page) { uint32_t addr_offest; uint32_t fifo_status; uint32_t idx = 0; uint8_t words_num; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (page > PAGE_SIZE) { return PAGE_NUM_ERROR; //max page num } if (length > PAGE_SIZE || length < MIN_WORDS_NUM) { return PAGE_READ_ERROR; } if (userdata_num > MAX_USERDATA_NUM || userdata_num < MIN_USERDATA_NUM) { return USERDATA_ACCESS_FAILED; } addr_offest = page * PAGE_SIZE; words_num = length / 4 - 1; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (userdata_num << 24) | addr_offest); //set the transaction partition ifc_fifo_reset(this_ifc, RD_FIFO_FLUSH); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | READ_ACCESS | (words_num << 4)); //start trans reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); while (fifo_status & RD_FIFO_EMPTY) { reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } while (!(fifo_status & RD_FIFO_EMPTY)) //continuously read 4 bytes of data until fifo is empty { for (int i = 0; i < 4; i++) { reg_32b_read(this_ifc->base_addr | RD_FIFO_DATA, &rd_buf[i]); idx++; if (idx == length) { break; } } reg_32b_read(this_ifc->base_addr | FIFO_STATUS, &fifo_status); } return SUCCESS; } uint8_t ifc_userdata_block_erase(struct ifc_instance * this_ifc, uint8_t userdata_num, uint32_t block) { uint32_t addr_offest; uint32_t fifo_status; uint8_t words_num; if (NULL == this_ifc) { return PTR_ERROR; } if (this_ifc->status == IFC_BUSY) { return STATUS_ERROR; } if (userdata_num > MAX_USERDATA_NUM || userdata_num < MIN_USERDATA_NUM) { return USERDATA_ACCESS_FAILED; } addr_offest = block * BLOCK_SIZE; reg_32b_write(this_ifc->base_addr | TRANSACTION_ADDR, (userdata_num << 24) | addr_offest); reg_32b_write(this_ifc->base_addr | TRANSACTION_CTRL, START_TRANSACTION | ERASE_ACCESS); //start erase this_ifc->status = IFC_BUSY; ////unable to operate IFC during erase return SUCCESS; } static uint8_t boundary_check(struct ifc_instance *this_ifc) { uint8_t size; if (NULL == this_ifc) { return PTR_ERROR; } for (uint8_t i = 0; i < MAX_CFG_NUM; i++) { if ((this_ifc->cfg_size[i] != CFG_SIZE_1) && (this_ifc->cfg_size[i] != CFG_SIZE_2) && (this_ifc->cfg_size[i] != CFG_SIZE_3)) { return CFG_ERROR; } //cfg size value check if ((this_ifc->ufm_size[i] != UFM_SIZE_1) && (this_ifc->ufm_size[i] != UFM_SIZE_2)) { return UFM_ERROR; } //ufm size value check size = this_ifc->cfg_size[i] + this_ifc->ufm_size[i]; if (size > MAX_CFG_UFM_SIZE) { return CFG_UFM_ERROR; } //cfgx+ufmx size check } for (uint8_t i = 0; i < MAX_USERDATA_NUM; i++) { if (this_ifc->userdata_size[i] > MAX_USERDATA_SIZE) { return USERDATA_ERROR; } //userdata size value check } return SUCCESS; } uint8_t ifc_config(struct ifc_instance * this_ifc, uint8_t int_enable) { if (NULL == this_ifc) { return PTR_ERROR; } reg_32b_write(this_ifc->base_addr | INT_ENABLE, int_enable); //enable interrupt return SUCCESS; } uint8_t ifc_init(struct ifc_instance * this_ifc, uint32_t base_address, uint32_t * memory_map, IFC_FIFO_DEPTH wr_fifo_depth, uint8_t wr_fifo_aempty_flag) { int status; if (NULL == this_ifc) { return PTR_ERROR; } if (wr_fifo_aempty_flag < MIN_AEMPTY_FLAG || wr_fifo_aempty_flag > (wr_fifo_depth - 1)) { return FIFO_ERROR; } this_ifc->base_addr = base_address; this_ifc->cfg_size[0] = memory_map[0]; this_ifc->ufm_size[0] = memory_map[1]; this_ifc->cfg_size[1] = memory_map[2]; this_ifc->ufm_size[1] = memory_map[3]; this_ifc->cfg_size[2] = memory_map[4]; this_ifc->ufm_size[2] = memory_map[5]; for (int i = 0; i < MAX_USERDATA_NUM; i++) { this_ifc->userdata_size[i] = memory_map[6 + i]; } this_ifc->wr_fifo_depth = wr_fifo_depth; this_ifc->wr_fifo_aempty_flag = wr_fifo_aempty_flag; status = boundary_check(this_ifc); return status; }