![](/media/cache/profiles/854d9fca60b4bd07f9bb215d59ef5561.jpg.50x50_q85.jpg)
bug fix
Diff: qspi-blockdevice/QSPIFBlockDevice.cpp
- Revision:
- 0:6b753f761943
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qspi-blockdevice/QSPIFBlockDevice.cpp Fri Oct 12 21:22:49 2018 +0000 @@ -0,0 +1,1316 @@ + +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#include "./mbed-os/drivers/qspi.h" + +#define DEVICE_QSPI 1 + +#include "QSPIFBlockDevice.h" + +/* Default QSPIF Parameters */ +/****************************/ +#define QSPIF_DEFAULT_READ_SIZE 1 +#define QSPIF_DEFAULT_PROG_SIZE 1 +#define QSPIF_DEFAULT_SE_SIZE 4096 +#define QSPI_MAX_STATUS_REGISTER_SIZE 2 +#define QSPI_STATUS_REGISTER_WRITE_TIMEOUT_MSEC 50 +#define QSPIF_DEFAULT_TIMEOUT_MSEC 1 + + +/* SFDP Header Parsing */ +/***********************/ +#define QSPIF_SFDP_HEADER_SIZE 8 +#define QSPIF_PARAM_HEADER_SIZE 8 + +/* Basic Parameters Table Parsing */ +/**********************************/ +#define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */ +//READ Instruction support according to BUS Configuration +#define QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2 +#define QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPOR_BYTE 16 +#define QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE 27 +#define QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE 9 +#define QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE 11 +#define QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23 +#define QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15 +#define QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13 +#define QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40 +// Quad Enable Params +#define QSPIF_BASIC_PARAM_TABLE_QER_BYTE 58 +#define QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE 56 +// Erase Types Params +#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32 +#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34 +#define QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1 + +// Debug Printouts +#define QSPIF_DEBUG_ERROR 1 +#define QSPIF_DEBUG_WARNING 2 +#define QSPIF_DEBUG_INFO 3 +#define QSPIF_DEBUG_DEBUG 4 +#define QSPIF_DEBUG_TRACE 5 +// #define QSPIF_DEFAULT_DEBUG_LEVEL QSPIF_DEBUG_INFO +// #define QSPIF_DEFAULT_DEBUG_LEVEL QSPIF_DEBUG_TRACE +#define QSPIF_DEFAULT_DEBUG_LEVEL QSPIF_DEBUG_WARNING + + +enum qspif_default_instructions { + QSPIF_NOP = 0x00, // No operation + QSPIF_PP = 0x02, // Page Program data + QSPIF_READ = 0x03, // Read data + QSPIF_SE = 0x20, // 4KB Sector Erase + QSPIF_SFDP = 0x5a, // Read SFDP + + QSPIF_WRSR = 0x01, // Write Status/Configuration Register + QSPIF_WRDI = 0x04, // Write Disable + QSPIF_RDSR = 0x05, // Read Status Register + QSPIF_WREN = 0x06, // Write Enable + + QSPIF_RSTEN = 0x66, // Reset Enable + QSPIF_RST = 0x99, // Reset + QSPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID +}; + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define QSPIF_LOG(level,...) {\ + if (level <= QSPIF_DEFAULT_DEBUG_LEVEL) {\ + char str[256];\ + sprintf(str, "\n[%s][%s:%d], ", __FILENAME__, __FUNCTION__, __LINE__);\ + sprintf(str+strlen(str),__VA_ARGS__);\ + printf(str);\ + }\ + } + +// Mutex is used for some QSPI Driver commands that must be done sequentially with no other commands in between +// e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready +SingletonPtr<PlatformMutex> QSPIFBlockDevice::_mutex; + + +/********* Public API Functions *********/ +/****************************************/ + +QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, + int clock_mode, int freq) + : _qspi(io0, io1, io2, io3, sclk, csel, clock_mode), _deviceSizeBytes(0) +{ + //_cs = 1; + is_initialized = false; + _minCommonEraseSize = 0; + _regions_count = 1; + _region_erase_types[0] = 0; + + //Default Bus Setup 1_1_1 with 0 dummy and mode cycles + _inst_width = QSPI_CFG_BUS_SINGLE; + _address_width = QSPI_CFG_BUS_SINGLE; + _address_size = QSPI_CFG_ADDR_SIZE_24; + _alt_width = QSPI_CFG_BUS_SINGLE; + _alt_size = QSPI_CFG_ALT_SIZE_8; + _data_width = QSPI_CFG_BUS_SINGLE; + _dummy_and_mode_cycles = 0; + + if (QSPI_STATUS_OK != _qspiSetFrequency(freq)) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Set Frequency Failed"); + } +} + + +int QSPIFBlockDevice::init() +{ + + uint8_t vendor_device_ids[4]; + size_t data_length = 3; + + _mutex->lock(); + if (is_initialized == true) { + _mutex->unlock(); + return 0; + } + + // Soft Reset + if ( -1 == _resetFlashMem()) { + QSPIF_LOG(QSPIF_DEBUG_INFO, "ERROR: init - Unable to initialize flash memory, tests failed\n"); + return -1; + } else { + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO: Initialize flash memory OK\n"); + } + + + + /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/ + int status = _qspiSendReadCommand(QSPIF_RDID, (char *)vendor_device_ids, 0x0 /*address*/, data_length); + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Read Vendor ID Failed"); + return status; + } + + switch (vendor_device_ids[0]) { + case 0xbf: + // SST devices come preset with block protection + // enabled for some regions, issue write disable instruction to clear + _setWriteEnable(); + //_cmdwrite(0x98, 0, 0, 0x0, NULL); + _qspiSendGeneralCommand(QSPIF_WRDI, -1, NULL, 0, NULL, 0); + + break; + } + + //Synchronize Device + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - _isMemReady Failed"); + return BD_ERROR_DEVICE_ERROR; + } + + + /**************************** Parse SFDP Header ***********************************/ + uint32_t basic_table_addr = NULL; + size_t basic_table_size = 0; + uint32_t sector_map_table_addr = NULL; + size_t sector_map_table_size = 0; + if ( 0 != _sfdpParseSFDPHeaders(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Parse SFDP Headers Failed"); + return BD_ERROR_DEVICE_ERROR; + } + + + /**************************** Parse Basic Parameters Table ***********************************/ + if ( 0 != _sfdpParseBasicParamTable(basic_table_addr, basic_table_size) ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Parse Basic Param Table Failed"); + return BD_ERROR_DEVICE_ERROR; + } + + + /**************************** Parse Sector Map Table ***********************************/ + _region_size_bytes[0] = + _deviceSizeBytes; // If there's no region map, we have a single region sized the entire device size + _region_high_boundary[0] = _deviceSizeBytes - 1; + + if ( (sector_map_table_addr != NULL) && (0 != sector_map_table_size) ) { + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO: init - Parsing Sector Map Table - addr: 0x%xh, Size: %d", sector_map_table_addr, + sector_map_table_size); + if ( 0 != _sfdpParseSectorMapTable(sector_map_table_addr, sector_map_table_size) ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Parse Sector Map Table Failed"); + return BD_ERROR_DEVICE_ERROR; + } + } + + + // Configure BUS Mode to 1_1_1 for all commands other than Read + _qspiConfiureFormat( QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, + QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + /*// Soft Reset + if( -1 == _resetFlashMem()) { + QSPIF_LOG(QSPIF_DEBUG_INFO,"ERROR: init - Unable to initialize flash memory, tests failed\n"); + return -1; + } else { + QSPIF_LOG(QSPIF_DEBUG_INFO,"INFO: Initialize flash memory OK\n"); + }*/ + + is_initialized = true; + _mutex->unlock(); + + return 0; +} + +int QSPIFBlockDevice::deinit() +{ + _mutex->lock(); + if (is_initialized == false) { + _mutex->unlock(); + return 0; + } + qspi_status_t status = _qspiSendGeneralCommand(QSPIF_WRDI, -1, NULL, 0, NULL, 0); + int result = 0; + + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Write Disable failed"); + result = -1; + } + is_initialized = false; + _mutex->unlock(); + + return result; +} + + +int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) +{ + + + int status = 0; + + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO Inst: 0x%xh", _readInstruction); + + _mutex->lock(); + + _qspiConfiureFormat( + _inst_width, //Bus width for Instruction phase + _address_width, //Bus width for Address phase + _address_size, + _alt_width, //Bus width for Alt phase + _alt_size, + _data_width, //Bus width for Data phase + _dummy_and_mode_cycles); + //_qspiConfiureFormat( QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8); + + if (QSPI_STATUS_OK != _qspiSendReadCommand(_readInstruction, buffer, addr, size)) { + status = -1; + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Read failed\n"); + } + + // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus) + _qspiConfiureFormat( QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, + QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + + _mutex->unlock(); + return status; + +} + + + + +int QSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) +{ + qspi_status_t result = QSPI_STATUS_OK; + bool program_failed = false; + int status = 0; + uint32_t offset = 0; + uint32_t chunk = 0; + bd_size_t writtenBytes = 0; + + while (size > 0) { + + // Write on _pageSizeBytes boundaries (Default 256 bytes a page) + offset = addr % _pageSizeBytes; + chunk = (offset + size < _pageSizeBytes) ? size : (_pageSizeBytes - offset); + writtenBytes = chunk; + + _mutex->lock(); + + //Send WREN + if (_setWriteEnable() != 0) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Write Enabe failed\n"); + program_failed = true; + goto Exit_Point; + } + + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Device not ready, write failed\n"); + program_failed = true; + goto Exit_Point; + } + + result = _qspiSendProgramCommand(_progInstruction, buffer, addr, &writtenBytes); + if ( (result != QSPI_STATUS_OK) || (chunk != writtenBytes) ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Write failed"); + program_failed = true; + goto Exit_Point; + } + + buffer = static_cast<const uint8_t *>(buffer) + chunk; + addr += chunk; + size -= chunk; + + wait_ms(QSPIF_DEFAULT_TIMEOUT_MSEC); + + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Device not ready after write, failed\n"); + program_failed = true; + goto Exit_Point; + } + _mutex->unlock(); + + + } + +Exit_Point: + if (program_failed) { + _mutex->unlock(); + status = -1; + } + + return status; +} + + +int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t inSize) +{ + + int type = 0; + uint32_t chunk = 4096; + unsigned int curEraseInst = _eraseInstruction; + int size = (int)inSize; + bool erase_failed = false; + int status = 0; + // Find region of erased address + int region = _utilsFindAddrRegion((int)addr); + // Erase Types of selected region + uint8_t bitfield = _region_erase_types[region]; + + + while (size > 0) { + + // iterate to find next Largest erase type (1) supported by region, 2) smaller than size) + // find the matching instruction and erase size chunk for that type. + type = _utilsIterateNextLargestEraseType(bitfield, (int)size, (int)addr, _region_high_boundary[region]); + curEraseInst = _eraseTypeInstArr[type]; + chunk = _eraseTypeSizeArr[type]; + + QSPIF_LOG(QSPIF_DEBUG_DEBUG, " Debug: addr: 0x%xh, size:%d, Inst: 0x%xh, chunk: %d , ", + (int)addr, (int)size, curEraseInst, chunk); + + _mutex->lock(); + + if (_setWriteEnable() != 0) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Erase - Write Enable failed"); + erase_failed = true; + goto Exit_Point; + } + + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Erase Device not ready - failed"); + erase_failed = true; + goto Exit_Point; + } + + if (QSPI_STATUS_OK != _qspiSendEraseCommand(curEraseInst, addr, size) ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Erase command failed!"); + erase_failed = true; + goto Exit_Point; + } + + addr += chunk; + size -= chunk; + + if ( (size > 0) && (addr > _region_high_boundary[region]) ) { + // erase crossed to next region + region++; + bitfield = _region_erase_types[region]; + } + wait_ms(QSPIF_DEFAULT_TIMEOUT_MSEC); + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI After Erase Device not ready - failed\n"); + erase_failed = true; + goto Exit_Point; + } + _mutex->unlock(); + + } + + +Exit_Point: + if (erase_failed) { + _mutex->unlock(); + status = -1; + } + + return status; +} + + + +bd_size_t QSPIFBlockDevice::get_read_size() const +{ + return QSPIF_DEFAULT_READ_SIZE; +} + +bd_size_t QSPIFBlockDevice::get_program_size() const +{ + return QSPIF_DEFAULT_PROG_SIZE; +} + +bd_size_t QSPIFBlockDevice::get_erase_size() const +{ + return _minCommonEraseSize; +} + + +// Find minimal erase size supported by address region +bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr) +{ + // Find region of current address + int region = _utilsFindAddrRegion((int)addr); + + int minRegionEraseSize = _minCommonEraseSize; + int8_t type_mask = 0x01; + int i_ind = 0; + + if (region != -1) { + type_mask = 0x01; + + for (i_ind = 0; i_ind < 4; i_ind++) { + // loop through erase types supported by region + if (_region_erase_types[region] & type_mask) { + + minRegionEraseSize = _eraseTypeSizeArr[i_ind]; + break; + } + type_mask = type_mask << 1; + } + + if (i_ind == 4) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: no erase type was found for region addr"); + } + } + + return (bd_size_t)minRegionEraseSize; + +} + +bd_size_t QSPIFBlockDevice::size() const +{ + return _deviceSizeBytes; +} + + +/*********************************************************/ +/********** SFDP Parsing and Detection Functions *********/ +/*********************************************************/ + +int QSPIFBlockDevice::_sfdpParseSectorMapTable(uint32_t sector_map_table_addr, size_t sector_map_table_size) +{ + uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ + uint32_t tmpRegionSize = 0; + int i_ind = 0; + int prevBoundary = 0; + // Default set to all type bits 1-4 are common + _minCommonEraseType = 0x0F; + + qspi_status_t status = _qspiSendReadCommand(QSPIF_SFDP, (char *)sector_map_table, sector_map_table_addr /*address*/, + sector_map_table_size); + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Read SFDP First Table Failed"); + return -1; + } + + //QSPIF_LOG(QSPIF_DEBUG_DEBUG,\nDEBUG: "Read table: %x %x %x %x %x %x %x %x %x[56] %x[57] %x[58] %x[59] %x[52]\n",sector_map_table[0], + // sector_map_table[1], + // sector_map_table[2], + // sector_map_table[3], + // sector_map_table[4], + // sector_map_table[5], + // sector_map_table[6], + // sector_map_table[7], sector_map_table[56], sector_map_table[57], sector_map_table[58], sector_map_table[59], sector_map_table[52]); + + // Currently we support only Single Map Descriptor + if (! ( (sector_map_table[0] & 0x3) == 0x03 ) && (sector_map_table[1] == 0x0) ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Sector Map - Supporting Only Single! Map Descriptor (not map commands)"); + return -1; + } + + _regions_count = sector_map_table[2] + 1; + if (_regions_count > QSPIF_MAX_REGIONS) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Supporting up to %d regions, current setup to %d regions - fail", + QSPIF_MAX_REGIONS, _regions_count); + return -1; + } + + // Loop through Regions and set for each one: size, supported erase types, high boundary offset + // Calculate minimum Common Erase Type for all Regions + for (i_ind = 0; i_ind < _regions_count; i_ind++) { + tmpRegionSize = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32 + _region_size_bytes[i_ind] = (tmpRegionSize + 1) * 256; // Region size is 0 based multiple of 256 bytes; + _region_erase_types[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4 + _minCommonEraseType &= _region_erase_types[i_ind]; + _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prevBoundary; + prevBoundary = _region_high_boundary[i_ind] + 1; + } + + // Calc minimum Common Erase Size from _minCommonEraseType + uint8_t type_mask = 0x01; + for (i_ind = 0; i_ind < 4; i_ind++) { + if (_minCommonEraseType & type_mask) { + _minCommonEraseType = i_ind; + _minCommonEraseSize = _eraseTypeSizeArr[i_ind]; + break; + } + type_mask = type_mask << 1; + } + + if (i_ind == 4) { + // No common erase type was found between regions + _minCommonEraseType = 0; + _minCommonEraseSize = -1; + } + + return 0; +} + + +int QSPIFBlockDevice::_sfdpParseBasicParamTable(uint32_t basic_table_addr, size_t basic_table_size) +{ + uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ + + qspi_status_t status = _qspiSendReadCommand(QSPIF_SFDP, (char *)param_table, basic_table_addr /*address*/, + basic_table_size); + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Read SFDP First Table Failed, Status %d",status); + return -1; + } + + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Read table: %x %x %x %x %x %x %x %x %x[56] %x[57] %x[58] %x[59] %x[52]\n", + param_table[0], + param_table[1], + param_table[2], + param_table[3], + param_table[4], + param_table[5], + param_table[6], + param_table[7], param_table[56], param_table[57], param_table[58], param_table[59], param_table[52]); + + + // Check address size, currently only supports 3byte addresses + if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - verify 3byte addressing Failed"); + return -1; + } + + // Get device density (stored in bits - 1) + uint32_t density_bits = ( + (param_table[7] << 24) | + (param_table[6] << 16) | + (param_table[5] << 8 ) | + param_table[4] ); + _deviceSizeBytes = (density_bits + 1) / 8; + + // Set Default read/program/erase Instructions + _readInstruction = QSPIF_READ; + _progInstruction = QSPIF_PP; + _eraseInstruction = QSPIF_SE; + + // Set Page Size (QSPI write must be done on Page limits) + _pageSizeBytes = _sfdpDetectPageSize(param_table); + + // Detect and Set Erase Types + bool shouldSetQuadEnable = false; + bool isQPIMode = false; + _sfdpDetectEraseTypesInstAndSize(param_table, _erase4KInst, _eraseTypeInstArr, _eraseTypeSizeArr); + _eraseInstruction = _erase4KInst; + + + // Detect and Set fastest Bus mode (default 1-1-1) + _sfdpDetectBestBusReadMode(param_table, shouldSetQuadEnable, isQPIMode, _readInstruction); + + if (true == shouldSetQuadEnable) { + // Set Quad Enable and QPI Bus modes if Supported + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO: init - Setting Quad Enable"); + _sfdpSetQuadEnabled(param_table); + if (true == isQPIMode) { + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO: init - Setting QPI mode"); + _sfdpSetQPIEnabled(param_table); + } + } + return 0; +} + +int QSPIFBlockDevice::_sfdpParseSFDPHeaders(uint32_t& basic_table_addr, size_t& basic_table_size, + uint32_t& sector_map_table_addr, size_t& sector_map_table_size) +{ + uint8_t sfdp_header[QSPIF_SFDP_HEADER_SIZE]; + uint8_t param_header[QSPIF_PARAM_HEADER_SIZE]; + size_t data_length = QSPIF_SFDP_HEADER_SIZE; + bd_addr_t addr = 0x0; + + // Set 1-1-1 bus mode for SFDP header parsing + _qspiConfiureFormat( QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, + QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8); + + qspi_status_t status = _qspiSendReadCommand(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length); + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Read SFDP Failed"); + return -1; + } + + + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG11: Read SFDP Header: %x %x %x %x %x %x %x %x\n", sfdp_header[0], + sfdp_header[1], + sfdp_header[2], + sfdp_header[3], + sfdp_header[4], + sfdp_header[5], + sfdp_header[6], + sfdp_header[7]); + + + // Verify SFDP signature for sanity + // Also check that major/minor version is acceptable + if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - _verify SFDP signature and version Failed"); + return -1; + } else { + QSPIF_LOG(QSPIF_DEBUG_INFO, "INFO: init - verified SFDP Signature and version Successfully"); + } + + // Discover Number of Parameter Headers + int number_of_param_headers = (int)(sfdp_header[6]) + 1; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: number of Param Headers: %d", number_of_param_headers); + + + addr += QSPIF_SFDP_HEADER_SIZE; + data_length = QSPIF_PARAM_HEADER_SIZE; + + // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table) + for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) { + + status = _qspiSendReadCommand(QSPIF_SFDP, (char *)param_header, addr, data_length); + if (status != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: init - Read Param Table %d Failed", i_ind + 1); + return -1; + } + // The SFDP spec indicates the standard table is always at offset 0 + // in the parameter headers, we check just to be safe + if (param_header[2] != 1) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Param Table %d - Major Version should be 1!", i_ind + 1); + return -1; + } + + if ((param_header[0] == 0) && (param_header[7] == 0xFF)) { + // Found Basic Params Table: LSB=0x00, MSB=0xFF + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Found Basic Param Table at Table: %d", i_ind + 1); + basic_table_addr = ( (param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]) ); + // Supporting up to 64 Bytes Table (16 DWORDS) + basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[11] * 4) : 64; + + } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) { + // Found Sector Map Table: LSB=0x81, MSB=0xFF + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Found Sector Map Table at Table: %d", i_ind + 1); + sector_map_table_addr = ( (param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]) ); + + sector_map_table_size = param_header[3] * 4; + + } + addr += QSPIF_PARAM_HEADER_SIZE; + + } + return 0; +} + + + +int QSPIFBlockDevice::_sfdpSetQPIEnabled(uint8_t *basicParamTablePtr) +{ + uint8_t config_reg[1]; + + // QPI 4-4-4 Enable Procedure is specified in 5 Bits + uint8_t en_seq_444_value = ( ((basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE] & 0xF0) >> 4) | (( + basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE + 1] & 0x01) << 4 )); + + switch (en_seq_444_value) { + case 1: + case 2: + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _setQPIEnabled - send command 38h"); + /*if (_setWriteEnable() != 0) { + printf("ERROR: Write Enabe failed\n"); + return -1; + } + if( false == _isMemReady()) { + printf("ERROR: Device not ready, write failed\n"); + return -1; + }*/ + + _qspiSendGeneralCommand(0x38, -1, NULL, 0, NULL, 0); + /*wait_ms(QSPI_STATUS_REGISTER_WRITE_TIMEOUT_MSEC); + if( false == _isMemReady()) { + printf("ERROR: Device not ready after write, failed\n"); + return -1; + }*/ + + + break; + + case 4: + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _setQPIEnabled - send command 35h"); + _qspiSendGeneralCommand(0x35, -1, NULL, 0, NULL, 0); + break; + + case 8: + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _setQPIEnabled - set config bit 6 and send command 71h"); + _qspiSendGeneralCommand(0x65, 0x800003, NULL, 0, (char *)config_reg, 1); + config_reg[1] |= 0x40; //Set Bit 6 + _qspiSendGeneralCommand(0x71, 0x800003, NULL, 0, (char *)config_reg, 1); + break; + + case 16: + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _setQPIEnabled - reset config bits 0-7 and send command 61h"); + _qspiSendGeneralCommand(0x65, -1, NULL, 0, (char *)config_reg, 1); + config_reg[1] &= 0x7F; //Reset Bit 7 of CR + + + + + /* + if (_setWriteEnable() != 0) { + printf("ERROR: Write Enabe failed\n"); + return -1; + } + if( false == _isMemReady()) { + printf("ERROR: Device not ready, write failed\n"); + return -1; + }*/ + + _qspiSendGeneralCommand(0x61, -1, NULL, 0, (char *)config_reg, 1); + + + /* wait_ms(QSPI_STATUS_REGISTER_WRITE_TIMEOUT_MSEC); + if( false == _isMemReady()) { + printf("ERROR: Device not ready after write, failed\n"); + return -1; + } + + + + _qspiSendGeneralCommand(0x65, -1, NULL, 0, (char *)config_reg, 1); + + if (_setWriteEnable() != 0) { + printf("ERROR: Write Enabe failed\n"); + return -1; + } + if( false == _isMemReady()) { + printf("ERROR: Device not ready, write failed\n"); + return -1; + } + config_reg[1] = 0x00; //Reset Bits 0-7 + _qspiSendGeneralCommand(0x61, -1, NULL, 0, (char *)config_reg, 1); + wait_ms(QSPI_STATUS_REGISTER_WRITE_TIMEOUT_MSEC);*/ + /* if( false == _isMemReady()) { + printf("ERROR: Device not ready after write, failed\n"); + return -1; + }*/ + + break; + + default: + QSPIF_LOG(QSPIF_DEBUG_WARNING, "WARNING: _setQPIEnabled - Unsuported En Seq 444 configuration"); + break; + + + } + + return 0; +} + + + +int QSPIFBlockDevice::_sfdpSetQuadEnabled(uint8_t *basicParamTablePtr) +{ + + int sr_read_size = QSPI_MAX_STATUS_REGISTER_SIZE; + int sr_write_size = QSPI_MAX_STATUS_REGISTER_SIZE; + + int status_reg_setup[QSPI_MAX_STATUS_REGISTER_SIZE]; + uint8_t status_reg[QSPI_MAX_STATUS_REGISTER_SIZE]; + unsigned int writeRegisterInst = QSPIF_WRSR; + unsigned int readRegisterInst = QSPIF_RDSR; + + uint8_t qer_value = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_QER_BYTE] & 0x70) >> 4; + + + + switch (qer_value) { + case 0: + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Device Does not Have a QE Bit, continue based on Read Inst"); + return 0; + + case 1: + case 4: + status_reg_setup[0] = 0; + status_reg_setup[1] = 0x02; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Setting QE Bit, Bit 1 of Status Reg 2"); + break; + + case 2: + status_reg_setup[0] = 0x40; + status_reg_setup[1] = 0; + sr_write_size = 1; + sr_read_size = 1; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Setting QE Bit, Bit 6 of Status Reg 1"); + break; + + case 3: + status_reg_setup[0] = 0x80; // Bit 7 of Status Reg 1 + status_reg_setup[1] = 0; + sr_write_size = 1; + sr_read_size = 1; + writeRegisterInst = 0x3E; + readRegisterInst = 0x3F; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Setting QE Bit, Bit 7 of Status Reg 1"); + break; + case 5: + status_reg_setup[0] = 0; + status_reg_setup[1] = 0x02; + readRegisterInst = 0x35; + sr_read_size = 1; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Setting QE Bit, Bit 1 of Status Reg 2 -special read command"); + break; + default: + QSPIF_LOG(QSPIF_DEBUG_WARNING, "WARNING: _setQuadEnable - Unsuported QER configuration"); + break; + + + } + + // Read Status Register + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(readRegisterInst, -1, NULL, 0, (char *)status_reg, + sr_read_size) ) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_reg[0]); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Reading Status Register failed"); + return -1; + } + + // Set Bits for Quad Enable + status_reg[0] |= status_reg_setup[0]; + status_reg[1] |= status_reg_setup[1]; + + + // Write new Status Register Setup + if (_setWriteEnable() != 0) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Write Enabe failed\n"); + return -1; + } + + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Device not ready, write failed"); + return -1; + } + + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(writeRegisterInst, -1, (char *)status_reg, sr_write_size, NULL, + 0) ) { // Write QE to status_register + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _setQuadEnable - Writing Status Register Success: value = 0x%x", + (int)status_reg[0]); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: _setQuadEnable - Writing Status Register failed"); + return -1; + } + + wait_ms(QSPI_STATUS_REGISTER_WRITE_TIMEOUT_MSEC); + + if ( false == _isMemReady()) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Device not ready after write, failed"); + return -1; + } + + + // For Debug + memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE); + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(readRegisterInst, -1, NULL, 0, (char *)status_reg, + sr_read_size) ) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_reg[0]); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Reading Status Register failed"); + return -1; + } + + + return 0;//((status_reg[0] & QSPI_STATUS_BIT_QE) != 0 ? 0 : -1); +} + + +int QSPIFBlockDevice::_sfdpDetectPageSize(uint8_t *basicParamTablePtr) +{ + int page2PowerSize = ( (int)basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4; + int pageSize = _utilsMathPower(2, page2PowerSize); + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: _detectPageSize - Page Size: %d", pageSize); + return pageSize; +} + + + +int QSPIFBlockDevice::_sfdpDetectEraseTypesInstAndSize(uint8_t *basicParamTablePtr, unsigned int& erase4KInst, + unsigned int *eraseTypeInstArr, unsigned int *eraseTypeSizeArr) +{ + erase4KInst = 0xff; + bool found4KEraseType = false; + uint8_t bitfield = 0x01; + + // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K + erase4KInst = basicParamTablePtr[QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE]; + + // Loop Erase Types 1-4 + for (int i_ind = 0; i_ind < 4; i_ind++) { + eraseTypeInstArr[i_ind] = 0xff; //0xFF default for unsupported type + eraseTypeSizeArr[i_ind] = _utilsMathPower(2, basicParamTablePtr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); + if (eraseTypeSizeArr[i_ind] > 1) { + // if size==1 type is not supported + eraseTypeInstArr[i_ind] = basicParamTablePtr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; + + if ((eraseTypeSizeArr[i_ind] < _minCommonEraseSize) || (_minCommonEraseSize == 0) ) { + //Set default minimal common erase for singal region + _minCommonEraseSize = eraseTypeSizeArr[i_ind]; + } + + if (eraseTypeSizeArr[i_ind] == 4096) { + found4KEraseType = true; + if (erase4KInst != eraseTypeInstArr[i_ind]) { + //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table + erase4KInst = eraseTypeInstArr[i_ind]; + QSPIF_LOG(QSPIF_DEBUG_WARNING, + "WARNING: _detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K"); + + } + } + _region_erase_types[0] |= bitfield; // If there's no region map, set region "0" types as defualt; + } + + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), eraseTypeInstArr[i_ind], + eraseTypeSizeArr[i_ind]); + bitfield = bitfield << 1; + } + + if (false == found4KEraseType) { + QSPIF_LOG(QSPIF_DEBUG_WARNING, "WARNING: Couldn't find Erase Type for 4KB size"); + } + return 0; +} + + +int QSPIFBlockDevice::_sfdpDetectBestBusReadMode(uint8_t *basicParamTablePtr, bool& setQuadEnable, bool& isQPIMode, + unsigned int& readInst) +{ + + bool isDone = false; + + setQuadEnable = false; + isQPIMode = false; + int dummyCycles = 0; + uint8_t examinedByte = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPOR_BYTE]; + + do { // compound statement is the loop body + + + + if (examinedByte & 0x10) { + // QPI 4-4-4 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE]; + setQuadEnable = true; + isQPIMode = true; + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F); + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 4-4-4, Instruction: 0x%xh", _readInstruction); + //_inst_width = QSPI_CFG_BUS_QUAD; + _address_width = QSPI_CFG_BUS_QUAD; + _data_width = QSPI_CFG_BUS_QUAD; + + break; + } + + + examinedByte = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE]; + if (examinedByte & 0x40) { + // Fast Read 1-4-4 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE]; + setQuadEnable = true; + // dummy cycles + mode cycles = Dummy Cycles + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F); + _address_width = QSPI_CFG_BUS_QUAD; + _data_width = QSPI_CFG_BUS_QUAD; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 1-4-4, Instruction: 0x%xh", _readInstruction); + break; + } + if (examinedByte & 0x80) { + // Fast Read 1-1-4 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE]; + setQuadEnable = true; + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F); + _data_width = QSPI_CFG_BUS_QUAD; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 1-1-4, Instruction: 0x%xh", _readInstruction); + break; + } + examinedByte = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPOR_BYTE]; + if (examinedByte & 0x01) { + // Fast Read 2-2-2 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE]; + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F); + _address_width = QSPI_CFG_BUS_DUAL; + _data_width = QSPI_CFG_BUS_DUAL; + QSPIF_LOG(QSPIF_DEBUG_INFO, "/nINFO: Read Bus Mode set to 2-2-2, Instruction: 0x%xh", _readInstruction); + break; + } + + examinedByte = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE]; + if (examinedByte & 0x20) { + // Fast Read 1-2-2 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE]; + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F); + _address_width = QSPI_CFG_BUS_DUAL; + _data_width = QSPI_CFG_BUS_DUAL; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 1-2-2, Instruction: 0x%xh", _readInstruction); + break; + } + if (examinedByte & 0x01) { + // Fast Read 1-1-2 Supported + readInst = basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE]; + _dummy_and_mode_cycles = (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5) + + (basicParamTablePtr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F); + _data_width = QSPI_CFG_BUS_DUAL; + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _readInstruction); + break; + } + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "/nDEBUG: Read Bus Mode set to 1-1-1, Instruction: 0x%xh", _readInstruction); + isDone = true; + } while (isDone == false); + + return 0; +} + + +int QSPIFBlockDevice::_resetFlashMem() +{ + int status = 0; + char status_value[2] = {0}; + QSPIF_LOG(QSPIF_DEBUG_ERROR, "INFO: _resetFlashMem:\n"); + //Read the Status Register from device + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(QSPIF_RDSR, -1, NULL, 0, status_value, + 1) ) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_value[0]); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Reading Status Register failed\n"); + status = -1; + } + + if (0 == status) { + //Send Reset Enable + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(QSPIF_RSTEN, -1, NULL, 0, NULL, + 0) ) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Sending RSTEN Success\n"); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Sending RSTEN failed\n"); + status = -1; + } + + + if (0 == status) { + //Send Reset + if (QSPI_STATUS_OK == _qspiSendGeneralCommand(QSPIF_RST, -1, NULL, 0, NULL, + 0)) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "DEBUG: Sending RST Success\n"); + } else { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Sending RST failed\n"); + status = -1; + } + + _isMemReady(); + } + } + + return status; +} + + +bool QSPIFBlockDevice::_isMemReady() +{ + char status_value[2]; + int retries = 0; + bool memReady = true; + + do { + retries++; + //Read the Status Register from device + if (QSPI_STATUS_OK != _qspiSendGeneralCommand(QSPIF_RDSR, -1, NULL, 0, status_value, + 2)) { // store received values in status_value + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Reading Status Register failed\n"); + } + } while ( (status_value[0] & 0x1) != 0 && retries < 10000 ); + + if ((status_value[0] & 0x1) != 0) { + QSPIF_LOG(QSPIF_DEBUG_DEBUG, "ERROR: _isMemReady FALSE\n"); + memReady = false; + } + return memReady; +} + + +int QSPIFBlockDevice::_setWriteEnable() +{ + int status = 0; + if (QSPI_STATUS_OK != _qspiSendGeneralCommand(QSPIF_WREN, -1, NULL, 0, NULL, 0)) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR:Sending WREN command FAILED\n"); + status = -1; + } + return status; +} + + + +/*********************************************/ +/************* Utility Functions *************/ +/*********************************************/ +int QSPIFBlockDevice::_utilsMathPower(int base, int exp) +{ + int result = 1; + while (exp) { + result *= base; + exp--; + } + return result; +} + + +int QSPIFBlockDevice::_utilsFindAddrRegion(int offset) +{ + if ((offset > (int)_deviceSizeBytes) || (_regions_count == 0)) { + return -1; + } + + if (_regions_count == 1) { + return 0; + } + + for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) { + + if (offset > _region_high_boundary[i_ind]) { + return (i_ind + 1); + } + } + return -1; + +} + + +int QSPIFBlockDevice::_utilsIterateNextLargestEraseType(uint8_t& bitfield, int size, int offset, int boundry) +{ + uint8_t type_mask = 0x08; + int i_ind = 0; + int largestEraseType = 0; + for (i_ind = 3; i_ind >= 0; i_ind--) { + if (bitfield & type_mask) { + largestEraseType = i_ind; + if ( (size > _eraseTypeSizeArr[largestEraseType]) && + ((boundry - offset) > _eraseTypeSizeArr[largestEraseType]) ) { + break; + } else { + bitfield &= ~type_mask; + } + } + type_mask = type_mask >> 1; + } + + if (i_ind == 4) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: no erase type was found for current region addr"); + } + return largestEraseType; + +} + + +/***************************************************/ +/*********** QSPI Driver API Functions *************/ +/***************************************************/ + +qspi_status_t QSPIFBlockDevice::_qspiSetFrequency(int freq) +{ + return _qspi.set_frequency(freq); +} + + +qspi_status_t QSPIFBlockDevice::_qspiSendReadCommand(unsigned int readInst, void *buffer, bd_addr_t addr, + bd_size_t size) +{ + // Check the address and size fit onto the chip. + + /* OFR_DBG */ + //MBED_ASSERT(is_valid_read(addr, size)); + + size_t bufLen = size; + + if (_qspi.read( readInst, -1, (unsigned int )addr, (char *)buffer, &bufLen) != QSPI_STATUS_OK ) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: Read failed"); + return QSPI_STATUS_ERROR; + } + + return QSPI_STATUS_OK; + +} + + +qspi_status_t QSPIFBlockDevice::_qspiSendProgramCommand(unsigned int progInst, const void *buffer, bd_addr_t addr, + bd_size_t *size) +{ + // Check the address and size fit onto the chip. + //MBED_ASSERT(is_valid_program(addr, (*size))); + qspi_status_t result = QSPI_STATUS_OK; + + result = _qspi.write( progInst, -1, addr/*(((unsigned int)addr) & 0x00FFFF00)*/, (char *)buffer, (size_t *)size); + if (result != QSPI_STATUS_OK) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Write failed"); + } + + return result; +} + + +qspi_status_t QSPIFBlockDevice::_qspiSendEraseCommand(unsigned int eraseInst, bd_addr_t addr, bd_size_t size) +{ + // Check the address and size fit onto the chip. + //MBED_ASSERT(is_valid_erase(addr, size)); + + qspi_status_t result = QSPI_STATUS_OK; + + result = _qspi.command_transfer(eraseInst, // command to send + (((int)addr) & 0x00FFF000), // Align addr to 4096 + NULL, // do not transmit + 0, // do not transmit + NULL, // just receive two bytes of data + 0); // store received values in status_value + if (QSPI_STATUS_OK != result) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI Erase failed"); + } + + return result; + +} + + +qspi_status_t QSPIFBlockDevice::_qspiSendGeneralCommand(unsigned int instruction, bd_addr_t addr, const char *tx_buffer, + size_t tx_length, const char *rx_buffer, size_t rx_length) +{ + + + qspi_status_t status = _qspi.command_transfer(instruction, (int)addr, tx_buffer, tx_length, rx_buffer, rx_length); + + if (QSPI_STATUS_OK != status) { + QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR:Sending Generic command: %x", instruction); + } + + return status; +} + + +qspi_status_t QSPIFBlockDevice::_qspiConfiureFormat(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, + qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, + int dummy_cycles) +{ + _qspi.configure_format( inst_width, address_width, address_size, alt_width, alt_size, data_width, dummy_cycles); + + return QSPI_STATUS_OK; +} + + + + +