RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
2019-03-13

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 2:7aab896b1a3b 1 /* mbed Microcontroller Library
kevman 2:7aab896b1a3b 2 * Copyright (c) 2018 ARM Limited
kevman 2:7aab896b1a3b 3 *
kevman 2:7aab896b1a3b 4 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 2:7aab896b1a3b 5 * you may not use this file except in compliance with the License.
kevman 2:7aab896b1a3b 6 * You may obtain a copy of the License at
kevman 2:7aab896b1a3b 7 *
kevman 2:7aab896b1a3b 8 * http://www.apache.org/licenses/LICENSE-2.0
kevman 2:7aab896b1a3b 9 *
kevman 2:7aab896b1a3b 10 * Unless required by applicable law or agreed to in writing, software
kevman 2:7aab896b1a3b 11 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 2:7aab896b1a3b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 2:7aab896b1a3b 13 * See the License for the specific language governing permissions and
kevman 2:7aab896b1a3b 14 * limitations under the License.
kevman 2:7aab896b1a3b 15 */
kevman 2:7aab896b1a3b 16
kevman 2:7aab896b1a3b 17 #include "SPIFBlockDevice.h"
kevman 2:7aab896b1a3b 18 #include "mbed_critical.h"
kevman 2:7aab896b1a3b 19
kevman 2:7aab896b1a3b 20 #include <string.h>
kevman 2:7aab896b1a3b 21 #include "mbed_wait_api.h"
kevman 2:7aab896b1a3b 22
kevman 2:7aab896b1a3b 23 #include "mbed_trace.h"
kevman 2:7aab896b1a3b 24 #define TRACE_GROUP "SPIF"
kevman 2:7aab896b1a3b 25 using namespace mbed;
kevman 2:7aab896b1a3b 26
kevman 2:7aab896b1a3b 27 /* Default SPIF Parameters */
kevman 2:7aab896b1a3b 28 /****************************/
kevman 2:7aab896b1a3b 29 #define SPIF_DEFAULT_READ_SIZE 1
kevman 2:7aab896b1a3b 30 #define SPIF_DEFAULT_PROG_SIZE 1
kevman 2:7aab896b1a3b 31 #define SPIF_DEFAULT_PAGE_SIZE 256
kevman 2:7aab896b1a3b 32 #define SPIF_DEFAULT_SE_SIZE 4096
kevman 2:7aab896b1a3b 33 #define SPI_MAX_STATUS_REGISTER_SIZE 2
kevman 2:7aab896b1a3b 34 #ifndef UINT64_MAX
kevman 2:7aab896b1a3b 35 #define UINT64_MAX -1
kevman 2:7aab896b1a3b 36 #endif
kevman 2:7aab896b1a3b 37 #define SPI_NO_ADDRESS_COMMAND UINT64_MAX
kevman 2:7aab896b1a3b 38 // Status Register Bits
kevman 2:7aab896b1a3b 39 #define SPIF_STATUS_BIT_WIP 0x1 //Write In Progress
kevman 2:7aab896b1a3b 40 #define SPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch
kevman 2:7aab896b1a3b 41
kevman 2:7aab896b1a3b 42 /* SFDP Header Parsing */
kevman 2:7aab896b1a3b 43 /***********************/
kevman 2:7aab896b1a3b 44 #define SPIF_SFDP_HEADER_SIZE 8
kevman 2:7aab896b1a3b 45 #define SPIF_PARAM_HEADER_SIZE 8
kevman 2:7aab896b1a3b 46
kevman 2:7aab896b1a3b 47 /* Basic Parameters Table Parsing */
kevman 2:7aab896b1a3b 48 /**********************************/
kevman 2:7aab896b1a3b 49 #define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */
kevman 2:7aab896b1a3b 50 //READ Instruction support according to BUS Configuration
kevman 2:7aab896b1a3b 51 #define SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2
kevman 2:7aab896b1a3b 52 #define SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16
kevman 2:7aab896b1a3b 53 #define SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23
kevman 2:7aab896b1a3b 54 #define SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15
kevman 2:7aab896b1a3b 55 #define SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13
kevman 2:7aab896b1a3b 56 #define SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40
kevman 2:7aab896b1a3b 57 // Address Length
kevman 2:7aab896b1a3b 58 #define SPIF_ADDR_SIZE_3_BYTES 3
kevman 2:7aab896b1a3b 59 // Erase Types Params
kevman 2:7aab896b1a3b 60 #define SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29
kevman 2:7aab896b1a3b 61 #define SPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31
kevman 2:7aab896b1a3b 62 #define SPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33
kevman 2:7aab896b1a3b 63 #define SPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35
kevman 2:7aab896b1a3b 64 #define SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28
kevman 2:7aab896b1a3b 65 #define SPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30
kevman 2:7aab896b1a3b 66 #define SPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32
kevman 2:7aab896b1a3b 67 #define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34
kevman 2:7aab896b1a3b 68 #define SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1
kevman 2:7aab896b1a3b 69
kevman 2:7aab896b1a3b 70 // Erase Types Per Region BitMask
kevman 2:7aab896b1a3b 71 #define ERASE_BITMASK_TYPE4 0x08
kevman 2:7aab896b1a3b 72 #define ERASE_BITMASK_TYPE1 0x01
kevman 2:7aab896b1a3b 73 #define ERASE_BITMASK_NONE 0x00
kevman 2:7aab896b1a3b 74 #define ERASE_BITMASK_ALL 0x0F
kevman 2:7aab896b1a3b 75
kevman 2:7aab896b1a3b 76 #define IS_MEM_READY_MAX_RETRIES 10000
kevman 2:7aab896b1a3b 77
kevman 2:7aab896b1a3b 78 enum spif_default_instructions {
kevman 2:7aab896b1a3b 79 SPIF_NOP = 0x00, // No operation
kevman 2:7aab896b1a3b 80 SPIF_PP = 0x02, // Page Program data
kevman 2:7aab896b1a3b 81 SPIF_READ = 0x03, // Read data
kevman 2:7aab896b1a3b 82 SPIF_SE = 0x20, // 4KB Sector Erase
kevman 2:7aab896b1a3b 83 SPIF_SFDP = 0x5a, // Read SFDP
kevman 2:7aab896b1a3b 84 SPIF_WRSR = 0x01, // Write Status/Configuration Register
kevman 2:7aab896b1a3b 85 SPIF_WRDI = 0x04, // Write Disable
kevman 2:7aab896b1a3b 86 SPIF_RDSR = 0x05, // Read Status Register
kevman 2:7aab896b1a3b 87 SPIF_WREN = 0x06, // Write Enable
kevman 2:7aab896b1a3b 88 SPIF_RSTEN = 0x66, // Reset Enable
kevman 2:7aab896b1a3b 89 SPIF_RST = 0x99, // Reset
kevman 2:7aab896b1a3b 90 SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
kevman 2:7aab896b1a3b 91 };
kevman 2:7aab896b1a3b 92
kevman 2:7aab896b1a3b 93 // Mutex is used for some SPI Driver commands that must be done sequentially with no other commands in between
kevman 2:7aab896b1a3b 94 // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
kevman 2:7aab896b1a3b 95 SingletonPtr<PlatformMutex> SPIFBlockDevice::_mutex;
kevman 2:7aab896b1a3b 96
kevman 2:7aab896b1a3b 97 // Local Function
kevman 2:7aab896b1a3b 98 static unsigned int local_math_power(int base, int exp);
kevman 2:7aab896b1a3b 99
kevman 2:7aab896b1a3b 100 //***********************
kevman 2:7aab896b1a3b 101 // SPIF Block Device APIs
kevman 2:7aab896b1a3b 102 //***********************
kevman 2:7aab896b1a3b 103 SPIFBlockDevice::SPIFBlockDevice(
kevman 2:7aab896b1a3b 104 PinName mosi, PinName miso, PinName sclk, PinName csel, int freq)
kevman 2:7aab896b1a3b 105 : _spi(mosi, miso, sclk), _cs(csel), _device_size_bytes(0), _is_initialized(false), _init_ref_count(0)
kevman 2:7aab896b1a3b 106 {
kevman 2:7aab896b1a3b 107 _address_size = SPIF_ADDR_SIZE_3_BYTES;
kevman 2:7aab896b1a3b 108 // Initial SFDP read tables are read with 8 dummy cycles
kevman 2:7aab896b1a3b 109 // Default Bus Setup 1_1_1 with 0 dummy and mode cycles
kevman 2:7aab896b1a3b 110 _read_dummy_and_mode_cycles = 8;
kevman 2:7aab896b1a3b 111 _write_dummy_and_mode_cycles = 0;
kevman 2:7aab896b1a3b 112 _dummy_and_mode_cycles = _read_dummy_and_mode_cycles;
kevman 2:7aab896b1a3b 113
kevman 2:7aab896b1a3b 114 _min_common_erase_size = 0;
kevman 2:7aab896b1a3b 115 _regions_count = 1;
kevman 2:7aab896b1a3b 116 _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
kevman 2:7aab896b1a3b 117
kevman 2:7aab896b1a3b 118 if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) {
kevman 2:7aab896b1a3b 119 tr_error("ERROR: SPI Set Frequency Failed");
kevman 2:7aab896b1a3b 120 }
kevman 2:7aab896b1a3b 121
kevman 2:7aab896b1a3b 122 _cs = 1;
kevman 2:7aab896b1a3b 123 }
kevman 2:7aab896b1a3b 124
kevman 2:7aab896b1a3b 125 int SPIFBlockDevice::init()
kevman 2:7aab896b1a3b 126 {
kevman 2:7aab896b1a3b 127 uint8_t vendor_device_ids[4];
kevman 2:7aab896b1a3b 128 size_t data_length = 3;
kevman 2:7aab896b1a3b 129 int status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 130 uint32_t basic_table_addr = 0;
kevman 2:7aab896b1a3b 131 size_t basic_table_size = 0;
kevman 2:7aab896b1a3b 132 uint32_t sector_map_table_addr = 0;
kevman 2:7aab896b1a3b 133 size_t sector_map_table_size = 0;
kevman 2:7aab896b1a3b 134 spif_bd_error spi_status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 135
kevman 2:7aab896b1a3b 136 _mutex->lock();
kevman 2:7aab896b1a3b 137
kevman 2:7aab896b1a3b 138 if (!_is_initialized) {
kevman 2:7aab896b1a3b 139 _init_ref_count = 0;
kevman 2:7aab896b1a3b 140 }
kevman 2:7aab896b1a3b 141
kevman 2:7aab896b1a3b 142 _init_ref_count++;
kevman 2:7aab896b1a3b 143
kevman 2:7aab896b1a3b 144 if (_init_ref_count != 1) {
kevman 2:7aab896b1a3b 145 goto exit_point;
kevman 2:7aab896b1a3b 146 }
kevman 2:7aab896b1a3b 147
kevman 2:7aab896b1a3b 148 // Soft Reset
kevman 2:7aab896b1a3b 149 if (-1 == _reset_flash_mem()) {
kevman 2:7aab896b1a3b 150 tr_error("ERROR: init - Unable to initialize flash memory, tests failed\n");
kevman 2:7aab896b1a3b 151 status = SPIF_BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 152 goto exit_point;
kevman 2:7aab896b1a3b 153 } else {
kevman 2:7aab896b1a3b 154 tr_info("INFO: Initialize flash memory OK\n");
kevman 2:7aab896b1a3b 155 }
kevman 2:7aab896b1a3b 156
kevman 2:7aab896b1a3b 157
kevman 2:7aab896b1a3b 158 /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/
kevman 2:7aab896b1a3b 159 spi_status = _spi_send_general_command(SPIF_RDID, SPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids,
kevman 2:7aab896b1a3b 160 data_length);
kevman 2:7aab896b1a3b 161 if (spi_status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 162 tr_error("ERROR: init - Read Vendor ID Failed");
kevman 2:7aab896b1a3b 163 status = SPIF_BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 164 goto exit_point;
kevman 2:7aab896b1a3b 165 }
kevman 2:7aab896b1a3b 166
kevman 2:7aab896b1a3b 167 switch (vendor_device_ids[0]) {
kevman 2:7aab896b1a3b 168 case 0xbf:
kevman 2:7aab896b1a3b 169 // SST devices come preset with block protection
kevman 2:7aab896b1a3b 170 // enabled for some regions, issue write disable instruction to clear
kevman 2:7aab896b1a3b 171 _set_write_enable();
kevman 2:7aab896b1a3b 172 _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
kevman 2:7aab896b1a3b 173 break;
kevman 2:7aab896b1a3b 174 }
kevman 2:7aab896b1a3b 175
kevman 2:7aab896b1a3b 176 //Synchronize Device
kevman 2:7aab896b1a3b 177 if (false == _is_mem_ready()) {
kevman 2:7aab896b1a3b 178 tr_error("ERROR: init - _is_mem_ready Failed");
kevman 2:7aab896b1a3b 179 status = SPIF_BD_ERROR_READY_FAILED;
kevman 2:7aab896b1a3b 180 goto exit_point;
kevman 2:7aab896b1a3b 181 }
kevman 2:7aab896b1a3b 182
kevman 2:7aab896b1a3b 183 /**************************** Parse SFDP Header ***********************************/
kevman 2:7aab896b1a3b 184 if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) {
kevman 2:7aab896b1a3b 185 tr_error("ERROR: init - Parse SFDP Headers Failed");
kevman 2:7aab896b1a3b 186 status = SPIF_BD_ERROR_PARSING_FAILED;
kevman 2:7aab896b1a3b 187 goto exit_point;
kevman 2:7aab896b1a3b 188 }
kevman 2:7aab896b1a3b 189
kevman 2:7aab896b1a3b 190
kevman 2:7aab896b1a3b 191 /**************************** Parse Basic Parameters Table ***********************************/
kevman 2:7aab896b1a3b 192 if (0 != _sfdp_parse_basic_param_table(basic_table_addr, basic_table_size)) {
kevman 2:7aab896b1a3b 193 tr_error("ERROR: init - Parse Basic Param Table Failed");
kevman 2:7aab896b1a3b 194 status = SPIF_BD_ERROR_PARSING_FAILED;
kevman 2:7aab896b1a3b 195 goto exit_point;
kevman 2:7aab896b1a3b 196 }
kevman 2:7aab896b1a3b 197
kevman 2:7aab896b1a3b 198 /**************************** Parse Sector Map Table ***********************************/
kevman 2:7aab896b1a3b 199 _region_size_bytes[0] =
kevman 2:7aab896b1a3b 200 _device_size_bytes; // If there's no region map, we have a single region sized the entire device size
kevman 2:7aab896b1a3b 201 _region_high_boundary[0] = _device_size_bytes - 1;
kevman 2:7aab896b1a3b 202
kevman 2:7aab896b1a3b 203 if ((sector_map_table_addr != 0) && (0 != sector_map_table_size)) {
kevman 2:7aab896b1a3b 204 tr_info("INFO: init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", sector_map_table_addr,
kevman 2:7aab896b1a3b 205 sector_map_table_size);
kevman 2:7aab896b1a3b 206 if (0 != _sfdp_parse_sector_map_table(sector_map_table_addr, sector_map_table_size)) {
kevman 2:7aab896b1a3b 207 tr_error("ERROR: init - Parse Sector Map Table Failed");
kevman 2:7aab896b1a3b 208 status = SPIF_BD_ERROR_PARSING_FAILED;
kevman 2:7aab896b1a3b 209 goto exit_point;
kevman 2:7aab896b1a3b 210 }
kevman 2:7aab896b1a3b 211 }
kevman 2:7aab896b1a3b 212
kevman 2:7aab896b1a3b 213 // Configure BUS Mode to 1_1_1 for all commands other than Read
kevman 2:7aab896b1a3b 214 // Dummy And Mode Cycles Back default 0
kevman 2:7aab896b1a3b 215 _dummy_and_mode_cycles = _write_dummy_and_mode_cycles;
kevman 2:7aab896b1a3b 216 _is_initialized = true;
kevman 2:7aab896b1a3b 217
kevman 2:7aab896b1a3b 218 exit_point:
kevman 2:7aab896b1a3b 219 _mutex->unlock();
kevman 2:7aab896b1a3b 220
kevman 2:7aab896b1a3b 221 return status;
kevman 2:7aab896b1a3b 222 }
kevman 2:7aab896b1a3b 223
kevman 2:7aab896b1a3b 224
kevman 2:7aab896b1a3b 225 int SPIFBlockDevice::deinit()
kevman 2:7aab896b1a3b 226 {
kevman 2:7aab896b1a3b 227 spif_bd_error status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 228
kevman 2:7aab896b1a3b 229 _mutex->lock();
kevman 2:7aab896b1a3b 230
kevman 2:7aab896b1a3b 231 if (!_is_initialized) {
kevman 2:7aab896b1a3b 232 _init_ref_count = 0;
kevman 2:7aab896b1a3b 233 goto exit_point;
kevman 2:7aab896b1a3b 234 }
kevman 2:7aab896b1a3b 235
kevman 2:7aab896b1a3b 236 _init_ref_count--;
kevman 2:7aab896b1a3b 237
kevman 2:7aab896b1a3b 238 if (_init_ref_count) {
kevman 2:7aab896b1a3b 239 goto exit_point;
kevman 2:7aab896b1a3b 240 }
kevman 2:7aab896b1a3b 241
kevman 2:7aab896b1a3b 242 // Disable Device for Writing
kevman 2:7aab896b1a3b 243 status = _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
kevman 2:7aab896b1a3b 244 if (status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 245 tr_error("ERROR: Write Disable failed");
kevman 2:7aab896b1a3b 246 }
kevman 2:7aab896b1a3b 247 _is_initialized = false;
kevman 2:7aab896b1a3b 248
kevman 2:7aab896b1a3b 249 exit_point:
kevman 2:7aab896b1a3b 250 _mutex->unlock();
kevman 2:7aab896b1a3b 251
kevman 2:7aab896b1a3b 252 return status;
kevman 2:7aab896b1a3b 253 }
kevman 2:7aab896b1a3b 254
kevman 2:7aab896b1a3b 255 int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 256 {
kevman 2:7aab896b1a3b 257 if (!_is_initialized) {
kevman 2:7aab896b1a3b 258 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 259 }
kevman 2:7aab896b1a3b 260
kevman 2:7aab896b1a3b 261 int status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 262 tr_info("INFO Read - Inst: 0x%xh", _read_instruction);
kevman 2:7aab896b1a3b 263 _mutex->lock();
kevman 2:7aab896b1a3b 264
kevman 2:7aab896b1a3b 265 // Set Dummy Cycles for Specific Read Command Mode
kevman 2:7aab896b1a3b 266 _dummy_and_mode_cycles = _read_dummy_and_mode_cycles;
kevman 2:7aab896b1a3b 267
kevman 2:7aab896b1a3b 268 status = _spi_send_read_command(_read_instruction, static_cast<uint8_t *>(buffer), addr, size);
kevman 2:7aab896b1a3b 269
kevman 2:7aab896b1a3b 270 // Set Dummy Cycles for all other command modes
kevman 2:7aab896b1a3b 271 _dummy_and_mode_cycles = _write_dummy_and_mode_cycles;
kevman 2:7aab896b1a3b 272
kevman 2:7aab896b1a3b 273 _mutex->unlock();
kevman 2:7aab896b1a3b 274 return status;
kevman 2:7aab896b1a3b 275 }
kevman 2:7aab896b1a3b 276
kevman 2:7aab896b1a3b 277 int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 278 {
kevman 2:7aab896b1a3b 279 if (!_is_initialized) {
kevman 2:7aab896b1a3b 280 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 281 }
kevman 2:7aab896b1a3b 282
kevman 2:7aab896b1a3b 283 bool program_failed = false;
kevman 2:7aab896b1a3b 284 int status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 285 uint32_t offset = 0;
kevman 2:7aab896b1a3b 286 uint32_t chunk = 0;
kevman 2:7aab896b1a3b 287
kevman 2:7aab896b1a3b 288 tr_debug("DEBUG: program - Buff: 0x%lxh, addr: %llu, size: %llu", (uint32_t)buffer, addr, size);
kevman 2:7aab896b1a3b 289
kevman 2:7aab896b1a3b 290 while (size > 0) {
kevman 2:7aab896b1a3b 291
kevman 2:7aab896b1a3b 292 // Write on _page_size_bytes boundaries (Default 256 bytes a page)
kevman 2:7aab896b1a3b 293 offset = addr % _page_size_bytes;
kevman 2:7aab896b1a3b 294 chunk = (offset + size < _page_size_bytes) ? size : (_page_size_bytes - offset);
kevman 2:7aab896b1a3b 295
kevman 2:7aab896b1a3b 296 _mutex->lock();
kevman 2:7aab896b1a3b 297
kevman 2:7aab896b1a3b 298 //Send WREN
kevman 2:7aab896b1a3b 299 if (_set_write_enable() != 0) {
kevman 2:7aab896b1a3b 300 tr_error("ERROR: Write Enabe failed\n");
kevman 2:7aab896b1a3b 301 program_failed = true;
kevman 2:7aab896b1a3b 302 status = SPIF_BD_ERROR_WREN_FAILED;
kevman 2:7aab896b1a3b 303 goto exit_point;
kevman 2:7aab896b1a3b 304 }
kevman 2:7aab896b1a3b 305
kevman 2:7aab896b1a3b 306 _spi_send_program_command(_prog_instruction, buffer, addr, chunk);
kevman 2:7aab896b1a3b 307
kevman 2:7aab896b1a3b 308 buffer = static_cast<const uint8_t *>(buffer) + chunk;
kevman 2:7aab896b1a3b 309 addr += chunk;
kevman 2:7aab896b1a3b 310 size -= chunk;
kevman 2:7aab896b1a3b 311
kevman 2:7aab896b1a3b 312 if (false == _is_mem_ready()) {
kevman 2:7aab896b1a3b 313 tr_error("ERROR: Device not ready after write, failed\n");
kevman 2:7aab896b1a3b 314 program_failed = true;
kevman 2:7aab896b1a3b 315 status = SPIF_BD_ERROR_READY_FAILED;
kevman 2:7aab896b1a3b 316 goto exit_point;
kevman 2:7aab896b1a3b 317 }
kevman 2:7aab896b1a3b 318 _mutex->unlock();
kevman 2:7aab896b1a3b 319 }
kevman 2:7aab896b1a3b 320
kevman 2:7aab896b1a3b 321 exit_point:
kevman 2:7aab896b1a3b 322 if (program_failed) {
kevman 2:7aab896b1a3b 323 _mutex->unlock();
kevman 2:7aab896b1a3b 324 }
kevman 2:7aab896b1a3b 325
kevman 2:7aab896b1a3b 326 return status;
kevman 2:7aab896b1a3b 327 }
kevman 2:7aab896b1a3b 328
kevman 2:7aab896b1a3b 329 int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
kevman 2:7aab896b1a3b 330 {
kevman 2:7aab896b1a3b 331 if (!_is_initialized) {
kevman 2:7aab896b1a3b 332 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 333 }
kevman 2:7aab896b1a3b 334
kevman 2:7aab896b1a3b 335 int type = 0;
kevman 2:7aab896b1a3b 336 uint32_t offset = 0;
kevman 2:7aab896b1a3b 337 uint32_t chunk = 4096;
kevman 2:7aab896b1a3b 338 int cur_erase_inst = _erase_instruction;
kevman 2:7aab896b1a3b 339 int size = (int)in_size;
kevman 2:7aab896b1a3b 340 bool erase_failed = false;
kevman 2:7aab896b1a3b 341 int status = SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 342 // Find region of erased address
kevman 2:7aab896b1a3b 343 int region = _utils_find_addr_region(addr);
kevman 2:7aab896b1a3b 344 // Erase Types of selected region
kevman 2:7aab896b1a3b 345 uint8_t bitfield = _region_erase_types_bitfield[region];
kevman 2:7aab896b1a3b 346
kevman 2:7aab896b1a3b 347 tr_info("DEBUG: erase - addr: %llu, in_size: %llu", addr, in_size);
kevman 2:7aab896b1a3b 348
kevman 2:7aab896b1a3b 349 if ((addr + in_size) > _device_size_bytes) {
kevman 2:7aab896b1a3b 350 tr_error("ERROR: erase exceeds flash device size");
kevman 2:7aab896b1a3b 351 return SPIF_BD_ERROR_INVALID_ERASE_PARAMS;
kevman 2:7aab896b1a3b 352 }
kevman 2:7aab896b1a3b 353
kevman 2:7aab896b1a3b 354 if (((addr % get_erase_size(addr)) != 0) || (((addr + in_size) % get_erase_size(addr + in_size - 1)) != 0)) {
kevman 2:7aab896b1a3b 355 tr_error("ERROR: invalid erase - unaligned address and size");
kevman 2:7aab896b1a3b 356 return SPIF_BD_ERROR_INVALID_ERASE_PARAMS;
kevman 2:7aab896b1a3b 357 }
kevman 2:7aab896b1a3b 358
kevman 2:7aab896b1a3b 359 // For each iteration erase the largest section supported by current region
kevman 2:7aab896b1a3b 360 while (size > 0) {
kevman 2:7aab896b1a3b 361
kevman 2:7aab896b1a3b 362 // iterate to find next Largest erase type ( a. supported by region, b. smaller than size)
kevman 2:7aab896b1a3b 363 // find the matching instruction and erase size chunk for that type.
kevman 2:7aab896b1a3b 364 type = _utils_iterate_next_largest_erase_type(bitfield, size, (unsigned int)addr, _region_high_boundary[region]);
kevman 2:7aab896b1a3b 365 cur_erase_inst = _erase_type_inst_arr[type];
kevman 2:7aab896b1a3b 366 offset = addr % _erase_type_size_arr[type];
kevman 2:7aab896b1a3b 367 chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset);
kevman 2:7aab896b1a3b 368
kevman 2:7aab896b1a3b 369 tr_debug("DEBUG: erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu , ",
kevman 2:7aab896b1a3b 370 addr, size, cur_erase_inst, chunk);
kevman 2:7aab896b1a3b 371 tr_debug("DEBUG: erase - Region: %d, Type:%d",
kevman 2:7aab896b1a3b 372 region, type);
kevman 2:7aab896b1a3b 373
kevman 2:7aab896b1a3b 374 _mutex->lock();
kevman 2:7aab896b1a3b 375
kevman 2:7aab896b1a3b 376 if (_set_write_enable() != 0) {
kevman 2:7aab896b1a3b 377 tr_error("ERROR: SPI Erase Device not ready - failed");
kevman 2:7aab896b1a3b 378 erase_failed = true;
kevman 2:7aab896b1a3b 379 status = SPIF_BD_ERROR_READY_FAILED;
kevman 2:7aab896b1a3b 380 goto exit_point;
kevman 2:7aab896b1a3b 381 }
kevman 2:7aab896b1a3b 382
kevman 2:7aab896b1a3b 383 _spi_send_erase_command(cur_erase_inst, addr, size);
kevman 2:7aab896b1a3b 384
kevman 2:7aab896b1a3b 385 addr += chunk;
kevman 2:7aab896b1a3b 386 size -= chunk;
kevman 2:7aab896b1a3b 387
kevman 2:7aab896b1a3b 388 if ((size > 0) && (addr > _region_high_boundary[region])) {
kevman 2:7aab896b1a3b 389 // erase crossed to next region
kevman 2:7aab896b1a3b 390 region++;
kevman 2:7aab896b1a3b 391 bitfield = _region_erase_types_bitfield[region];
kevman 2:7aab896b1a3b 392 }
kevman 2:7aab896b1a3b 393
kevman 2:7aab896b1a3b 394 if (false == _is_mem_ready()) {
kevman 2:7aab896b1a3b 395 tr_error("ERROR: SPI After Erase Device not ready - failed\n");
kevman 2:7aab896b1a3b 396 erase_failed = true;
kevman 2:7aab896b1a3b 397 status = SPIF_BD_ERROR_READY_FAILED;
kevman 2:7aab896b1a3b 398 goto exit_point;
kevman 2:7aab896b1a3b 399 }
kevman 2:7aab896b1a3b 400
kevman 2:7aab896b1a3b 401 _mutex->unlock();
kevman 2:7aab896b1a3b 402 }
kevman 2:7aab896b1a3b 403
kevman 2:7aab896b1a3b 404 exit_point:
kevman 2:7aab896b1a3b 405 if (erase_failed) {
kevman 2:7aab896b1a3b 406 _mutex->unlock();
kevman 2:7aab896b1a3b 407 }
kevman 2:7aab896b1a3b 408
kevman 2:7aab896b1a3b 409 return status;
kevman 2:7aab896b1a3b 410 }
kevman 2:7aab896b1a3b 411
kevman 2:7aab896b1a3b 412 bd_size_t SPIFBlockDevice::get_read_size() const
kevman 2:7aab896b1a3b 413 {
kevman 2:7aab896b1a3b 414 // Assuming all devices support 1byte read granularity
kevman 2:7aab896b1a3b 415 return SPIF_DEFAULT_READ_SIZE;
kevman 2:7aab896b1a3b 416 }
kevman 2:7aab896b1a3b 417
kevman 2:7aab896b1a3b 418 bd_size_t SPIFBlockDevice::get_program_size() const
kevman 2:7aab896b1a3b 419 {
kevman 2:7aab896b1a3b 420 // Assuming all devices support 1byte program granularity
kevman 2:7aab896b1a3b 421 return SPIF_DEFAULT_PROG_SIZE;
kevman 2:7aab896b1a3b 422 }
kevman 2:7aab896b1a3b 423
kevman 2:7aab896b1a3b 424 bd_size_t SPIFBlockDevice::get_erase_size() const
kevman 2:7aab896b1a3b 425 {
kevman 2:7aab896b1a3b 426 // return minimal erase size supported by all regions (0 if none exists)
kevman 2:7aab896b1a3b 427 return _min_common_erase_size;
kevman 2:7aab896b1a3b 428 }
kevman 2:7aab896b1a3b 429
kevman 2:7aab896b1a3b 430 // Find minimal erase size supported by the region to which the address belongs to
kevman 2:7aab896b1a3b 431 bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr)
kevman 2:7aab896b1a3b 432 {
kevman 2:7aab896b1a3b 433 // Find region of current address
kevman 2:7aab896b1a3b 434 int region = _utils_find_addr_region(addr);
kevman 2:7aab896b1a3b 435
kevman 2:7aab896b1a3b 436 unsigned int min_region_erase_size = _min_common_erase_size;
kevman 2:7aab896b1a3b 437 int8_t type_mask = ERASE_BITMASK_TYPE1;
kevman 2:7aab896b1a3b 438 int i_ind = 0;
kevman 2:7aab896b1a3b 439
kevman 2:7aab896b1a3b 440 if (region != -1) {
kevman 2:7aab896b1a3b 441 type_mask = 0x01;
kevman 2:7aab896b1a3b 442
kevman 2:7aab896b1a3b 443 for (i_ind = 0; i_ind < 4; i_ind++) {
kevman 2:7aab896b1a3b 444 // loop through erase types bitfield supported by region
kevman 2:7aab896b1a3b 445 if (_region_erase_types_bitfield[region] & type_mask) {
kevman 2:7aab896b1a3b 446
kevman 2:7aab896b1a3b 447 min_region_erase_size = _erase_type_size_arr[i_ind];
kevman 2:7aab896b1a3b 448 break;
kevman 2:7aab896b1a3b 449 }
kevman 2:7aab896b1a3b 450 type_mask = type_mask << 1;
kevman 2:7aab896b1a3b 451 }
kevman 2:7aab896b1a3b 452
kevman 2:7aab896b1a3b 453 if (i_ind == 4) {
kevman 2:7aab896b1a3b 454 tr_error("ERROR: no erase type was found for region addr");
kevman 2:7aab896b1a3b 455 }
kevman 2:7aab896b1a3b 456 }
kevman 2:7aab896b1a3b 457
kevman 2:7aab896b1a3b 458 return (bd_size_t)min_region_erase_size;
kevman 2:7aab896b1a3b 459 }
kevman 2:7aab896b1a3b 460
kevman 2:7aab896b1a3b 461 bd_size_t SPIFBlockDevice::size() const
kevman 2:7aab896b1a3b 462 {
kevman 2:7aab896b1a3b 463 if (!_is_initialized) {
kevman 2:7aab896b1a3b 464 return 0;
kevman 2:7aab896b1a3b 465 }
kevman 2:7aab896b1a3b 466
kevman 2:7aab896b1a3b 467 return _device_size_bytes;
kevman 2:7aab896b1a3b 468 }
kevman 2:7aab896b1a3b 469
kevman 2:7aab896b1a3b 470 int SPIFBlockDevice::get_erase_value() const
kevman 2:7aab896b1a3b 471 {
kevman 2:7aab896b1a3b 472 return 0xFF;
kevman 2:7aab896b1a3b 473 }
kevman 2:7aab896b1a3b 474
kevman 2:7aab896b1a3b 475 /***************************************************/
kevman 2:7aab896b1a3b 476 /*********** SPI Driver API Functions **************/
kevman 2:7aab896b1a3b 477 /***************************************************/
kevman 2:7aab896b1a3b 478 spif_bd_error SPIFBlockDevice::_spi_set_frequency(int freq)
kevman 2:7aab896b1a3b 479 {
kevman 2:7aab896b1a3b 480 _spi.frequency(freq);
kevman 2:7aab896b1a3b 481 return SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 482 }
kevman 2:7aab896b1a3b 483
kevman 2:7aab896b1a3b 484 spif_bd_error SPIFBlockDevice::_spi_send_read_command(int read_inst, uint8_t *buffer, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 485 {
kevman 2:7aab896b1a3b 486 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
kevman 2:7aab896b1a3b 487 int dummy_byte = 0;
kevman 2:7aab896b1a3b 488
kevman 2:7aab896b1a3b 489 // csel must go low for the entire command (Inst, Address and Data)
kevman 2:7aab896b1a3b 490 _cs = 0;
kevman 2:7aab896b1a3b 491
kevman 2:7aab896b1a3b 492 // Write 1 byte Instruction
kevman 2:7aab896b1a3b 493 _spi.write(read_inst);
kevman 2:7aab896b1a3b 494
kevman 2:7aab896b1a3b 495 // Write Address (can be either 3 or 4 bytes long)
kevman 2:7aab896b1a3b 496 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
kevman 2:7aab896b1a3b 497 _spi.write((addr >> address_shift) & 0xFF);
kevman 2:7aab896b1a3b 498 }
kevman 2:7aab896b1a3b 499
kevman 2:7aab896b1a3b 500 // Write Dummy Cycles Bytes
kevman 2:7aab896b1a3b 501 for (uint32_t i = 0; i < dummy_bytes; i++) {
kevman 2:7aab896b1a3b 502 _spi.write(dummy_byte);
kevman 2:7aab896b1a3b 503 }
kevman 2:7aab896b1a3b 504
kevman 2:7aab896b1a3b 505 // Read Data
kevman 2:7aab896b1a3b 506 for (bd_size_t i = 0; i < size; i++) {
kevman 2:7aab896b1a3b 507 buffer[i] = _spi.write(0);
kevman 2:7aab896b1a3b 508 }
kevman 2:7aab896b1a3b 509
kevman 2:7aab896b1a3b 510 // csel back to high
kevman 2:7aab896b1a3b 511 _cs = 1;
kevman 2:7aab896b1a3b 512 return SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 513 }
kevman 2:7aab896b1a3b 514
kevman 2:7aab896b1a3b 515 spif_bd_error SPIFBlockDevice::_spi_send_program_command(int prog_inst, const void *buffer, bd_addr_t addr,
kevman 2:7aab896b1a3b 516 bd_size_t size)
kevman 2:7aab896b1a3b 517 {
kevman 2:7aab896b1a3b 518 // Send Program (write) command to device driver
kevman 2:7aab896b1a3b 519 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
kevman 2:7aab896b1a3b 520 int dummy_byte = 0;
kevman 2:7aab896b1a3b 521 uint8_t *data = (uint8_t *)buffer;
kevman 2:7aab896b1a3b 522
kevman 2:7aab896b1a3b 523 // csel must go low for the entire command (Inst, Address and Data)
kevman 2:7aab896b1a3b 524 _cs = 0;
kevman 2:7aab896b1a3b 525
kevman 2:7aab896b1a3b 526 // Write 1 byte Instruction
kevman 2:7aab896b1a3b 527 _spi.write(prog_inst);
kevman 2:7aab896b1a3b 528
kevman 2:7aab896b1a3b 529 // Write Address (can be either 3 or 4 bytes long)
kevman 2:7aab896b1a3b 530 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
kevman 2:7aab896b1a3b 531 _spi.write((addr >> address_shift) & 0xFF);
kevman 2:7aab896b1a3b 532 }
kevman 2:7aab896b1a3b 533
kevman 2:7aab896b1a3b 534 // Write Dummy Cycles Bytes
kevman 2:7aab896b1a3b 535 for (uint32_t i = 0; i < dummy_bytes; i++) {
kevman 2:7aab896b1a3b 536 _spi.write(dummy_byte);
kevman 2:7aab896b1a3b 537 }
kevman 2:7aab896b1a3b 538
kevman 2:7aab896b1a3b 539 // Write Data
kevman 2:7aab896b1a3b 540 for (bd_size_t i = 0; i < size; i++) {
kevman 2:7aab896b1a3b 541 _spi.write(data[i]);
kevman 2:7aab896b1a3b 542 }
kevman 2:7aab896b1a3b 543
kevman 2:7aab896b1a3b 544 // csel back to high
kevman 2:7aab896b1a3b 545 _cs = 1;
kevman 2:7aab896b1a3b 546
kevman 2:7aab896b1a3b 547 return SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 548 }
kevman 2:7aab896b1a3b 549
kevman 2:7aab896b1a3b 550 spif_bd_error SPIFBlockDevice::_spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 551 {
kevman 2:7aab896b1a3b 552 tr_info("INFO: Erase Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size);
kevman 2:7aab896b1a3b 553 addr = (((int)addr) & 0x00FFF000);
kevman 2:7aab896b1a3b 554 _spi_send_general_command(erase_inst, addr, NULL, 0, NULL, 0);
kevman 2:7aab896b1a3b 555 return SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 556 }
kevman 2:7aab896b1a3b 557
kevman 2:7aab896b1a3b 558 spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_addr_t addr, char *tx_buffer,
kevman 2:7aab896b1a3b 559 size_t tx_length, char *rx_buffer, size_t rx_length)
kevman 2:7aab896b1a3b 560 {
kevman 2:7aab896b1a3b 561 // Send a general command Instruction to driver
kevman 2:7aab896b1a3b 562 uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
kevman 2:7aab896b1a3b 563 uint8_t dummy_byte = 0x00;
kevman 2:7aab896b1a3b 564
kevman 2:7aab896b1a3b 565 // csel must go low for the entire command (Inst, Address and Data)
kevman 2:7aab896b1a3b 566 _cs = 0;
kevman 2:7aab896b1a3b 567
kevman 2:7aab896b1a3b 568 // Write 1 byte Instruction
kevman 2:7aab896b1a3b 569 _spi.write(instruction);
kevman 2:7aab896b1a3b 570
kevman 2:7aab896b1a3b 571 // Reading SPI Bus registers does not require Flash Address
kevman 2:7aab896b1a3b 572 if (addr != SPI_NO_ADDRESS_COMMAND) {
kevman 2:7aab896b1a3b 573 // Write Address (can be either 3 or 4 bytes long)
kevman 2:7aab896b1a3b 574 for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
kevman 2:7aab896b1a3b 575 _spi.write((addr >> address_shift) & 0xFF);
kevman 2:7aab896b1a3b 576 }
kevman 2:7aab896b1a3b 577
kevman 2:7aab896b1a3b 578 // Write Dummy Cycles Bytes
kevman 2:7aab896b1a3b 579 for (uint32_t i = 0; i < dummy_bytes; i++) {
kevman 2:7aab896b1a3b 580 _spi.write(dummy_byte);
kevman 2:7aab896b1a3b 581 }
kevman 2:7aab896b1a3b 582 }
kevman 2:7aab896b1a3b 583
kevman 2:7aab896b1a3b 584 // Read/Write Data
kevman 2:7aab896b1a3b 585 _spi.write(tx_buffer, (int)tx_length, rx_buffer, (int)rx_length);
kevman 2:7aab896b1a3b 586
kevman 2:7aab896b1a3b 587 // csel back to high
kevman 2:7aab896b1a3b 588 _cs = 1;
kevman 2:7aab896b1a3b 589
kevman 2:7aab896b1a3b 590 return SPIF_BD_ERROR_OK;
kevman 2:7aab896b1a3b 591 }
kevman 2:7aab896b1a3b 592
kevman 2:7aab896b1a3b 593 /*********************************************************/
kevman 2:7aab896b1a3b 594 /********** SFDP Parsing and Detection Functions *********/
kevman 2:7aab896b1a3b 595 /*********************************************************/
kevman 2:7aab896b1a3b 596 int SPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size)
kevman 2:7aab896b1a3b 597 {
kevman 2:7aab896b1a3b 598 uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
kevman 2:7aab896b1a3b 599 uint32_t tmp_region_size = 0;
kevman 2:7aab896b1a3b 600 int i_ind = 0;
kevman 2:7aab896b1a3b 601 int prev_boundary = 0;
kevman 2:7aab896b1a3b 602 // Default set to all type bits 1-4 are common
kevman 2:7aab896b1a3b 603 int min_common_erase_type_bits = ERASE_BITMASK_ALL;
kevman 2:7aab896b1a3b 604
kevman 2:7aab896b1a3b 605
kevman 2:7aab896b1a3b 606 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/,
kevman 2:7aab896b1a3b 607 sector_map_table_size);
kevman 2:7aab896b1a3b 608 if (status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 609 tr_error("ERROR: init - Read SFDP First Table Failed");
kevman 2:7aab896b1a3b 610 return -1;
kevman 2:7aab896b1a3b 611 }
kevman 2:7aab896b1a3b 612
kevman 2:7aab896b1a3b 613 // Currently we support only Single Map Descriptor
kevman 2:7aab896b1a3b 614 if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
kevman 2:7aab896b1a3b 615 tr_error("ERROR: Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
kevman 2:7aab896b1a3b 616 return -1;
kevman 2:7aab896b1a3b 617 }
kevman 2:7aab896b1a3b 618
kevman 2:7aab896b1a3b 619 _regions_count = sector_map_table[2] + 1;
kevman 2:7aab896b1a3b 620 if (_regions_count > SPIF_MAX_REGIONS) {
kevman 2:7aab896b1a3b 621 tr_error("ERROR: Supporting up to %d regions, current setup to %d regions - fail",
kevman 2:7aab896b1a3b 622 SPIF_MAX_REGIONS, _regions_count);
kevman 2:7aab896b1a3b 623 return -1;
kevman 2:7aab896b1a3b 624 }
kevman 2:7aab896b1a3b 625
kevman 2:7aab896b1a3b 626 // Loop through Regions and set for each one: size, supported erase types, high boundary offset
kevman 2:7aab896b1a3b 627 // Calculate minimum Common Erase Type for all Regions
kevman 2:7aab896b1a3b 628 for (i_ind = 0; i_ind < _regions_count; i_ind++) {
kevman 2:7aab896b1a3b 629 tmp_region_size = ((*((uint32_t *)&sector_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
kevman 2:7aab896b1a3b 630 _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
kevman 2:7aab896b1a3b 631 _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
kevman 2:7aab896b1a3b 632 min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind];
kevman 2:7aab896b1a3b 633 _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary;
kevman 2:7aab896b1a3b 634 prev_boundary = _region_high_boundary[i_ind] + 1;
kevman 2:7aab896b1a3b 635 }
kevman 2:7aab896b1a3b 636
kevman 2:7aab896b1a3b 637 // Calc minimum Common Erase Size from min_common_erase_type_bits
kevman 2:7aab896b1a3b 638 uint8_t type_mask = ERASE_BITMASK_TYPE1;
kevman 2:7aab896b1a3b 639 for (i_ind = 0; i_ind < 4; i_ind++) {
kevman 2:7aab896b1a3b 640 if (min_common_erase_type_bits & type_mask) {
kevman 2:7aab896b1a3b 641 _min_common_erase_size = _erase_type_size_arr[i_ind];
kevman 2:7aab896b1a3b 642 break;
kevman 2:7aab896b1a3b 643 }
kevman 2:7aab896b1a3b 644 type_mask = type_mask << 1;
kevman 2:7aab896b1a3b 645 }
kevman 2:7aab896b1a3b 646
kevman 2:7aab896b1a3b 647 if (i_ind == 4) {
kevman 2:7aab896b1a3b 648 // No common erase type was found between regions
kevman 2:7aab896b1a3b 649 _min_common_erase_size = 0;
kevman 2:7aab896b1a3b 650 }
kevman 2:7aab896b1a3b 651
kevman 2:7aab896b1a3b 652 return 0;
kevman 2:7aab896b1a3b 653 }
kevman 2:7aab896b1a3b 654
kevman 2:7aab896b1a3b 655 int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size)
kevman 2:7aab896b1a3b 656 {
kevman 2:7aab896b1a3b 657 uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
kevman 2:7aab896b1a3b 658 //memset(param_table, 0, SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES);
kevman 2:7aab896b1a3b 659
kevman 2:7aab896b1a3b 660 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, param_table, basic_table_addr /*address*/,
kevman 2:7aab896b1a3b 661 basic_table_size);
kevman 2:7aab896b1a3b 662 if (status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 663 tr_error("ERROR: init - Read SFDP First Table Failed");
kevman 2:7aab896b1a3b 664 return -1;
kevman 2:7aab896b1a3b 665 }
kevman 2:7aab896b1a3b 666
kevman 2:7aab896b1a3b 667 // Check address size, currently only supports 3byte addresses
kevman 2:7aab896b1a3b 668 if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) {
kevman 2:7aab896b1a3b 669 tr_error("ERROR: init - verify 3byte addressing Failed");
kevman 2:7aab896b1a3b 670 return -1;
kevman 2:7aab896b1a3b 671 }
kevman 2:7aab896b1a3b 672
kevman 2:7aab896b1a3b 673 // Get device density (stored in bits - 1)
kevman 2:7aab896b1a3b 674 uint32_t density_bits = (
kevman 2:7aab896b1a3b 675 (param_table[7] << 24) |
kevman 2:7aab896b1a3b 676 (param_table[6] << 16) |
kevman 2:7aab896b1a3b 677 (param_table[5] << 8) |
kevman 2:7aab896b1a3b 678 param_table[4]);
kevman 2:7aab896b1a3b 679 _device_size_bytes = (density_bits + 1) / 8;
kevman 2:7aab896b1a3b 680
kevman 2:7aab896b1a3b 681 // Set Default read/program/erase Instructions
kevman 2:7aab896b1a3b 682 _read_instruction = SPIF_READ;
kevman 2:7aab896b1a3b 683 _prog_instruction = SPIF_PP;
kevman 2:7aab896b1a3b 684 _erase_instruction = SPIF_SE;
kevman 2:7aab896b1a3b 685
kevman 2:7aab896b1a3b 686 // Set Page Size (SPI write must be done on Page limits)
kevman 2:7aab896b1a3b 687 _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size);
kevman 2:7aab896b1a3b 688
kevman 2:7aab896b1a3b 689 // Detect and Set Erase Types
kevman 2:7aab896b1a3b 690 _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr,
kevman 2:7aab896b1a3b 691 _erase_type_size_arr);
kevman 2:7aab896b1a3b 692 _erase_instruction = _erase4k_inst;
kevman 2:7aab896b1a3b 693
kevman 2:7aab896b1a3b 694 // Detect and Set fastest Bus mode (default 1-1-1)
kevman 2:7aab896b1a3b 695 _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, _read_instruction);
kevman 2:7aab896b1a3b 696
kevman 2:7aab896b1a3b 697 return 0;
kevman 2:7aab896b1a3b 698 }
kevman 2:7aab896b1a3b 699
kevman 2:7aab896b1a3b 700 int SPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
kevman 2:7aab896b1a3b 701 uint32_t &sector_map_table_addr, size_t &sector_map_table_size)
kevman 2:7aab896b1a3b 702 {
kevman 2:7aab896b1a3b 703 uint8_t sfdp_header[16];
kevman 2:7aab896b1a3b 704 uint8_t param_header[SPIF_SFDP_HEADER_SIZE];
kevman 2:7aab896b1a3b 705 size_t data_length = SPIF_SFDP_HEADER_SIZE;
kevman 2:7aab896b1a3b 706 bd_addr_t addr = 0x0;
kevman 2:7aab896b1a3b 707
kevman 2:7aab896b1a3b 708 // Set 1-1-1 bus mode for SFDP header parsing
kevman 2:7aab896b1a3b 709 // Initial SFDP read tables are read with 8 dummy cycles
kevman 2:7aab896b1a3b 710 _read_dummy_and_mode_cycles = 8;
kevman 2:7aab896b1a3b 711 _dummy_and_mode_cycles = 8;
kevman 2:7aab896b1a3b 712
kevman 2:7aab896b1a3b 713 spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sfdp_header, addr /*address*/, data_length);
kevman 2:7aab896b1a3b 714 if (status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 715 tr_error("ERROR: init - Read SFDP Failed");
kevman 2:7aab896b1a3b 716 return -1;
kevman 2:7aab896b1a3b 717 }
kevman 2:7aab896b1a3b 718
kevman 2:7aab896b1a3b 719 // Verify SFDP signature for sanity
kevman 2:7aab896b1a3b 720 // Also check that major/minor version is acceptable
kevman 2:7aab896b1a3b 721 if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) {
kevman 2:7aab896b1a3b 722 tr_error("ERROR: init - _verify SFDP signature and version Failed");
kevman 2:7aab896b1a3b 723 return -1;
kevman 2:7aab896b1a3b 724 } else {
kevman 2:7aab896b1a3b 725 tr_info("INFO: init - verified SFDP Signature and version Successfully");
kevman 2:7aab896b1a3b 726 }
kevman 2:7aab896b1a3b 727
kevman 2:7aab896b1a3b 728 // Discover Number of Parameter Headers
kevman 2:7aab896b1a3b 729 int number_of_param_headers = (int)(sfdp_header[6]) + 1;
kevman 2:7aab896b1a3b 730 tr_debug("DEBUG: number of Param Headers: %d", number_of_param_headers);
kevman 2:7aab896b1a3b 731
kevman 2:7aab896b1a3b 732
kevman 2:7aab896b1a3b 733 addr += SPIF_SFDP_HEADER_SIZE;
kevman 2:7aab896b1a3b 734 data_length = SPIF_PARAM_HEADER_SIZE;
kevman 2:7aab896b1a3b 735
kevman 2:7aab896b1a3b 736 // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table)
kevman 2:7aab896b1a3b 737 for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) {
kevman 2:7aab896b1a3b 738
kevman 2:7aab896b1a3b 739 status = _spi_send_read_command(SPIF_SFDP, param_header, addr, data_length);
kevman 2:7aab896b1a3b 740 if (status != SPIF_BD_ERROR_OK) {
kevman 2:7aab896b1a3b 741 tr_error("ERROR: init - Read Param Table %d Failed", i_ind + 1);
kevman 2:7aab896b1a3b 742 return -1;
kevman 2:7aab896b1a3b 743 }
kevman 2:7aab896b1a3b 744
kevman 2:7aab896b1a3b 745 // The SFDP spec indicates the standard table is always at offset 0
kevman 2:7aab896b1a3b 746 // in the parameter headers, we check just to be safe
kevman 2:7aab896b1a3b 747 if (param_header[2] != 1) {
kevman 2:7aab896b1a3b 748 tr_error("ERROR: Param Table %d - Major Version should be 1!", i_ind + 1);
kevman 2:7aab896b1a3b 749 return -1;
kevman 2:7aab896b1a3b 750 }
kevman 2:7aab896b1a3b 751
kevman 2:7aab896b1a3b 752 if ((param_header[0] == 0) && (param_header[7] == 0xFF)) {
kevman 2:7aab896b1a3b 753 // Found Basic Params Table: LSB=0x00, MSB=0xFF
kevman 2:7aab896b1a3b 754 tr_debug("DEBUG: Found Basic Param Table at Table: %d", i_ind + 1);
kevman 2:7aab896b1a3b 755 basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
kevman 2:7aab896b1a3b 756 // Supporting up to 64 Bytes Table (16 DWORDS)
kevman 2:7aab896b1a3b 757 basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64;
kevman 2:7aab896b1a3b 758
kevman 2:7aab896b1a3b 759 } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) {
kevman 2:7aab896b1a3b 760 // Found Sector Map Table: LSB=0x81, MSB=0xFF
kevman 2:7aab896b1a3b 761 tr_debug("DEBUG: Found Sector Map Table at Table: %d", i_ind + 1);
kevman 2:7aab896b1a3b 762 sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
kevman 2:7aab896b1a3b 763 sector_map_table_size = param_header[3] * 4;
kevman 2:7aab896b1a3b 764
kevman 2:7aab896b1a3b 765 }
kevman 2:7aab896b1a3b 766 addr += SPIF_PARAM_HEADER_SIZE;
kevman 2:7aab896b1a3b 767
kevman 2:7aab896b1a3b 768 }
kevman 2:7aab896b1a3b 769 return 0;
kevman 2:7aab896b1a3b 770 }
kevman 2:7aab896b1a3b 771
kevman 2:7aab896b1a3b 772 unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
kevman 2:7aab896b1a3b 773 {
kevman 2:7aab896b1a3b 774 unsigned int page_size = SPIF_DEFAULT_PAGE_SIZE;
kevman 2:7aab896b1a3b 775
kevman 2:7aab896b1a3b 776 if (basic_param_table_size > SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE) {
kevman 2:7aab896b1a3b 777 // Page Size is specified by 4 Bits (N), calculated by 2^N
kevman 2:7aab896b1a3b 778 int page_to_power_size = ((int)basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4;
kevman 2:7aab896b1a3b 779 page_size = local_math_power(2, page_to_power_size);
kevman 2:7aab896b1a3b 780 tr_debug("DEBUG: Detected Page Size: %d", page_size);
kevman 2:7aab896b1a3b 781 } else {
kevman 2:7aab896b1a3b 782 tr_debug("DEBUG: Using Default Page Size: %d", page_size);
kevman 2:7aab896b1a3b 783 }
kevman 2:7aab896b1a3b 784 return page_size;
kevman 2:7aab896b1a3b 785 }
kevman 2:7aab896b1a3b 786
kevman 2:7aab896b1a3b 787 int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
kevman 2:7aab896b1a3b 788 int &erase4k_inst,
kevman 2:7aab896b1a3b 789 int *erase_type_inst_arr, unsigned int *erase_type_size_arr)
kevman 2:7aab896b1a3b 790 {
kevman 2:7aab896b1a3b 791 erase4k_inst = 0xff;
kevman 2:7aab896b1a3b 792 bool found_4Kerase_type = false;
kevman 2:7aab896b1a3b 793 uint8_t bitfield = 0x01;
kevman 2:7aab896b1a3b 794
kevman 2:7aab896b1a3b 795 // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K
kevman 2:7aab896b1a3b 796 erase4k_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE];
kevman 2:7aab896b1a3b 797
kevman 2:7aab896b1a3b 798 if (basic_param_table_size > SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) {
kevman 2:7aab896b1a3b 799 // Loop Erase Types 1-4
kevman 2:7aab896b1a3b 800 for (int i_ind = 0; i_ind < 4; i_ind++) {
kevman 2:7aab896b1a3b 801 erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
kevman 2:7aab896b1a3b 802 erase_type_size_arr[i_ind] = local_math_power(2,
kevman 2:7aab896b1a3b 803 basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
kevman 2:7aab896b1a3b 804 tr_info("DEBUG: Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
kevman 2:7aab896b1a3b 805 erase_type_size_arr[i_ind]);
kevman 2:7aab896b1a3b 806 if (erase_type_size_arr[i_ind] > 1) {
kevman 2:7aab896b1a3b 807 // if size==1 type is not supported
kevman 2:7aab896b1a3b 808 erase_type_inst_arr[i_ind] = basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
kevman 2:7aab896b1a3b 809
kevman 2:7aab896b1a3b 810 if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) {
kevman 2:7aab896b1a3b 811 //Set default minimal common erase for singal region
kevman 2:7aab896b1a3b 812 _min_common_erase_size = erase_type_size_arr[i_ind];
kevman 2:7aab896b1a3b 813 }
kevman 2:7aab896b1a3b 814
kevman 2:7aab896b1a3b 815 // SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction
kevman 2:7aab896b1a3b 816 if (erase_type_size_arr[i_ind] == 4096) {
kevman 2:7aab896b1a3b 817 found_4Kerase_type = true;
kevman 2:7aab896b1a3b 818 if (erase4k_inst != erase_type_inst_arr[i_ind]) {
kevman 2:7aab896b1a3b 819 //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table
kevman 2:7aab896b1a3b 820 erase4k_inst = erase_type_inst_arr[i_ind];
kevman 2:7aab896b1a3b 821 tr_warning("WARNING: _detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
kevman 2:7aab896b1a3b 822
kevman 2:7aab896b1a3b 823 }
kevman 2:7aab896b1a3b 824 }
kevman 2:7aab896b1a3b 825 _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt;
kevman 2:7aab896b1a3b 826 }
kevman 2:7aab896b1a3b 827
kevman 2:7aab896b1a3b 828 tr_info("INFO: Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
kevman 2:7aab896b1a3b 829 erase_type_size_arr[i_ind]);
kevman 2:7aab896b1a3b 830 bitfield = bitfield << 1;
kevman 2:7aab896b1a3b 831 }
kevman 2:7aab896b1a3b 832 }
kevman 2:7aab896b1a3b 833
kevman 2:7aab896b1a3b 834 if (false == found_4Kerase_type) {
kevman 2:7aab896b1a3b 835 tr_warning("WARNING: Couldn't find Erase Type for 4KB size");
kevman 2:7aab896b1a3b 836 }
kevman 2:7aab896b1a3b 837 return 0;
kevman 2:7aab896b1a3b 838 }
kevman 2:7aab896b1a3b 839
kevman 2:7aab896b1a3b 840 int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
kevman 2:7aab896b1a3b 841 int &read_inst)
kevman 2:7aab896b1a3b 842 {
kevman 2:7aab896b1a3b 843 do {
kevman 2:7aab896b1a3b 844
kevman 2:7aab896b1a3b 845 // TBD - SPIF Dual Read Modes Require SPI driver support
kevman 2:7aab896b1a3b 846 /*
kevman 2:7aab896b1a3b 847 uint8_t examined_byte;
kevman 2:7aab896b1a3b 848
kevman 2:7aab896b1a3b 849 if (basic_param_table_size > SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE) {
kevman 2:7aab896b1a3b 850 examined_byte = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
kevman 2:7aab896b1a3b 851 if (examined_byte & 0x01) {
kevman 2:7aab896b1a3b 852 // Fast Read 2-2-2 Supported
kevman 2:7aab896b1a3b 853 read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE];
kevman 2:7aab896b1a3b 854 _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5)
kevman 2:7aab896b1a3b 855 + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F);
kevman 2:7aab896b1a3b 856 tr_info("\nDEBUG: Read Bus Mode set to 2-2-2, Instruction: 0x%xh", read_inst);
kevman 2:7aab896b1a3b 857 break;
kevman 2:7aab896b1a3b 858 }
kevman 2:7aab896b1a3b 859 }
kevman 2:7aab896b1a3b 860 examined_byte = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
kevman 2:7aab896b1a3b 861 if (examined_byte & 0x20) {
kevman 2:7aab896b1a3b 862 // Fast Read 1-2-2 Supported
kevman 2:7aab896b1a3b 863 read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE];
kevman 2:7aab896b1a3b 864 _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5)
kevman 2:7aab896b1a3b 865 + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F);
kevman 2:7aab896b1a3b 866 tr_debug("\nDEBUG: Read Bus Mode set to 1-2-2, Instruction: 0x%xh", read_inst);
kevman 2:7aab896b1a3b 867 break;
kevman 2:7aab896b1a3b 868 }
kevman 2:7aab896b1a3b 869 if (examined_byte & 0x01) {
kevman 2:7aab896b1a3b 870 // Fast Read 1-1-2 Supported
kevman 2:7aab896b1a3b 871 read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE];
kevman 2:7aab896b1a3b 872 _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5)
kevman 2:7aab896b1a3b 873 + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F);
kevman 2:7aab896b1a3b 874 tr_debug("\nDEBUG: Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction);
kevman 2:7aab896b1a3b 875 break;
kevman 2:7aab896b1a3b 876 }
kevman 2:7aab896b1a3b 877 */
kevman 2:7aab896b1a3b 878 _read_dummy_and_mode_cycles = 0;
kevman 2:7aab896b1a3b 879 tr_debug("\nDEBUG: Read Bus Mode set to 1-1-1, Instruction: 0x%xh", read_inst);
kevman 2:7aab896b1a3b 880 } while (false);
kevman 2:7aab896b1a3b 881
kevman 2:7aab896b1a3b 882 return 0;
kevman 2:7aab896b1a3b 883 }
kevman 2:7aab896b1a3b 884
kevman 2:7aab896b1a3b 885 int SPIFBlockDevice::_reset_flash_mem()
kevman 2:7aab896b1a3b 886 {
kevman 2:7aab896b1a3b 887 // Perform Soft Reset of the Device prior to initialization
kevman 2:7aab896b1a3b 888 int status = 0;
kevman 2:7aab896b1a3b 889 char status_value[2] = {0};
kevman 2:7aab896b1a3b 890 tr_info("INFO: _reset_flash_mem:\n");
kevman 2:7aab896b1a3b 891 //Read the Status Register from device
kevman 2:7aab896b1a3b 892 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 1)) {
kevman 2:7aab896b1a3b 893 // store received values in status_value
kevman 2:7aab896b1a3b 894 tr_debug("DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_value[0]);
kevman 2:7aab896b1a3b 895 } else {
kevman 2:7aab896b1a3b 896 tr_debug("ERROR: Reading Status Register failed\n");
kevman 2:7aab896b1a3b 897 status = -1;
kevman 2:7aab896b1a3b 898 }
kevman 2:7aab896b1a3b 899
kevman 2:7aab896b1a3b 900 if (0 == status) {
kevman 2:7aab896b1a3b 901 //Send Reset Enable
kevman 2:7aab896b1a3b 902 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RSTEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
kevman 2:7aab896b1a3b 903 // store received values in status_value
kevman 2:7aab896b1a3b 904 tr_debug("DEBUG: Sending RSTEN Success\n");
kevman 2:7aab896b1a3b 905 } else {
kevman 2:7aab896b1a3b 906 tr_error("ERROR: Sending RSTEN failed\n");
kevman 2:7aab896b1a3b 907 status = -1;
kevman 2:7aab896b1a3b 908 }
kevman 2:7aab896b1a3b 909
kevman 2:7aab896b1a3b 910 if (0 == status) {
kevman 2:7aab896b1a3b 911 //Send Reset
kevman 2:7aab896b1a3b 912 if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RST, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
kevman 2:7aab896b1a3b 913 // store received values in status_value
kevman 2:7aab896b1a3b 914 tr_debug("DEBUG: Sending RST Success\n");
kevman 2:7aab896b1a3b 915 } else {
kevman 2:7aab896b1a3b 916 tr_error("ERROR: Sending RST failed\n");
kevman 2:7aab896b1a3b 917 status = -1;
kevman 2:7aab896b1a3b 918 }
kevman 2:7aab896b1a3b 919 _is_mem_ready();
kevman 2:7aab896b1a3b 920 }
kevman 2:7aab896b1a3b 921 }
kevman 2:7aab896b1a3b 922
kevman 2:7aab896b1a3b 923 return status;
kevman 2:7aab896b1a3b 924 }
kevman 2:7aab896b1a3b 925
kevman 2:7aab896b1a3b 926 bool SPIFBlockDevice::_is_mem_ready()
kevman 2:7aab896b1a3b 927 {
kevman 2:7aab896b1a3b 928 // Check Status Register Busy Bit to Verify the Device isn't Busy
kevman 2:7aab896b1a3b 929 char status_value[2];
kevman 2:7aab896b1a3b 930 int retries = 0;
kevman 2:7aab896b1a3b 931 bool mem_ready = true;
kevman 2:7aab896b1a3b 932
kevman 2:7aab896b1a3b 933 do {
kevman 2:7aab896b1a3b 934 wait_ms(1);
kevman 2:7aab896b1a3b 935 retries++;
kevman 2:7aab896b1a3b 936 //Read the Status Register from device
kevman 2:7aab896b1a3b 937 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
kevman 2:7aab896b1a3b 938 1)) { // store received values in status_value
kevman 2:7aab896b1a3b 939 tr_error("ERROR: Reading Status Register failed\n");
kevman 2:7aab896b1a3b 940 }
kevman 2:7aab896b1a3b 941 } while ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES);
kevman 2:7aab896b1a3b 942
kevman 2:7aab896b1a3b 943 if ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0) {
kevman 2:7aab896b1a3b 944 tr_error("ERROR: _is_mem_ready FALSE\n");
kevman 2:7aab896b1a3b 945 mem_ready = false;
kevman 2:7aab896b1a3b 946 }
kevman 2:7aab896b1a3b 947 return mem_ready;
kevman 2:7aab896b1a3b 948 }
kevman 2:7aab896b1a3b 949
kevman 2:7aab896b1a3b 950 int SPIFBlockDevice::_set_write_enable()
kevman 2:7aab896b1a3b 951 {
kevman 2:7aab896b1a3b 952 // Check Status Register Busy Bit to Verify the Device isn't Busy
kevman 2:7aab896b1a3b 953 char status_value[2];
kevman 2:7aab896b1a3b 954 int status = -1;
kevman 2:7aab896b1a3b 955
kevman 2:7aab896b1a3b 956 do {
kevman 2:7aab896b1a3b 957 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_WREN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
kevman 2:7aab896b1a3b 958 tr_error("ERROR:Sending WREN command FAILED\n");
kevman 2:7aab896b1a3b 959 break;
kevman 2:7aab896b1a3b 960 }
kevman 2:7aab896b1a3b 961
kevman 2:7aab896b1a3b 962 if (false == _is_mem_ready()) {
kevman 2:7aab896b1a3b 963 tr_error("ERROR: Device not ready, write failed");
kevman 2:7aab896b1a3b 964 break;
kevman 2:7aab896b1a3b 965 }
kevman 2:7aab896b1a3b 966
kevman 2:7aab896b1a3b 967 memset(status_value, 0, 2);
kevman 2:7aab896b1a3b 968 if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
kevman 2:7aab896b1a3b 969 1)) { // store received values in status_value
kevman 2:7aab896b1a3b 970 tr_error("ERROR: Reading Status Register failed\n");
kevman 2:7aab896b1a3b 971 break;
kevman 2:7aab896b1a3b 972 }
kevman 2:7aab896b1a3b 973
kevman 2:7aab896b1a3b 974 if ((status_value[0] & SPIF_STATUS_BIT_WEL) == 0) {
kevman 2:7aab896b1a3b 975 tr_error("ERROR: _set_write_enable failed\n");
kevman 2:7aab896b1a3b 976 break;
kevman 2:7aab896b1a3b 977 }
kevman 2:7aab896b1a3b 978 status = 0;
kevman 2:7aab896b1a3b 979 } while (false);
kevman 2:7aab896b1a3b 980 return status;
kevman 2:7aab896b1a3b 981 }
kevman 2:7aab896b1a3b 982
kevman 2:7aab896b1a3b 983 /*********************************************/
kevman 2:7aab896b1a3b 984 /************* Utility Functions *************/
kevman 2:7aab896b1a3b 985 /*********************************************/
kevman 2:7aab896b1a3b 986 int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset)
kevman 2:7aab896b1a3b 987 {
kevman 2:7aab896b1a3b 988 //Find the region to which the given offset belong to
kevman 2:7aab896b1a3b 989 if ((offset > _device_size_bytes) || (_regions_count == 0)) {
kevman 2:7aab896b1a3b 990 return -1;
kevman 2:7aab896b1a3b 991 }
kevman 2:7aab896b1a3b 992
kevman 2:7aab896b1a3b 993 if (_regions_count == 1) {
kevman 2:7aab896b1a3b 994 return 0;
kevman 2:7aab896b1a3b 995 }
kevman 2:7aab896b1a3b 996
kevman 2:7aab896b1a3b 997 for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) {
kevman 2:7aab896b1a3b 998
kevman 2:7aab896b1a3b 999 if (offset > _region_high_boundary[i_ind]) {
kevman 2:7aab896b1a3b 1000 return (i_ind + 1);
kevman 2:7aab896b1a3b 1001 }
kevman 2:7aab896b1a3b 1002 }
kevman 2:7aab896b1a3b 1003 return -1;
kevman 2:7aab896b1a3b 1004
kevman 2:7aab896b1a3b 1005 }
kevman 2:7aab896b1a3b 1006
kevman 2:7aab896b1a3b 1007 int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry)
kevman 2:7aab896b1a3b 1008 {
kevman 2:7aab896b1a3b 1009 // Iterate on all supported Erase Types of the Region to which the offset belong to.
kevman 2:7aab896b1a3b 1010 // Iterates from highest type to lowest
kevman 2:7aab896b1a3b 1011 uint8_t type_mask = ERASE_BITMASK_TYPE4;
kevman 2:7aab896b1a3b 1012 int i_ind = 0;
kevman 2:7aab896b1a3b 1013 int largest_erase_type = 0;
kevman 2:7aab896b1a3b 1014 for (i_ind = 3; i_ind >= 0; i_ind--) {
kevman 2:7aab896b1a3b 1015 if (bitfield & type_mask) {
kevman 2:7aab896b1a3b 1016 largest_erase_type = i_ind;
kevman 2:7aab896b1a3b 1017 if ((size > (int)(_erase_type_size_arr[largest_erase_type])) &&
kevman 2:7aab896b1a3b 1018 ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) {
kevman 2:7aab896b1a3b 1019 break;
kevman 2:7aab896b1a3b 1020 } else {
kevman 2:7aab896b1a3b 1021 bitfield &= ~type_mask;
kevman 2:7aab896b1a3b 1022 }
kevman 2:7aab896b1a3b 1023 }
kevman 2:7aab896b1a3b 1024 type_mask = type_mask >> 1;
kevman 2:7aab896b1a3b 1025 }
kevman 2:7aab896b1a3b 1026
kevman 2:7aab896b1a3b 1027 if (i_ind == 4) {
kevman 2:7aab896b1a3b 1028 tr_error("ERROR: no erase type was found for current region addr");
kevman 2:7aab896b1a3b 1029 }
kevman 2:7aab896b1a3b 1030 return largest_erase_type;
kevman 2:7aab896b1a3b 1031
kevman 2:7aab896b1a3b 1032 }
kevman 2:7aab896b1a3b 1033
kevman 2:7aab896b1a3b 1034 /*********************************************/
kevman 2:7aab896b1a3b 1035 /************** Local Functions **************/
kevman 2:7aab896b1a3b 1036 /*********************************************/
kevman 2:7aab896b1a3b 1037 static unsigned int local_math_power(int base, int exp)
kevman 2:7aab896b1a3b 1038 {
kevman 2:7aab896b1a3b 1039 // Integer X^Y function, used to calculate size fields given in 2^N format
kevman 2:7aab896b1a3b 1040 int result = 1;
kevman 2:7aab896b1a3b 1041 while (exp) {
kevman 2:7aab896b1a3b 1042 result *= base;
kevman 2:7aab896b1a3b 1043 exp--;
kevman 2:7aab896b1a3b 1044 }
kevman 2:7aab896b1a3b 1045 return result;
kevman 2:7aab896b1a3b 1046 }
kevman 2:7aab896b1a3b 1047
kevman 2:7aab896b1a3b 1048