Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
SPIFBlockDevice.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "SPIFBlockDevice.h" 00018 #include "rtos/ThisThread.h" 00019 #include "mbed_critical.h" 00020 00021 #include <string.h> 00022 #include <inttypes.h> 00023 00024 #include "mbed_trace.h" 00025 #define TRACE_GROUP "SPIF" 00026 using namespace mbed; 00027 00028 /* Default SPIF Parameters */ 00029 /****************************/ 00030 #define SPIF_DEFAULT_READ_SIZE 1 00031 #define SPIF_DEFAULT_PROG_SIZE 1 00032 #define SPIF_DEFAULT_PAGE_SIZE 256 00033 #define SPIF_DEFAULT_SE_SIZE 4096 00034 #define SPI_MAX_STATUS_REGISTER_SIZE 2 00035 #ifndef UINT64_MAX 00036 #define UINT64_MAX -1 00037 #endif 00038 #define SPI_NO_ADDRESS_COMMAND UINT64_MAX 00039 // Status Register Bits 00040 #define SPIF_STATUS_BIT_WIP 0x1 //Write In Progress 00041 #define SPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch 00042 00043 /* SFDP Header Parsing */ 00044 /***********************/ 00045 #define SPIF_SFDP_HEADER_SIZE 8 00046 #define SPIF_PARAM_HEADER_SIZE 8 00047 00048 /* Basic Parameters Table Parsing */ 00049 /**********************************/ 00050 #define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */ 00051 //READ Instruction support according to BUS Configuration 00052 #define SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2 00053 #define SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16 00054 #define SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23 00055 #define SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15 00056 #define SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13 00057 #define SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40 00058 // Address Length 00059 #define SPIF_ADDR_SIZE_3_BYTES 3 00060 #define SPIF_ADDR_SIZE_4_BYTES 4 00061 // Erase Types Params 00062 #define SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29 00063 #define SPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31 00064 #define SPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33 00065 #define SPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35 00066 #define SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28 00067 #define SPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30 00068 #define SPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32 00069 #define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34 00070 #define SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1 00071 00072 // Erase Types Per Region BitMask 00073 #define ERASE_BITMASK_TYPE4 0x08 00074 #define ERASE_BITMASK_TYPE1 0x01 00075 #define ERASE_BITMASK_NONE 0x00 00076 #define ERASE_BITMASK_ALL 0x0F 00077 00078 #define IS_MEM_READY_MAX_RETRIES 10000 00079 00080 enum spif_default_instructions { 00081 SPIF_NOP = 0x00, // No operation 00082 SPIF_PP = 0x02, // Page Program data 00083 SPIF_READ = 0x03, // Read data 00084 SPIF_SE = 0x20, // 4KB Sector Erase 00085 SPIF_SFDP = 0x5a, // Read SFDP 00086 SPIF_WRSR = 0x01, // Write Status/Configuration Register 00087 SPIF_WRDI = 0x04, // Write Disable 00088 SPIF_RDSR = 0x05, // Read Status Register 00089 SPIF_WREN = 0x06, // Write Enable 00090 SPIF_RSTEN = 0x66, // Reset Enable 00091 SPIF_RST = 0x99, // Reset 00092 SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID 00093 SPIF_ULBPR = 0x98, // Clears all write-protection bits in the Block-Protection register, 00094 SPIF_4BEN = 0xB7, // Enable 4-byte address mode 00095 SPIF_4BDIS = 0xE9, // Disable 4-byte address mode 00096 }; 00097 00098 // Mutex is used for some SPI Driver commands that must be done sequentially with no other commands in between 00099 // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready 00100 SingletonPtr<PlatformMutex> SPIFBlockDevice::_mutex; 00101 00102 // Local Function 00103 static unsigned int local_math_power(int base, int exp); 00104 00105 //*********************** 00106 // SPIF Block Device APIs 00107 //*********************** 00108 SPIFBlockDevice::SPIFBlockDevice( 00109 PinName mosi, PinName miso, PinName sclk, PinName csel, int freq) 00110 : _spi(mosi, miso, sclk), _cs(csel), _read_instruction(0), _prog_instruction(0), _erase_instruction(0), 00111 _erase4k_inst(0), _page_size_bytes(0), _device_size_bytes(0), _init_ref_count(0), _is_initialized(false) 00112 { 00113 _address_size = SPIF_ADDR_SIZE_3_BYTES; 00114 // Initial SFDP read tables are read with 8 dummy cycles 00115 // Default Bus Setup 1_1_1 with 0 dummy and mode cycles 00116 _read_dummy_and_mode_cycles = 8; 00117 _write_dummy_and_mode_cycles = 0; 00118 _dummy_and_mode_cycles = _read_dummy_and_mode_cycles; 00119 00120 _min_common_erase_size = 0; 00121 _regions_count = 1; 00122 _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE; 00123 00124 if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) { 00125 tr_error("SPI Set Frequency Failed"); 00126 } 00127 00128 _cs = 1; 00129 } 00130 00131 int SPIFBlockDevice::init() 00132 { 00133 uint8_t vendor_device_ids[4]; 00134 size_t data_length = 3; 00135 int status = SPIF_BD_ERROR_OK; 00136 uint32_t basic_table_addr = 0; 00137 size_t basic_table_size = 0; 00138 uint32_t sector_map_table_addr = 0; 00139 size_t sector_map_table_size = 0; 00140 spif_bd_error spi_status = SPIF_BD_ERROR_OK; 00141 00142 _mutex->lock(); 00143 00144 if (!_is_initialized) { 00145 _init_ref_count = 0; 00146 } 00147 00148 _init_ref_count++; 00149 00150 if (_init_ref_count != 1) { 00151 goto exit_point; 00152 } 00153 00154 // Soft Reset 00155 if (-1 == _reset_flash_mem()) { 00156 tr_error("init - Unable to initialize flash memory, tests failed"); 00157 status = SPIF_BD_ERROR_DEVICE_ERROR; 00158 goto exit_point; 00159 } else { 00160 tr_debug("Initialize flash memory OK"); 00161 } 00162 00163 /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/ 00164 spi_status = _spi_send_general_command(SPIF_RDID, SPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids, 00165 data_length); 00166 if (spi_status != SPIF_BD_ERROR_OK) { 00167 tr_error("init - Read Vendor ID Failed"); 00168 status = SPIF_BD_ERROR_DEVICE_ERROR; 00169 goto exit_point; 00170 } 00171 00172 switch (vendor_device_ids[0]) { 00173 case 0xbf: 00174 // SST devices come preset with block protection 00175 // enabled for some regions, issue global protection unlock to clear 00176 _set_write_enable(); 00177 _spi_send_general_command(SPIF_ULBPR, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); 00178 break; 00179 } 00180 00181 //Synchronize Device 00182 if (false == _is_mem_ready()) { 00183 tr_error("init - _is_mem_ready Failed"); 00184 status = SPIF_BD_ERROR_READY_FAILED; 00185 goto exit_point; 00186 } 00187 00188 /**************************** Parse SFDP Header ***********************************/ 00189 if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) { 00190 tr_error("init - Parse SFDP Headers Failed"); 00191 status = SPIF_BD_ERROR_PARSING_FAILED; 00192 goto exit_point; 00193 } 00194 00195 00196 /**************************** Parse Basic Parameters Table ***********************************/ 00197 if (0 != _sfdp_parse_basic_param_table(basic_table_addr, basic_table_size)) { 00198 tr_error("init - Parse Basic Param Table Failed"); 00199 status = SPIF_BD_ERROR_PARSING_FAILED; 00200 goto exit_point; 00201 } 00202 00203 /**************************** Parse Sector Map Table ***********************************/ 00204 _region_size_bytes[0] = 00205 _device_size_bytes; // If there's no region map, we have a single region sized the entire device size 00206 _region_high_boundary[0] = _device_size_bytes - 1; 00207 00208 if ((sector_map_table_addr != 0) && (0 != sector_map_table_size)) { 00209 tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", sector_map_table_addr, 00210 sector_map_table_size); 00211 if (0 != _sfdp_parse_sector_map_table(sector_map_table_addr, sector_map_table_size)) { 00212 tr_error("init - Parse Sector Map Table Failed"); 00213 status = SPIF_BD_ERROR_PARSING_FAILED; 00214 goto exit_point; 00215 } 00216 } 00217 00218 // Configure BUS Mode to 1_1_1 for all commands other than Read 00219 // Dummy And Mode Cycles Back default 0 00220 _dummy_and_mode_cycles = _write_dummy_and_mode_cycles; 00221 _is_initialized = true; 00222 tr_debug("Device size: %llu Kbytes", _device_size_bytes / 1024); 00223 00224 if (_device_size_bytes > (1 << 24)) { 00225 tr_debug("Size is bigger than 16MB and thus address does not fit in 3 byte, switch to 4 byte address mode"); 00226 _spi_send_general_command(SPIF_4BEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); 00227 _address_size = SPIF_ADDR_SIZE_4_BYTES; 00228 } 00229 00230 exit_point: 00231 _mutex->unlock(); 00232 00233 return status; 00234 } 00235 00236 00237 int SPIFBlockDevice::deinit() 00238 { 00239 spif_bd_error status = SPIF_BD_ERROR_OK; 00240 00241 _mutex->lock(); 00242 00243 if (!_is_initialized) { 00244 _init_ref_count = 0; 00245 goto exit_point; 00246 } 00247 00248 _init_ref_count--; 00249 00250 if (_init_ref_count) { 00251 goto exit_point; 00252 } 00253 00254 // Disable Device for Writing 00255 status = _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); 00256 if (status != SPIF_BD_ERROR_OK) { 00257 tr_error("Write Disable failed"); 00258 } 00259 _is_initialized = false; 00260 00261 exit_point: 00262 _mutex->unlock(); 00263 00264 return status; 00265 } 00266 00267 int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) 00268 { 00269 if (!_is_initialized) { 00270 return BD_ERROR_DEVICE_ERROR; 00271 } 00272 00273 int status = SPIF_BD_ERROR_OK; 00274 tr_debug("Read - Inst: 0x%xh", _read_instruction); 00275 _mutex->lock(); 00276 00277 // Set Dummy Cycles for Specific Read Command Mode 00278 _dummy_and_mode_cycles = _read_dummy_and_mode_cycles; 00279 00280 status = _spi_send_read_command(_read_instruction, static_cast<uint8_t *>(buffer), addr, size); 00281 00282 // Set Dummy Cycles for all other command modes 00283 _dummy_and_mode_cycles = _write_dummy_and_mode_cycles; 00284 00285 _mutex->unlock(); 00286 return status; 00287 } 00288 00289 int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) 00290 { 00291 if (!_is_initialized) { 00292 return BD_ERROR_DEVICE_ERROR; 00293 } 00294 00295 bool program_failed = false; 00296 int status = SPIF_BD_ERROR_OK; 00297 uint32_t offset = 0; 00298 uint32_t chunk = 0; 00299 00300 tr_debug("program - Buff: 0x%" PRIx32 "h, addr: %llu, size: %llu", (uint32_t)buffer, addr, size); 00301 00302 while (size > 0) { 00303 00304 // Write on _page_size_bytes boundaries (Default 256 bytes a page) 00305 offset = addr % _page_size_bytes; 00306 chunk = (offset + size < _page_size_bytes) ? size : (_page_size_bytes - offset); 00307 00308 _mutex->lock(); 00309 00310 //Send WREN 00311 if (_set_write_enable() != 0) { 00312 tr_error("Write Enabe failed"); 00313 program_failed = true; 00314 status = SPIF_BD_ERROR_WREN_FAILED; 00315 goto exit_point; 00316 } 00317 00318 _spi_send_program_command(_prog_instruction, buffer, addr, chunk); 00319 00320 buffer = static_cast<const uint8_t *>(buffer) + chunk; 00321 addr += chunk; 00322 size -= chunk; 00323 00324 if (false == _is_mem_ready()) { 00325 tr_error("Device not ready after write, failed"); 00326 program_failed = true; 00327 status = SPIF_BD_ERROR_READY_FAILED; 00328 goto exit_point; 00329 } 00330 _mutex->unlock(); 00331 } 00332 00333 exit_point: 00334 if (program_failed) { 00335 _mutex->unlock(); 00336 } 00337 00338 return status; 00339 } 00340 00341 int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) 00342 { 00343 if (!_is_initialized) { 00344 return BD_ERROR_DEVICE_ERROR; 00345 } 00346 00347 int type = 0; 00348 uint32_t offset = 0; 00349 uint32_t chunk = 4096; 00350 int cur_erase_inst = _erase_instruction; 00351 int size = (int)in_size; 00352 bool erase_failed = false; 00353 int status = SPIF_BD_ERROR_OK; 00354 // Find region of erased address 00355 int region = _utils_find_addr_region(addr); 00356 if (region < 0) { 00357 tr_error("no region found for address %llu", addr); 00358 return SPIF_BD_ERROR_INVALID_ERASE_PARAMS; 00359 } 00360 // Erase Types of selected region 00361 uint8_t bitfield = _region_erase_types_bitfield[region]; 00362 00363 tr_debug("erase - addr: %llu, in_size: %llu", addr, in_size); 00364 00365 if ((addr + in_size) > _device_size_bytes) { 00366 tr_error("erase exceeds flash device size"); 00367 return SPIF_BD_ERROR_INVALID_ERASE_PARAMS; 00368 } 00369 00370 if (((addr % get_erase_size(addr)) != 0) || (((addr + in_size) % get_erase_size(addr + in_size - 1)) != 0)) { 00371 tr_error("invalid erase - unaligned address and size"); 00372 return SPIF_BD_ERROR_INVALID_ERASE_PARAMS; 00373 } 00374 00375 // For each iteration erase the largest section supported by current region 00376 while (size > 0) { 00377 00378 // iterate to find next Largest erase type ( a. supported by region, b. smaller than size) 00379 // find the matching instruction and erase size chunk for that type. 00380 type = _utils_iterate_next_largest_erase_type(bitfield, size, (unsigned int)addr, _region_high_boundary[region]); 00381 cur_erase_inst = _erase_type_inst_arr[type]; 00382 offset = addr % _erase_type_size_arr[type]; 00383 chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset); 00384 00385 tr_debug("erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %" PRIu32 " , ", 00386 addr, size, cur_erase_inst, chunk); 00387 tr_debug("erase - Region: %d, Type:%d", 00388 region, type); 00389 00390 _mutex->lock(); 00391 00392 if (_set_write_enable() != 0) { 00393 tr_error("SPI Erase Device not ready - failed"); 00394 erase_failed = true; 00395 status = SPIF_BD_ERROR_READY_FAILED; 00396 goto exit_point; 00397 } 00398 00399 _spi_send_erase_command(cur_erase_inst, addr, size); 00400 00401 addr += chunk; 00402 size -= chunk; 00403 00404 if ((size > 0) && (addr > _region_high_boundary[region])) { 00405 // erase crossed to next region 00406 region++; 00407 bitfield = _region_erase_types_bitfield[region]; 00408 } 00409 00410 if (false == _is_mem_ready()) { 00411 tr_error("SPI After Erase Device not ready - failed"); 00412 erase_failed = true; 00413 status = SPIF_BD_ERROR_READY_FAILED; 00414 goto exit_point; 00415 } 00416 00417 _mutex->unlock(); 00418 } 00419 00420 exit_point: 00421 if (erase_failed) { 00422 _mutex->unlock(); 00423 } 00424 00425 return status; 00426 } 00427 00428 bd_size_t SPIFBlockDevice::get_read_size() const 00429 { 00430 // Assuming all devices support 1byte read granularity 00431 return SPIF_DEFAULT_READ_SIZE; 00432 } 00433 00434 bd_size_t SPIFBlockDevice::get_program_size() const 00435 { 00436 // Assuming all devices support 1byte program granularity 00437 return SPIF_DEFAULT_PROG_SIZE; 00438 } 00439 00440 bd_size_t SPIFBlockDevice::get_erase_size() const 00441 { 00442 // return minimal erase size supported by all regions (0 if none exists) 00443 return _min_common_erase_size; 00444 } 00445 00446 // Find minimal erase size supported by the region to which the address belongs to 00447 bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr) const 00448 { 00449 // Find region of current address 00450 int region = _utils_find_addr_region(addr); 00451 00452 unsigned int min_region_erase_size = _min_common_erase_size; 00453 int8_t type_mask = ERASE_BITMASK_TYPE1; 00454 int i_ind = 0; 00455 00456 if (region != -1) { 00457 type_mask = 0x01; 00458 00459 for (i_ind = 0; i_ind < 4; i_ind++) { 00460 // loop through erase types bitfield supported by region 00461 if (_region_erase_types_bitfield[region] & type_mask) { 00462 00463 min_region_erase_size = _erase_type_size_arr[i_ind]; 00464 break; 00465 } 00466 type_mask = type_mask << 1; 00467 } 00468 00469 if (i_ind == 4) { 00470 tr_error("no erase type was found for region addr"); 00471 } 00472 } 00473 00474 return (bd_size_t)min_region_erase_size; 00475 } 00476 00477 bd_size_t SPIFBlockDevice::size() const 00478 { 00479 if (!_is_initialized) { 00480 return 0; 00481 } 00482 00483 return _device_size_bytes; 00484 } 00485 00486 int SPIFBlockDevice::get_erase_value() const 00487 { 00488 return 0xFF; 00489 } 00490 00491 const char *SPIFBlockDevice::get_type() const 00492 { 00493 return "SPIF"; 00494 } 00495 00496 /***************************************************/ 00497 /*********** SPI Driver API Functions **************/ 00498 /***************************************************/ 00499 spif_bd_error SPIFBlockDevice::_spi_set_frequency(int freq) 00500 { 00501 _spi.frequency(freq); 00502 return SPIF_BD_ERROR_OK; 00503 } 00504 00505 spif_bd_error SPIFBlockDevice::_spi_send_read_command(int read_inst, uint8_t *buffer, bd_addr_t addr, bd_size_t size) 00506 { 00507 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8; 00508 int dummy_byte = 0; 00509 00510 // csel must go low for the entire command (Inst, Address and Data) 00511 _cs = 0; 00512 00513 // Write 1 byte Instruction 00514 _spi.write(read_inst); 00515 00516 // Write Address (can be either 3 or 4 bytes long) 00517 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) { 00518 _spi.write((addr >> address_shift) & 0xFF); 00519 } 00520 00521 // Write Dummy Cycles Bytes 00522 for (uint32_t i = 0; i < dummy_bytes; i++) { 00523 _spi.write(dummy_byte); 00524 } 00525 00526 // Read Data 00527 for (bd_size_t i = 0; i < size; i++) { 00528 buffer[i] = _spi.write(0); 00529 } 00530 00531 // csel back to high 00532 _cs = 1; 00533 return SPIF_BD_ERROR_OK; 00534 } 00535 00536 spif_bd_error SPIFBlockDevice::_spi_send_program_command(int prog_inst, const void *buffer, bd_addr_t addr, 00537 bd_size_t size) 00538 { 00539 // Send Program (write) command to device driver 00540 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8; 00541 int dummy_byte = 0; 00542 uint8_t *data = (uint8_t *)buffer; 00543 00544 // csel must go low for the entire command (Inst, Address and Data) 00545 _cs = 0; 00546 00547 // Write 1 byte Instruction 00548 _spi.write(prog_inst); 00549 00550 // Write Address (can be either 3 or 4 bytes long) 00551 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) { 00552 _spi.write((addr >> address_shift) & 0xFF); 00553 } 00554 00555 // Write Dummy Cycles Bytes 00556 for (uint32_t i = 0; i < dummy_bytes; i++) { 00557 _spi.write(dummy_byte); 00558 } 00559 00560 // Write Data 00561 for (bd_size_t i = 0; i < size; i++) { 00562 _spi.write(data[i]); 00563 } 00564 00565 // csel back to high 00566 _cs = 1; 00567 00568 return SPIF_BD_ERROR_OK; 00569 } 00570 00571 spif_bd_error SPIFBlockDevice::_spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size) 00572 { 00573 tr_debug("Erase Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size); 00574 addr = (((int)addr) & 0xFFFFF000); 00575 _spi_send_general_command(erase_inst, addr, NULL, 0, NULL, 0); 00576 return SPIF_BD_ERROR_OK; 00577 } 00578 00579 spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_addr_t addr, char *tx_buffer, 00580 size_t tx_length, char *rx_buffer, size_t rx_length) 00581 { 00582 // Send a general command Instruction to driver 00583 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8; 00584 uint8_t dummy_byte = 0x00; 00585 00586 // csel must go low for the entire command (Inst, Address and Data) 00587 _cs = 0; 00588 00589 // Write 1 byte Instruction 00590 _spi.write(instruction); 00591 00592 // Reading SPI Bus registers does not require Flash Address 00593 if (addr != SPI_NO_ADDRESS_COMMAND) { 00594 // Write Address (can be either 3 or 4 bytes long) 00595 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) { 00596 _spi.write((addr >> address_shift) & 0xFF); 00597 } 00598 00599 // Write Dummy Cycles Bytes 00600 for (uint32_t i = 0; i < dummy_bytes; i++) { 00601 _spi.write(dummy_byte); 00602 } 00603 } 00604 00605 // Read/Write Data 00606 _spi.write(tx_buffer, (int)tx_length, rx_buffer, (int)rx_length); 00607 00608 // csel back to high 00609 _cs = 1; 00610 00611 return SPIF_BD_ERROR_OK; 00612 } 00613 00614 /*********************************************************/ 00615 /********** SFDP Parsing and Detection Functions *********/ 00616 /*********************************************************/ 00617 int SPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size) 00618 { 00619 uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ 00620 uint32_t tmp_region_size = 0; 00621 int i_ind = 0; 00622 int prev_boundary = 0; 00623 // Default set to all type bits 1-4 are common 00624 int min_common_erase_type_bits = ERASE_BITMASK_ALL; 00625 00626 00627 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/, 00628 sector_map_table_size); 00629 if (status != SPIF_BD_ERROR_OK) { 00630 tr_error("init - Read SFDP First Table Failed"); 00631 return -1; 00632 } 00633 00634 // Currently we support only Single Map Descriptor 00635 if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) { 00636 tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)"); 00637 return -1; 00638 } 00639 00640 _regions_count = sector_map_table[2] + 1; 00641 if (_regions_count > SPIF_MAX_REGIONS) { 00642 tr_error("Supporting up to %d regions, current setup to %d regions - fail", 00643 SPIF_MAX_REGIONS, _regions_count); 00644 return -1; 00645 } 00646 00647 // Loop through Regions and set for each one: size, supported erase types, high boundary offset 00648 // Calculate minimum Common Erase Type for all Regions 00649 for (i_ind = 0; i_ind < _regions_count; i_ind++) { 00650 tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32 00651 _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes; 00652 _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4 00653 min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind]; 00654 _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary; 00655 prev_boundary = _region_high_boundary[i_ind] + 1; 00656 } 00657 00658 // Calc minimum Common Erase Size from min_common_erase_type_bits 00659 uint8_t type_mask = ERASE_BITMASK_TYPE1; 00660 for (i_ind = 0; i_ind < 4; i_ind++) { 00661 if (min_common_erase_type_bits & type_mask) { 00662 _min_common_erase_size = _erase_type_size_arr[i_ind]; 00663 break; 00664 } 00665 type_mask = type_mask << 1; 00666 } 00667 00668 if (i_ind == 4) { 00669 // No common erase type was found between regions 00670 _min_common_erase_size = 0; 00671 } 00672 00673 return 0; 00674 } 00675 00676 int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size) 00677 { 00678 uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ 00679 //memset(param_table, 0, SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES); 00680 00681 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, param_table, basic_table_addr /*address*/, 00682 basic_table_size); 00683 if (status != SPIF_BD_ERROR_OK) { 00684 tr_error("init - Read SFDP First Table Failed"); 00685 return -1; 00686 } 00687 00688 // Check address size, currently only supports 3byte addresses 00689 if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) { 00690 tr_error("init - verify 3byte addressing Failed"); 00691 return -1; 00692 } 00693 00694 // Get device density (stored in bits - 1) 00695 uint32_t density_bits = ( 00696 (param_table[7] << 24) | 00697 (param_table[6] << 16) | 00698 (param_table[5] << 8) | 00699 param_table[4]); 00700 _device_size_bytes = (density_bits + 1) / 8; 00701 tr_debug("Density bits: %" PRIu32 " , device size: %llu bytes", density_bits, _device_size_bytes); 00702 00703 // Set Default read/program/erase Instructions 00704 _read_instruction = SPIF_READ; 00705 _prog_instruction = SPIF_PP; 00706 _erase_instruction = SPIF_SE; 00707 00708 // Set Page Size (SPI write must be done on Page limits) 00709 _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size); 00710 00711 // Detect and Set Erase Types 00712 _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr, 00713 _erase_type_size_arr); 00714 _erase_instruction = _erase4k_inst; 00715 00716 // Detect and Set fastest Bus mode (default 1-1-1) 00717 _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, _read_instruction); 00718 00719 return 0; 00720 } 00721 00722 int SPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size, 00723 uint32_t §or_map_table_addr, size_t §or_map_table_size) 00724 { 00725 uint8_t sfdp_header[16]; 00726 uint8_t param_header[SPIF_SFDP_HEADER_SIZE]; 00727 size_t data_length = SPIF_SFDP_HEADER_SIZE; 00728 bd_addr_t addr = 0x0; 00729 00730 // Set 1-1-1 bus mode for SFDP header parsing 00731 // Initial SFDP read tables are read with 8 dummy cycles 00732 _read_dummy_and_mode_cycles = 8; 00733 _dummy_and_mode_cycles = 8; 00734 00735 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sfdp_header, addr /*address*/, data_length); 00736 if (status != SPIF_BD_ERROR_OK) { 00737 tr_error("init - Read SFDP Failed"); 00738 return -1; 00739 } 00740 00741 // Verify SFDP signature for sanity 00742 // Also check that major/minor version is acceptable 00743 if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) { 00744 tr_error("init - _verify SFDP signature and version Failed"); 00745 return -1; 00746 } else { 00747 tr_debug("init - verified SFDP Signature and version Successfully"); 00748 } 00749 00750 // Discover Number of Parameter Headers 00751 int number_of_param_headers = (int)(sfdp_header[6]) + 1; 00752 tr_debug("number of Param Headers: %d", number_of_param_headers); 00753 00754 addr += SPIF_SFDP_HEADER_SIZE; 00755 data_length = SPIF_PARAM_HEADER_SIZE; 00756 00757 // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table) 00758 for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) { 00759 00760 status = _spi_send_read_command(SPIF_SFDP, param_header, addr, data_length); 00761 if (status != SPIF_BD_ERROR_OK) { 00762 tr_error("init - Read Param Table %d Failed", i_ind + 1); 00763 return -1; 00764 } 00765 00766 // The SFDP spec indicates the standard table is always at offset 0 00767 // in the parameter headers, we check just to be safe 00768 if (param_header[2] != 1) { 00769 tr_error("Param Table %d - Major Version should be 1!", i_ind + 1); 00770 return -1; 00771 } 00772 00773 if ((param_header[0] == 0) && (param_header[7] == 0xFF)) { 00774 // Found Basic Params Table: LSB=0x00, MSB=0xFF 00775 tr_debug("Found Basic Param Table at Table: %d", i_ind + 1); 00776 basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4])); 00777 // Supporting up to 64 Bytes Table (16 DWORDS) 00778 basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64; 00779 00780 } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) { 00781 // Found Sector Map Table: LSB=0x81, MSB=0xFF 00782 tr_debug("Found Sector Map Table at Table: %d", i_ind + 1); 00783 sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4])); 00784 sector_map_table_size = param_header[3] * 4; 00785 00786 } 00787 addr += SPIF_PARAM_HEADER_SIZE; 00788 00789 } 00790 return 0; 00791 } 00792 00793 unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size) 00794 { 00795 unsigned int page_size = SPIF_DEFAULT_PAGE_SIZE; 00796 00797 if (basic_param_table_size > SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE) { 00798 // Page Size is specified by 4 Bits (N), calculated by 2^N 00799 int page_to_power_size = ((int)basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4; 00800 page_size = local_math_power(2, page_to_power_size); 00801 tr_debug("Detected Page Size: %d", page_size); 00802 } else { 00803 tr_debug("Using Default Page Size: %d", page_size); 00804 } 00805 return page_size; 00806 } 00807 00808 int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, 00809 int &erase4k_inst, 00810 int *erase_type_inst_arr, unsigned int *erase_type_size_arr) 00811 { 00812 erase4k_inst = 0xff; 00813 bool found_4Kerase_type = false; 00814 uint8_t bitfield = 0x01; 00815 00816 // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K 00817 erase4k_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE]; 00818 00819 if (basic_param_table_size > SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) { 00820 // Loop Erase Types 1-4 00821 for (int i_ind = 0; i_ind < 4; i_ind++) { 00822 erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type 00823 erase_type_size_arr[i_ind] = local_math_power(2, 00824 basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N 00825 tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind], 00826 erase_type_size_arr[i_ind]); 00827 if (erase_type_size_arr[i_ind] > 1) { 00828 // if size==1 type is not supported 00829 erase_type_inst_arr[i_ind] = basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; 00830 00831 if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) { 00832 //Set default minimal common erase for singal region 00833 _min_common_erase_size = erase_type_size_arr[i_ind]; 00834 } 00835 00836 // SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction 00837 if (erase_type_size_arr[i_ind] == 4096) { 00838 found_4Kerase_type = true; 00839 if (erase4k_inst != erase_type_inst_arr[i_ind]) { 00840 //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table 00841 erase4k_inst = erase_type_inst_arr[i_ind]; 00842 tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K"); 00843 00844 } 00845 } 00846 _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt; 00847 } 00848 tr_info("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), 00849 erase_type_inst_arr[i_ind], erase_type_size_arr[i_ind]); 00850 bitfield = bitfield << 1; 00851 } 00852 } 00853 00854 if (false == found_4Kerase_type) { 00855 tr_warning("Couldn't find Erase Type for 4KB size"); 00856 } 00857 return 0; 00858 } 00859 00860 int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, 00861 int &read_inst) 00862 { 00863 do { 00864 00865 // TBD - SPIF Dual Read Modes Require SPI driver support 00866 _read_dummy_and_mode_cycles = 0; 00867 tr_debug("Read Bus Mode set to 1-1-1, Instruction: 0x%xh", read_inst); 00868 } while (false); 00869 00870 return 0; 00871 } 00872 00873 int SPIFBlockDevice::_reset_flash_mem() 00874 { 00875 // Perform Soft Reset of the Device prior to initialization 00876 int status = 0; 00877 char status_value[2] = {0}; 00878 tr_info("_reset_flash_mem:"); 00879 //Read the Status Register from device 00880 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 1)) { 00881 // store received values in status_value 00882 tr_debug("Reading Status Register Success: value = 0x%x", (int)status_value[0]); 00883 } else { 00884 tr_error("Reading Status Register failed"); 00885 status = -1; 00886 } 00887 00888 if (0 == status) { 00889 //Send Reset Enable 00890 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RSTEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) { 00891 // store received values in status_value 00892 tr_debug("Sending RSTEN Success"); 00893 } else { 00894 tr_error("Sending RSTEN failed"); 00895 status = -1; 00896 } 00897 00898 if (0 == status) { 00899 //Send Reset 00900 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RST, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) { 00901 // store received values in status_value 00902 tr_debug("Sending RST Success"); 00903 } else { 00904 tr_error("Sending RST failed"); 00905 status = -1; 00906 } 00907 if (false == _is_mem_ready()) { 00908 tr_error("Device not ready, write failed"); 00909 status = -1; 00910 } 00911 } 00912 } 00913 00914 return status; 00915 } 00916 00917 bool SPIFBlockDevice::_is_mem_ready() 00918 { 00919 // Check Status Register Busy Bit to Verify the Device isn't Busy 00920 char status_value[2]; 00921 int retries = 0; 00922 bool mem_ready = true; 00923 00924 do { 00925 rtos::ThisThread::sleep_for(1); 00926 retries++; 00927 //Read the Status Register from device 00928 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 00929 1)) { // store received values in status_value 00930 tr_error("Reading Status Register failed"); 00931 } 00932 } while ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES); 00933 00934 if ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0) { 00935 tr_error("_is_mem_ready FALSE"); 00936 mem_ready = false; 00937 } 00938 return mem_ready; 00939 } 00940 00941 int SPIFBlockDevice::_set_write_enable() 00942 { 00943 // Check Status Register Busy Bit to Verify the Device isn't Busy 00944 char status_value[2]; 00945 int status = -1; 00946 00947 do { 00948 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_WREN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) { 00949 tr_error("Sending WREN command FAILED"); 00950 break; 00951 } 00952 00953 if (false == _is_mem_ready()) { 00954 tr_error("Device not ready, write failed"); 00955 break; 00956 } 00957 00958 memset(status_value, 0, 2); 00959 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 00960 1)) { // store received values in status_value 00961 tr_error("Reading Status Register failed"); 00962 break; 00963 } 00964 00965 if ((status_value[0] & SPIF_STATUS_BIT_WEL) == 0) { 00966 tr_error("_set_write_enable failed"); 00967 break; 00968 } 00969 status = 0; 00970 } while (false); 00971 return status; 00972 } 00973 00974 /*********************************************/ 00975 /************* Utility Functions *************/ 00976 /*********************************************/ 00977 int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) const 00978 { 00979 //Find the region to which the given offset belong to 00980 if ((offset > _device_size_bytes) || (_regions_count == 0)) { 00981 return -1; 00982 } 00983 00984 if (_regions_count == 1) { 00985 return 0; 00986 } 00987 00988 for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) { 00989 00990 if (offset > _region_high_boundary[i_ind]) { 00991 return (i_ind + 1); 00992 } 00993 } 00994 return -1; 00995 00996 } 00997 00998 int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry) 00999 { 01000 // Iterate on all supported Erase Types of the Region to which the offset belong to. 01001 // Iterates from highest type to lowest 01002 uint8_t type_mask = ERASE_BITMASK_TYPE4; 01003 int i_ind = 0; 01004 int largest_erase_type = 0; 01005 for (i_ind = 3; i_ind >= 0; i_ind--) { 01006 if (bitfield & type_mask) { 01007 largest_erase_type = i_ind; 01008 if ((size > (int)(_erase_type_size_arr[largest_erase_type])) && 01009 ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) { 01010 break; 01011 } else { 01012 bitfield &= ~type_mask; 01013 } 01014 } 01015 type_mask = type_mask >> 1; 01016 } 01017 01018 if (i_ind == 4) { 01019 tr_error("no erase type was found for current region addr"); 01020 } 01021 return largest_erase_type; 01022 01023 } 01024 01025 /*********************************************/ 01026 /************** Local Functions **************/ 01027 /*********************************************/ 01028 static unsigned int local_math_power(int base, int exp) 01029 { 01030 // Integer X^Y function, used to calculate size fields given in 2^N format 01031 int result = 1; 01032 while (exp) { 01033 result *= base; 01034 exp--; 01035 } 01036 return result; 01037 } 01038 01039
Generated on Tue Jul 12 2022 13:54:51 by
