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