Generic Pelion Device Management example for various U-blox-based boards.

Dependencies:   ublox-at-cellular-interface ublox-cellular-base

DEPRECATED

This example application is not maintained and not recommended. It uses an old version of Mbed OS, Pelion DM, and Arm toolchain. It doesn't work with Mbed Studio.

Please use: https://os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-pelion/

This example is known to work great on the following platforms:

For Odin-W2 please go to Repository link

Follow the Quick-Start instructions: https://cloud.mbed.com/quick-start

UBLOX_C030_U201

UBLOX_C030_R412M

Example functionality

This example showcases the following device functionality:

  • On user button click, increment Pelion LWM2M button resource.
  • Allow the user to change the state of the board LED from Pelion LWM2M led_state resource and PUT request.
  • (currently disabled) Read ADC temperature and ADC vref, and report them as Pelion LWM2M resources.

Use this example with Mbed CLI

1. Import the application into your desktop:

mbed import https://os.mbed.com/teams/ublox/code/pelion-example-common

cd pelion-example-common

2. Install the CLOUD_SDK_API_KEY

mbed config -G CLOUD_SDK_API_KEY <PELION_DM_API_KEY>

For instructions on how to generate your API key, please see the documentation.

3. Initialize firmware credentials (done once per repository). You can use the following command:

mbed dm init -d "<your company name in Pelion DM>" --model-name "<product model identifier>" -q --force

If above command do not work for your Mbed CLI, please consider upgrading Mbed CLI to version 1.8.x or above.

4. Compile and program:

mbed compile -t <toolchain> -m <TARGET_BOARD>

(supported toolchains : GCC_ARM / ARM / IAR)

Committer:
screamer
Date:
Mon Dec 10 21:58:43 2018 +0000
Revision:
0:a076a1bbe630
Initial revision

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:a076a1bbe630 1 /* mbed Microcontroller Library
screamer 0:a076a1bbe630 2 * Copyright (c) 2018 ARM Limited
screamer 0:a076a1bbe630 3 *
screamer 0:a076a1bbe630 4 * Licensed under the Apache License, Version 2.0 (the "License");
screamer 0:a076a1bbe630 5 * you may not use this file except in compliance with the License.
screamer 0:a076a1bbe630 6 * You may obtain a copy of the License at
screamer 0:a076a1bbe630 7 *
screamer 0:a076a1bbe630 8 * http://www.apache.org/licenses/LICENSE-2.0
screamer 0:a076a1bbe630 9 *
screamer 0:a076a1bbe630 10 * Unless required by applicable law or agreed to in writing, software
screamer 0:a076a1bbe630 11 * distributed under the License is distributed on an "AS IS" BASIS,
screamer 0:a076a1bbe630 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 0:a076a1bbe630 13 * See the License for the specific language governing permissions and
screamer 0:a076a1bbe630 14 * limitations under the License.
screamer 0:a076a1bbe630 15 */
screamer 0:a076a1bbe630 16
screamer 0:a076a1bbe630 17 #include "QSPIFBlockDevice.h"
screamer 0:a076a1bbe630 18 #include <string.h>
screamer 0:a076a1bbe630 19 #include "mbed_wait_api.h"
screamer 0:a076a1bbe630 20
screamer 0:a076a1bbe630 21 #ifndef MBED_CONF_MBED_TRACE_ENABLE
screamer 0:a076a1bbe630 22 #define MBED_CONF_MBED_TRACE_ENABLE 0
screamer 0:a076a1bbe630 23 #endif
screamer 0:a076a1bbe630 24
screamer 0:a076a1bbe630 25 #include "mbed_trace.h"
screamer 0:a076a1bbe630 26 #define TRACE_GROUP "QSPIF"
screamer 0:a076a1bbe630 27
screamer 0:a076a1bbe630 28 using namespace mbed;
screamer 0:a076a1bbe630 29
screamer 0:a076a1bbe630 30 /* Default QSPIF Parameters */
screamer 0:a076a1bbe630 31 /****************************/
screamer 0:a076a1bbe630 32 #define QSPIF_DEFAULT_READ_SIZE 1
screamer 0:a076a1bbe630 33 #define QSPIF_DEFAULT_PROG_SIZE 1
screamer 0:a076a1bbe630 34 #define QSPIF_DEFAULT_PAGE_SIZE 256
screamer 0:a076a1bbe630 35 #define QSPIF_DEFAULT_SE_SIZE 4096
screamer 0:a076a1bbe630 36 #define QSPI_MAX_STATUS_REGISTER_SIZE 3
screamer 0:a076a1bbe630 37 #ifndef UINT64_MAX
screamer 0:a076a1bbe630 38 #define UINT64_MAX -1
screamer 0:a076a1bbe630 39 #endif
screamer 0:a076a1bbe630 40 #define QSPI_NO_ADDRESS_COMMAND UINT64_MAX
screamer 0:a076a1bbe630 41 // Status Register Bits
screamer 0:a076a1bbe630 42 #define QSPIF_STATUS_BIT_WIP 0x1 //Write In Progress
screamer 0:a076a1bbe630 43 #define QSPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch
screamer 0:a076a1bbe630 44
screamer 0:a076a1bbe630 45 /* SFDP Header Parsing */
screamer 0:a076a1bbe630 46 /***********************/
screamer 0:a076a1bbe630 47 #define QSPIF_SFDP_HEADER_SIZE 8
screamer 0:a076a1bbe630 48 #define QSPIF_PARAM_HEADER_SIZE 8
screamer 0:a076a1bbe630 49
screamer 0:a076a1bbe630 50 /* Basic Parameters Table Parsing */
screamer 0:a076a1bbe630 51 /**********************************/
screamer 0:a076a1bbe630 52 #define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */
screamer 0:a076a1bbe630 53 //READ Instruction support according to BUS Configuration
screamer 0:a076a1bbe630 54 #define QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2
screamer 0:a076a1bbe630 55 #define QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16
screamer 0:a076a1bbe630 56 #define QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE 27
screamer 0:a076a1bbe630 57 #define QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE 9
screamer 0:a076a1bbe630 58 #define QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE 11
screamer 0:a076a1bbe630 59 #define QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23
screamer 0:a076a1bbe630 60 #define QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15
screamer 0:a076a1bbe630 61 #define QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13
screamer 0:a076a1bbe630 62 #define QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40
screamer 0:a076a1bbe630 63 // Quad Enable Params
screamer 0:a076a1bbe630 64 #define QSPIF_BASIC_PARAM_TABLE_QER_BYTE 58
screamer 0:a076a1bbe630 65 #define QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE 56
screamer 0:a076a1bbe630 66 // Erase Types Params
screamer 0:a076a1bbe630 67 #define QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29
screamer 0:a076a1bbe630 68 #define QSPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31
screamer 0:a076a1bbe630 69 #define QSPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33
screamer 0:a076a1bbe630 70 #define QSPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35
screamer 0:a076a1bbe630 71 #define QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28
screamer 0:a076a1bbe630 72 #define QSPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30
screamer 0:a076a1bbe630 73 #define QSPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32
screamer 0:a076a1bbe630 74 #define QSPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34
screamer 0:a076a1bbe630 75 #define QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1
screamer 0:a076a1bbe630 76
screamer 0:a076a1bbe630 77 // Erase Types Per Region BitMask
screamer 0:a076a1bbe630 78 #define ERASE_BITMASK_TYPE4 0x08
screamer 0:a076a1bbe630 79 #define ERASE_BITMASK_TYPE1 0x01
screamer 0:a076a1bbe630 80 #define ERASE_BITMASK_NONE 0x00
screamer 0:a076a1bbe630 81 #define ERASE_BITMASK_ALL 0x0F
screamer 0:a076a1bbe630 82
screamer 0:a076a1bbe630 83 #define IS_MEM_READY_MAX_RETRIES 10000
screamer 0:a076a1bbe630 84
screamer 0:a076a1bbe630 85 enum qspif_default_instructions {
screamer 0:a076a1bbe630 86 QSPIF_NOP = 0x00, // No operation
screamer 0:a076a1bbe630 87 QSPIF_PP = 0x02, // Page Program data
screamer 0:a076a1bbe630 88 QSPIF_READ = 0x03, // Read data
screamer 0:a076a1bbe630 89 QSPIF_SE = 0x20, // 4KB Sector Erase
screamer 0:a076a1bbe630 90 QSPIF_SFDP = 0x5a, // Read SFDP
screamer 0:a076a1bbe630 91 QSPIF_WRSR = 0x01, // Write Status/Configuration Register
screamer 0:a076a1bbe630 92 QSPIF_WRDI = 0x04, // Write Disable
screamer 0:a076a1bbe630 93 QSPIF_RDSR = 0x05, // Read Status Register
screamer 0:a076a1bbe630 94 QSPIF_WREN = 0x06, // Write Enable
screamer 0:a076a1bbe630 95 QSPIF_RSTEN = 0x66, // Reset Enable
screamer 0:a076a1bbe630 96 QSPIF_RST = 0x99, // Reset
screamer 0:a076a1bbe630 97 QSPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
screamer 0:a076a1bbe630 98 };
screamer 0:a076a1bbe630 99
screamer 0:a076a1bbe630 100 // Local Function
screamer 0:a076a1bbe630 101 static int local_math_power(int base, int exp);
screamer 0:a076a1bbe630 102
screamer 0:a076a1bbe630 103 /* Init function to initialize Different Devices CS static list */
screamer 0:a076a1bbe630 104 static PinName *generate_initialized_active_qspif_csel_arr();
screamer 0:a076a1bbe630 105 // Static Members for different devices csel
screamer 0:a076a1bbe630 106 // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
screamer 0:a076a1bbe630 107 SingletonPtr<PlatformMutex> QSPIFBlockDevice::_devices_mutex;
screamer 0:a076a1bbe630 108 int QSPIFBlockDevice::_number_of_active_qspif_flash_csel = 0;
screamer 0:a076a1bbe630 109 PinName *QSPIFBlockDevice::_active_qspif_flash_csel_arr = generate_initialized_active_qspif_csel_arr();
screamer 0:a076a1bbe630 110
screamer 0:a076a1bbe630 111 /********* Public API Functions *********/
screamer 0:a076a1bbe630 112 /****************************************/
screamer 0:a076a1bbe630 113 QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel,
screamer 0:a076a1bbe630 114 int clock_mode, int freq)
screamer 0:a076a1bbe630 115 : _qspi(io0, io1, io2, io3, sclk, csel, clock_mode), _csel(csel), _freq(freq), _device_size_bytes(0),
screamer 0:a076a1bbe630 116 _init_ref_count(0),
screamer 0:a076a1bbe630 117 _is_initialized(false)
screamer 0:a076a1bbe630 118 {
screamer 0:a076a1bbe630 119 _unique_device_status = add_new_csel_instance(csel);
screamer 0:a076a1bbe630 120
screamer 0:a076a1bbe630 121 if (_unique_device_status == 0) {
screamer 0:a076a1bbe630 122 tr_info("Adding a new QSPIFBlockDevice csel: %d\n", (int)csel);
screamer 0:a076a1bbe630 123 } else if (_unique_device_status == -1) {
screamer 0:a076a1bbe630 124 tr_error("QSPIFBlockDevice with the same csel(%d) already exists\n", (int)csel);
screamer 0:a076a1bbe630 125 } else {
screamer 0:a076a1bbe630 126 tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d\n", QSPIF_MAX_ACTIVE_FLASH_DEVICES);
screamer 0:a076a1bbe630 127 }
screamer 0:a076a1bbe630 128 }
screamer 0:a076a1bbe630 129
screamer 0:a076a1bbe630 130 int QSPIFBlockDevice::init()
screamer 0:a076a1bbe630 131 {
screamer 0:a076a1bbe630 132 if (_unique_device_status == 0) {
screamer 0:a076a1bbe630 133 tr_debug("QSPIFBlockDevice csel: %d", (int)_csel);
screamer 0:a076a1bbe630 134 } else if (_unique_device_status == -1) {
screamer 0:a076a1bbe630 135 tr_error("QSPIFBlockDevice with the same csel(%d) already exists", (int)_csel);
screamer 0:a076a1bbe630 136 return QSPIF_BD_ERROR_DEVICE_NOT_UNIQE;
screamer 0:a076a1bbe630 137 } else {
screamer 0:a076a1bbe630 138 tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d", QSPIF_MAX_ACTIVE_FLASH_DEVICES);
screamer 0:a076a1bbe630 139 return QSPIF_BD_ERROR_DEVICE_MAX_EXCEED;
screamer 0:a076a1bbe630 140 }
screamer 0:a076a1bbe630 141
screamer 0:a076a1bbe630 142 uint8_t vendor_device_ids[4];
screamer 0:a076a1bbe630 143 size_t data_length = 3;
screamer 0:a076a1bbe630 144 int status = QSPIF_BD_ERROR_OK;
screamer 0:a076a1bbe630 145 uint32_t basic_table_addr = 0;
screamer 0:a076a1bbe630 146 size_t basic_table_size = 0;
screamer 0:a076a1bbe630 147 uint32_t sector_map_table_addr = 0;
screamer 0:a076a1bbe630 148 size_t sector_map_table_size = 0;
screamer 0:a076a1bbe630 149 int qspi_status = QSPI_STATUS_OK;
screamer 0:a076a1bbe630 150
screamer 0:a076a1bbe630 151 _mutex.lock();
screamer 0:a076a1bbe630 152
screamer 0:a076a1bbe630 153 if (!_is_initialized) {
screamer 0:a076a1bbe630 154 _init_ref_count = 0;
screamer 0:a076a1bbe630 155 }
screamer 0:a076a1bbe630 156
screamer 0:a076a1bbe630 157 _init_ref_count++;
screamer 0:a076a1bbe630 158
screamer 0:a076a1bbe630 159 if (_init_ref_count != 1) {
screamer 0:a076a1bbe630 160 goto exit_point;
screamer 0:a076a1bbe630 161 }
screamer 0:a076a1bbe630 162
screamer 0:a076a1bbe630 163 //Initialize parameters
screamer 0:a076a1bbe630 164 _min_common_erase_size = 0;
screamer 0:a076a1bbe630 165 _regions_count = 1;
screamer 0:a076a1bbe630 166 _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
screamer 0:a076a1bbe630 167
screamer 0:a076a1bbe630 168 //Default Bus Setup 1_1_1 with 0 dummy and mode cycles
screamer 0:a076a1bbe630 169 _inst_width = QSPI_CFG_BUS_SINGLE;
screamer 0:a076a1bbe630 170 _address_width = QSPI_CFG_BUS_SINGLE;
screamer 0:a076a1bbe630 171 _address_size = QSPI_CFG_ADDR_SIZE_24;
screamer 0:a076a1bbe630 172 _data_width = QSPI_CFG_BUS_SINGLE;
screamer 0:a076a1bbe630 173 _dummy_and_mode_cycles = 0;
screamer 0:a076a1bbe630 174 _write_register_inst = QSPIF_WRSR;
screamer 0:a076a1bbe630 175 _read_register_inst = QSPIF_RDSR;
screamer 0:a076a1bbe630 176
screamer 0:a076a1bbe630 177
screamer 0:a076a1bbe630 178 if (QSPI_STATUS_OK != _qspi_set_frequency(_freq)) {
screamer 0:a076a1bbe630 179 tr_error("QSPI Set Frequency Failed");
screamer 0:a076a1bbe630 180 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 181 goto exit_point;
screamer 0:a076a1bbe630 182 }
screamer 0:a076a1bbe630 183
screamer 0:a076a1bbe630 184 // Soft Reset
screamer 0:a076a1bbe630 185 if (-1 == _reset_flash_mem()) {
screamer 0:a076a1bbe630 186 tr_error("Init - Unable to initialize flash memory, tests failed");
screamer 0:a076a1bbe630 187 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 188 goto exit_point;
screamer 0:a076a1bbe630 189 } else {
screamer 0:a076a1bbe630 190 tr_info("Initialize flash memory OK");
screamer 0:a076a1bbe630 191 }
screamer 0:a076a1bbe630 192
screamer 0:a076a1bbe630 193 /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/
screamer 0:a076a1bbe630 194 qspi_status = _qspi_send_general_command(QSPIF_RDID, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids,
screamer 0:a076a1bbe630 195 data_length);
screamer 0:a076a1bbe630 196 if (qspi_status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 197 tr_error("Init - Read Vendor ID Failed");
screamer 0:a076a1bbe630 198 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 199 goto exit_point;
screamer 0:a076a1bbe630 200 }
screamer 0:a076a1bbe630 201
screamer 0:a076a1bbe630 202 tr_debug("Vendor device ID = 0x%x 0x%x 0x%x 0x%x \n", vendor_device_ids[0],
screamer 0:a076a1bbe630 203 vendor_device_ids[1], vendor_device_ids[2], vendor_device_ids[3]);
screamer 0:a076a1bbe630 204 switch (vendor_device_ids[0]) {
screamer 0:a076a1bbe630 205 case 0xbf:
screamer 0:a076a1bbe630 206 // SST devices come preset with block protection
screamer 0:a076a1bbe630 207 // enabled for some regions, issue write disable instruction to clear
screamer 0:a076a1bbe630 208 _set_write_enable();
screamer 0:a076a1bbe630 209 _qspi_send_general_command(QSPIF_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
screamer 0:a076a1bbe630 210 break;
screamer 0:a076a1bbe630 211 }
screamer 0:a076a1bbe630 212
screamer 0:a076a1bbe630 213 //Synchronize Device
screamer 0:a076a1bbe630 214 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 215 tr_error("Init - _is_mem_ready Failed");
screamer 0:a076a1bbe630 216 status = QSPIF_BD_ERROR_READY_FAILED;
screamer 0:a076a1bbe630 217 goto exit_point;
screamer 0:a076a1bbe630 218 }
screamer 0:a076a1bbe630 219
screamer 0:a076a1bbe630 220 /**************************** Parse SFDP Header ***********************************/
screamer 0:a076a1bbe630 221 if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) {
screamer 0:a076a1bbe630 222 tr_error("Init - Parse SFDP Headers Failed");
screamer 0:a076a1bbe630 223 status = QSPIF_BD_ERROR_PARSING_FAILED;
screamer 0:a076a1bbe630 224 goto exit_point;
screamer 0:a076a1bbe630 225 }
screamer 0:a076a1bbe630 226
screamer 0:a076a1bbe630 227 /**************************** Parse Basic Parameters Table ***********************************/
screamer 0:a076a1bbe630 228 if (0 != _sfdp_parse_basic_param_table(basic_table_addr, basic_table_size)) {
screamer 0:a076a1bbe630 229 tr_error("Init - Parse Basic Param Table Failed");
screamer 0:a076a1bbe630 230 status = QSPIF_BD_ERROR_PARSING_FAILED;
screamer 0:a076a1bbe630 231 goto exit_point;
screamer 0:a076a1bbe630 232 }
screamer 0:a076a1bbe630 233
screamer 0:a076a1bbe630 234 /**************************** Parse Sector Map Table ***********************************/
screamer 0:a076a1bbe630 235 _region_size_bytes[0] =
screamer 0:a076a1bbe630 236 _device_size_bytes; // If there's no region map, we have a single region sized the entire device size
screamer 0:a076a1bbe630 237 _region_high_boundary[0] = _device_size_bytes - 1;
screamer 0:a076a1bbe630 238
screamer 0:a076a1bbe630 239 if ((sector_map_table_addr != 0) && (0 != sector_map_table_size)) {
screamer 0:a076a1bbe630 240 tr_info("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", sector_map_table_addr,
screamer 0:a076a1bbe630 241 sector_map_table_size);
screamer 0:a076a1bbe630 242 if (0 != _sfdp_parse_sector_map_table(sector_map_table_addr, sector_map_table_size)) {
screamer 0:a076a1bbe630 243 tr_error("Init - Parse Sector Map Table Failed");
screamer 0:a076a1bbe630 244 status = QSPIF_BD_ERROR_PARSING_FAILED;
screamer 0:a076a1bbe630 245 goto exit_point;
screamer 0:a076a1bbe630 246 }
screamer 0:a076a1bbe630 247 }
screamer 0:a076a1bbe630 248
screamer 0:a076a1bbe630 249 // Configure BUS Mode to 1_1_1 for all commands other than Read
screamer 0:a076a1bbe630 250 _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 251 QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
screamer 0:a076a1bbe630 252
screamer 0:a076a1bbe630 253 _is_initialized = true;
screamer 0:a076a1bbe630 254
screamer 0:a076a1bbe630 255 exit_point:
screamer 0:a076a1bbe630 256 _mutex.unlock();
screamer 0:a076a1bbe630 257
screamer 0:a076a1bbe630 258 return status;
screamer 0:a076a1bbe630 259 }
screamer 0:a076a1bbe630 260
screamer 0:a076a1bbe630 261 int QSPIFBlockDevice::deinit()
screamer 0:a076a1bbe630 262 {
screamer 0:a076a1bbe630 263 int result = QSPIF_BD_ERROR_OK;
screamer 0:a076a1bbe630 264
screamer 0:a076a1bbe630 265 _mutex.lock();
screamer 0:a076a1bbe630 266
screamer 0:a076a1bbe630 267 if (!_is_initialized) {
screamer 0:a076a1bbe630 268 _init_ref_count = 0;
screamer 0:a076a1bbe630 269 _mutex.unlock();
screamer 0:a076a1bbe630 270 return result;
screamer 0:a076a1bbe630 271 }
screamer 0:a076a1bbe630 272
screamer 0:a076a1bbe630 273 _init_ref_count--;
screamer 0:a076a1bbe630 274
screamer 0:a076a1bbe630 275 if (_init_ref_count) {
screamer 0:a076a1bbe630 276 _mutex.unlock();
screamer 0:a076a1bbe630 277 return result;
screamer 0:a076a1bbe630 278 }
screamer 0:a076a1bbe630 279
screamer 0:a076a1bbe630 280 // Disable Device for Writing
screamer 0:a076a1bbe630 281 qspi_status_t status = _qspi_send_general_command(QSPIF_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
screamer 0:a076a1bbe630 282 if (status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 283 tr_error("Write Disable failed");
screamer 0:a076a1bbe630 284 result = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 285 }
screamer 0:a076a1bbe630 286
screamer 0:a076a1bbe630 287 _is_initialized = false;
screamer 0:a076a1bbe630 288
screamer 0:a076a1bbe630 289 _mutex.unlock();
screamer 0:a076a1bbe630 290
screamer 0:a076a1bbe630 291 if (_unique_device_status == 0) {
screamer 0:a076a1bbe630 292 remove_csel_instance(_csel);
screamer 0:a076a1bbe630 293 }
screamer 0:a076a1bbe630 294
screamer 0:a076a1bbe630 295 return result;
screamer 0:a076a1bbe630 296 }
screamer 0:a076a1bbe630 297
screamer 0:a076a1bbe630 298 int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
screamer 0:a076a1bbe630 299 {
screamer 0:a076a1bbe630 300 int status = QSPIF_BD_ERROR_OK;
screamer 0:a076a1bbe630 301 tr_info("Read Inst: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 302
screamer 0:a076a1bbe630 303 _mutex.lock();
screamer 0:a076a1bbe630 304
screamer 0:a076a1bbe630 305 // Configure Bus for Reading
screamer 0:a076a1bbe630 306 _qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 307 QSPI_CFG_ALT_SIZE_8, _data_width, _dummy_and_mode_cycles);
screamer 0:a076a1bbe630 308
screamer 0:a076a1bbe630 309 if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) {
screamer 0:a076a1bbe630 310 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 311 tr_error("Read Command failed");
screamer 0:a076a1bbe630 312 }
screamer 0:a076a1bbe630 313
screamer 0:a076a1bbe630 314 // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus)
screamer 0:a076a1bbe630 315 _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 316 QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
screamer 0:a076a1bbe630 317
screamer 0:a076a1bbe630 318 _mutex.unlock();
screamer 0:a076a1bbe630 319 return status;
screamer 0:a076a1bbe630 320
screamer 0:a076a1bbe630 321 }
screamer 0:a076a1bbe630 322
screamer 0:a076a1bbe630 323 int QSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
screamer 0:a076a1bbe630 324 {
screamer 0:a076a1bbe630 325 qspi_status_t result = QSPI_STATUS_OK;
screamer 0:a076a1bbe630 326 bool program_failed = false;
screamer 0:a076a1bbe630 327 int status = QSPIF_BD_ERROR_OK;
screamer 0:a076a1bbe630 328 uint32_t offset = 0;
screamer 0:a076a1bbe630 329 uint32_t chunk = 0;
screamer 0:a076a1bbe630 330 bd_size_t written_bytes = 0;
screamer 0:a076a1bbe630 331
screamer 0:a076a1bbe630 332 tr_debug("Program - Buff: 0x%lxh, addr: %llu, size: %llu", (uint32_t)buffer, addr, size);
screamer 0:a076a1bbe630 333
screamer 0:a076a1bbe630 334 while (size > 0) {
screamer 0:a076a1bbe630 335 // Write on _page_size_bytes boundaries (Default 256 bytes a page)
screamer 0:a076a1bbe630 336 offset = addr % _page_size_bytes;
screamer 0:a076a1bbe630 337 chunk = (offset + size < _page_size_bytes) ? size : (_page_size_bytes - offset);
screamer 0:a076a1bbe630 338 written_bytes = chunk;
screamer 0:a076a1bbe630 339
screamer 0:a076a1bbe630 340 _mutex.lock();
screamer 0:a076a1bbe630 341
screamer 0:a076a1bbe630 342 //Send WREN
screamer 0:a076a1bbe630 343 if (_set_write_enable() != 0) {
screamer 0:a076a1bbe630 344 tr_error("Write Enabe failed");
screamer 0:a076a1bbe630 345 program_failed = true;
screamer 0:a076a1bbe630 346 status = QSPIF_BD_ERROR_WREN_FAILED;
screamer 0:a076a1bbe630 347 goto exit_point;
screamer 0:a076a1bbe630 348 }
screamer 0:a076a1bbe630 349
screamer 0:a076a1bbe630 350 result = _qspi_send_program_command(_prog_instruction, buffer, addr, &written_bytes);
screamer 0:a076a1bbe630 351 if ((result != QSPI_STATUS_OK) || (chunk != written_bytes)) {
screamer 0:a076a1bbe630 352 tr_error("Write failed");
screamer 0:a076a1bbe630 353 program_failed = true;
screamer 0:a076a1bbe630 354 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 355 goto exit_point;
screamer 0:a076a1bbe630 356 }
screamer 0:a076a1bbe630 357
screamer 0:a076a1bbe630 358 buffer = static_cast<const uint8_t *>(buffer) + chunk;
screamer 0:a076a1bbe630 359 addr += chunk;
screamer 0:a076a1bbe630 360 size -= chunk;
screamer 0:a076a1bbe630 361
screamer 0:a076a1bbe630 362 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 363 tr_error("Device not ready after write, failed");
screamer 0:a076a1bbe630 364 program_failed = true;
screamer 0:a076a1bbe630 365 status = QSPIF_BD_ERROR_READY_FAILED;
screamer 0:a076a1bbe630 366 goto exit_point;
screamer 0:a076a1bbe630 367 }
screamer 0:a076a1bbe630 368 _mutex.unlock();
screamer 0:a076a1bbe630 369 }
screamer 0:a076a1bbe630 370
screamer 0:a076a1bbe630 371 exit_point:
screamer 0:a076a1bbe630 372 if (program_failed) {
screamer 0:a076a1bbe630 373 _mutex.unlock();
screamer 0:a076a1bbe630 374 }
screamer 0:a076a1bbe630 375
screamer 0:a076a1bbe630 376 return status;
screamer 0:a076a1bbe630 377 }
screamer 0:a076a1bbe630 378
screamer 0:a076a1bbe630 379 int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
screamer 0:a076a1bbe630 380 {
screamer 0:a076a1bbe630 381 int type = 0;
screamer 0:a076a1bbe630 382 uint32_t offset = 0;
screamer 0:a076a1bbe630 383 uint32_t chunk = 4096;
screamer 0:a076a1bbe630 384 unsigned int cur_erase_inst = _erase_instruction;
screamer 0:a076a1bbe630 385 int size = (int)in_size;
screamer 0:a076a1bbe630 386 bool erase_failed = false;
screamer 0:a076a1bbe630 387 int status = QSPIF_BD_ERROR_OK;
screamer 0:a076a1bbe630 388 // Find region of erased address
screamer 0:a076a1bbe630 389 int region = _utils_find_addr_region(addr);
screamer 0:a076a1bbe630 390 // Erase Types of selected region
screamer 0:a076a1bbe630 391 uint8_t bitfield = _region_erase_types_bitfield[region];
screamer 0:a076a1bbe630 392
screamer 0:a076a1bbe630 393 tr_debug("Erase - addr: %llu, in_size: %llu", addr, in_size);
screamer 0:a076a1bbe630 394
screamer 0:a076a1bbe630 395 if ((addr + in_size) > _device_size_bytes) {
screamer 0:a076a1bbe630 396 tr_error("Erase exceeds flash device size");
screamer 0:a076a1bbe630 397 return QSPIF_BD_ERROR_INVALID_ERASE_PARAMS;
screamer 0:a076a1bbe630 398 }
screamer 0:a076a1bbe630 399
screamer 0:a076a1bbe630 400 if (((addr % get_erase_size(addr)) != 0) || (((addr + in_size) % get_erase_size(addr + in_size - 1)) != 0)) {
screamer 0:a076a1bbe630 401 tr_error("Invalid erase - unaligned address and size");
screamer 0:a076a1bbe630 402 return QSPIF_BD_ERROR_INVALID_ERASE_PARAMS;
screamer 0:a076a1bbe630 403 }
screamer 0:a076a1bbe630 404
screamer 0:a076a1bbe630 405 // For each iteration erase the largest section supported by current region
screamer 0:a076a1bbe630 406 while (size > 0) {
screamer 0:a076a1bbe630 407 // iterate to find next Largest erase type ( a. supported by region, b. smaller than size)
screamer 0:a076a1bbe630 408 // find the matching instruction and erase size chunk for that type.
screamer 0:a076a1bbe630 409 type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, _region_high_boundary[region]);
screamer 0:a076a1bbe630 410 cur_erase_inst = _erase_type_inst_arr[type];
screamer 0:a076a1bbe630 411 offset = addr % _erase_type_size_arr[type];
screamer 0:a076a1bbe630 412 chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset);
screamer 0:a076a1bbe630 413
screamer 0:a076a1bbe630 414 tr_debug("Erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu ",
screamer 0:a076a1bbe630 415 addr, size, cur_erase_inst, chunk);
screamer 0:a076a1bbe630 416 tr_debug("Erase - Region: %d, Type:%d ",
screamer 0:a076a1bbe630 417 region, type);
screamer 0:a076a1bbe630 418
screamer 0:a076a1bbe630 419 _mutex.lock();
screamer 0:a076a1bbe630 420
screamer 0:a076a1bbe630 421 if (_set_write_enable() != 0) {
screamer 0:a076a1bbe630 422 tr_error("QSPI Erase Device not ready - failed");
screamer 0:a076a1bbe630 423 erase_failed = true;
screamer 0:a076a1bbe630 424 status = QSPIF_BD_ERROR_READY_FAILED;
screamer 0:a076a1bbe630 425 goto exit_point;
screamer 0:a076a1bbe630 426 }
screamer 0:a076a1bbe630 427
screamer 0:a076a1bbe630 428 if (QSPI_STATUS_OK != _qspi_send_erase_command(cur_erase_inst, addr, size)) {
screamer 0:a076a1bbe630 429 tr_error("QSPI Erase command failed!");
screamer 0:a076a1bbe630 430 erase_failed = true;
screamer 0:a076a1bbe630 431 status = QSPIF_BD_ERROR_DEVICE_ERROR;
screamer 0:a076a1bbe630 432 goto exit_point;
screamer 0:a076a1bbe630 433 }
screamer 0:a076a1bbe630 434
screamer 0:a076a1bbe630 435 addr += chunk;
screamer 0:a076a1bbe630 436 size -= chunk;
screamer 0:a076a1bbe630 437
screamer 0:a076a1bbe630 438 if ((size > 0) && (addr > _region_high_boundary[region])) {
screamer 0:a076a1bbe630 439 // erase crossed to next region
screamer 0:a076a1bbe630 440 region++;
screamer 0:a076a1bbe630 441 bitfield = _region_erase_types_bitfield[region];
screamer 0:a076a1bbe630 442 }
screamer 0:a076a1bbe630 443
screamer 0:a076a1bbe630 444 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 445 tr_error("QSPI After Erase Device not ready - failed");
screamer 0:a076a1bbe630 446 erase_failed = true;
screamer 0:a076a1bbe630 447 status = QSPIF_BD_ERROR_READY_FAILED;
screamer 0:a076a1bbe630 448 goto exit_point;
screamer 0:a076a1bbe630 449 }
screamer 0:a076a1bbe630 450
screamer 0:a076a1bbe630 451 _mutex.unlock();
screamer 0:a076a1bbe630 452 }
screamer 0:a076a1bbe630 453
screamer 0:a076a1bbe630 454 exit_point:
screamer 0:a076a1bbe630 455 if (erase_failed) {
screamer 0:a076a1bbe630 456 _mutex.unlock();
screamer 0:a076a1bbe630 457 }
screamer 0:a076a1bbe630 458
screamer 0:a076a1bbe630 459 return status;
screamer 0:a076a1bbe630 460 }
screamer 0:a076a1bbe630 461
screamer 0:a076a1bbe630 462 bd_size_t QSPIFBlockDevice::get_read_size() const
screamer 0:a076a1bbe630 463 {
screamer 0:a076a1bbe630 464 // Assuming all devices support 1byte read granularity
screamer 0:a076a1bbe630 465 return QSPIF_DEFAULT_READ_SIZE;
screamer 0:a076a1bbe630 466 }
screamer 0:a076a1bbe630 467
screamer 0:a076a1bbe630 468 bd_size_t QSPIFBlockDevice::get_program_size() const
screamer 0:a076a1bbe630 469 {
screamer 0:a076a1bbe630 470 // Assuming all devices support 1byte program granularity
screamer 0:a076a1bbe630 471 return QSPIF_DEFAULT_PROG_SIZE;
screamer 0:a076a1bbe630 472 }
screamer 0:a076a1bbe630 473
screamer 0:a076a1bbe630 474 bd_size_t QSPIFBlockDevice::get_erase_size() const
screamer 0:a076a1bbe630 475 {
screamer 0:a076a1bbe630 476 // return minimal erase size supported by all regions (0 if none exists)
screamer 0:a076a1bbe630 477 return _min_common_erase_size;
screamer 0:a076a1bbe630 478 }
screamer 0:a076a1bbe630 479
screamer 0:a076a1bbe630 480 // Find minimal erase size supported by the region to which the address belongs to
screamer 0:a076a1bbe630 481 bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr)
screamer 0:a076a1bbe630 482 {
screamer 0:a076a1bbe630 483 // Find region of current address
screamer 0:a076a1bbe630 484 int region = _utils_find_addr_region(addr);
screamer 0:a076a1bbe630 485
screamer 0:a076a1bbe630 486 int min_region_erase_size = _min_common_erase_size;
screamer 0:a076a1bbe630 487 int8_t type_mask = ERASE_BITMASK_TYPE1;
screamer 0:a076a1bbe630 488 int i_ind = 0;
screamer 0:a076a1bbe630 489
screamer 0:a076a1bbe630 490
screamer 0:a076a1bbe630 491 if (region != -1) {
screamer 0:a076a1bbe630 492 type_mask = 0x01;
screamer 0:a076a1bbe630 493
screamer 0:a076a1bbe630 494 for (i_ind = 0; i_ind < 4; i_ind++) {
screamer 0:a076a1bbe630 495 // loop through erase types bitfield supported by region
screamer 0:a076a1bbe630 496 if (_region_erase_types_bitfield[region] & type_mask) {
screamer 0:a076a1bbe630 497
screamer 0:a076a1bbe630 498 min_region_erase_size = _erase_type_size_arr[i_ind];
screamer 0:a076a1bbe630 499 break;
screamer 0:a076a1bbe630 500 }
screamer 0:a076a1bbe630 501 type_mask = type_mask << 1;
screamer 0:a076a1bbe630 502 }
screamer 0:a076a1bbe630 503
screamer 0:a076a1bbe630 504 if (i_ind == 4) {
screamer 0:a076a1bbe630 505 tr_error("No erase type was found for region addr");
screamer 0:a076a1bbe630 506 }
screamer 0:a076a1bbe630 507 }
screamer 0:a076a1bbe630 508
screamer 0:a076a1bbe630 509 return (bd_size_t)min_region_erase_size;
screamer 0:a076a1bbe630 510 }
screamer 0:a076a1bbe630 511
screamer 0:a076a1bbe630 512 bd_size_t QSPIFBlockDevice::size() const
screamer 0:a076a1bbe630 513 {
screamer 0:a076a1bbe630 514 return _device_size_bytes;
screamer 0:a076a1bbe630 515 }
screamer 0:a076a1bbe630 516
screamer 0:a076a1bbe630 517 int QSPIFBlockDevice::get_erase_value() const
screamer 0:a076a1bbe630 518 {
screamer 0:a076a1bbe630 519 return 0xFF;
screamer 0:a076a1bbe630 520 }
screamer 0:a076a1bbe630 521
screamer 0:a076a1bbe630 522 /********************************/
screamer 0:a076a1bbe630 523 /* Different Device Csel Mgmt */
screamer 0:a076a1bbe630 524 /********************************/
screamer 0:a076a1bbe630 525 static PinName *generate_initialized_active_qspif_csel_arr()
screamer 0:a076a1bbe630 526 {
screamer 0:a076a1bbe630 527 PinName *init_arr = new PinName[QSPIF_MAX_ACTIVE_FLASH_DEVICES];
screamer 0:a076a1bbe630 528 for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
screamer 0:a076a1bbe630 529 init_arr[i_ind] = NC;
screamer 0:a076a1bbe630 530 }
screamer 0:a076a1bbe630 531 return init_arr;
screamer 0:a076a1bbe630 532 }
screamer 0:a076a1bbe630 533
screamer 0:a076a1bbe630 534 int QSPIFBlockDevice::add_new_csel_instance(PinName csel)
screamer 0:a076a1bbe630 535 {
screamer 0:a076a1bbe630 536 int status = 0;
screamer 0:a076a1bbe630 537 _devices_mutex->lock();
screamer 0:a076a1bbe630 538 if (_number_of_active_qspif_flash_csel >= QSPIF_MAX_ACTIVE_FLASH_DEVICES) {
screamer 0:a076a1bbe630 539 status = -2;
screamer 0:a076a1bbe630 540 goto exit_point;
screamer 0:a076a1bbe630 541 }
screamer 0:a076a1bbe630 542
screamer 0:a076a1bbe630 543 // verify the device is unique(no identical csel already exists)
screamer 0:a076a1bbe630 544 for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
screamer 0:a076a1bbe630 545 if (_active_qspif_flash_csel_arr[i_ind] == csel) {
screamer 0:a076a1bbe630 546 status = -1;
screamer 0:a076a1bbe630 547 goto exit_point;
screamer 0:a076a1bbe630 548 }
screamer 0:a076a1bbe630 549 }
screamer 0:a076a1bbe630 550
screamer 0:a076a1bbe630 551 // Insert new csel into existing device list
screamer 0:a076a1bbe630 552 for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
screamer 0:a076a1bbe630 553 if (_active_qspif_flash_csel_arr[i_ind] == NC) {
screamer 0:a076a1bbe630 554 _active_qspif_flash_csel_arr[i_ind] = csel;
screamer 0:a076a1bbe630 555 break;
screamer 0:a076a1bbe630 556 }
screamer 0:a076a1bbe630 557 }
screamer 0:a076a1bbe630 558 _number_of_active_qspif_flash_csel++;
screamer 0:a076a1bbe630 559
screamer 0:a076a1bbe630 560 exit_point:
screamer 0:a076a1bbe630 561 _devices_mutex->unlock();
screamer 0:a076a1bbe630 562 return status;
screamer 0:a076a1bbe630 563 }
screamer 0:a076a1bbe630 564
screamer 0:a076a1bbe630 565 int QSPIFBlockDevice::remove_csel_instance(PinName csel)
screamer 0:a076a1bbe630 566 {
screamer 0:a076a1bbe630 567 int status = -1;
screamer 0:a076a1bbe630 568 _devices_mutex->lock();
screamer 0:a076a1bbe630 569 // remove the csel from existing device list
screamer 0:a076a1bbe630 570 for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
screamer 0:a076a1bbe630 571 if (_active_qspif_flash_csel_arr[i_ind] == csel) {
screamer 0:a076a1bbe630 572 _active_qspif_flash_csel_arr[i_ind] = NC;
screamer 0:a076a1bbe630 573 if (_number_of_active_qspif_flash_csel > 0) {
screamer 0:a076a1bbe630 574 _number_of_active_qspif_flash_csel--;
screamer 0:a076a1bbe630 575 }
screamer 0:a076a1bbe630 576 status = 0;
screamer 0:a076a1bbe630 577 break;
screamer 0:a076a1bbe630 578 }
screamer 0:a076a1bbe630 579 }
screamer 0:a076a1bbe630 580 _devices_mutex->unlock();
screamer 0:a076a1bbe630 581 return status;
screamer 0:a076a1bbe630 582 }
screamer 0:a076a1bbe630 583
screamer 0:a076a1bbe630 584 /*********************************************************/
screamer 0:a076a1bbe630 585 /********** SFDP Parsing and Detection Functions *********/
screamer 0:a076a1bbe630 586 /*********************************************************/
screamer 0:a076a1bbe630 587 int QSPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size)
screamer 0:a076a1bbe630 588 {
screamer 0:a076a1bbe630 589 uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
screamer 0:a076a1bbe630 590 uint32_t tmp_region_size = 0;
screamer 0:a076a1bbe630 591 int i_ind = 0;
screamer 0:a076a1bbe630 592 int prev_boundary = 0;
screamer 0:a076a1bbe630 593 // Default set to all type bits 1-4 are common
screamer 0:a076a1bbe630 594 int min_common_erase_type_bits = ERASE_BITMASK_ALL;
screamer 0:a076a1bbe630 595
screamer 0:a076a1bbe630 596
screamer 0:a076a1bbe630 597 qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sector_map_table, sector_map_table_addr /*address*/,
screamer 0:a076a1bbe630 598 sector_map_table_size);
screamer 0:a076a1bbe630 599 if (status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 600 tr_error("Init - Read SFDP First Table Failed");
screamer 0:a076a1bbe630 601 return -1;
screamer 0:a076a1bbe630 602 }
screamer 0:a076a1bbe630 603
screamer 0:a076a1bbe630 604 // Currently we support only Single Map Descriptor
screamer 0:a076a1bbe630 605 if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
screamer 0:a076a1bbe630 606 tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
screamer 0:a076a1bbe630 607 return -1;
screamer 0:a076a1bbe630 608 }
screamer 0:a076a1bbe630 609
screamer 0:a076a1bbe630 610 _regions_count = sector_map_table[2] + 1;
screamer 0:a076a1bbe630 611 if (_regions_count > QSPIF_MAX_REGIONS) {
screamer 0:a076a1bbe630 612 tr_error("Supporting up to %d regions, current setup to %d regions - fail",
screamer 0:a076a1bbe630 613 QSPIF_MAX_REGIONS, _regions_count);
screamer 0:a076a1bbe630 614 return -1;
screamer 0:a076a1bbe630 615 }
screamer 0:a076a1bbe630 616
screamer 0:a076a1bbe630 617 // Loop through Regions and set for each one: size, supported erase types, high boundary offset
screamer 0:a076a1bbe630 618 // Calculate minimum Common Erase Type for all Regions
screamer 0:a076a1bbe630 619 for (i_ind = 0; i_ind < _regions_count; i_ind++) {
screamer 0:a076a1bbe630 620 tmp_region_size = ((*((uint32_t *)&sector_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
screamer 0:a076a1bbe630 621 _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
screamer 0:a076a1bbe630 622 _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
screamer 0:a076a1bbe630 623 min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind];
screamer 0:a076a1bbe630 624 _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary;
screamer 0:a076a1bbe630 625 prev_boundary = _region_high_boundary[i_ind] + 1;
screamer 0:a076a1bbe630 626 }
screamer 0:a076a1bbe630 627
screamer 0:a076a1bbe630 628 // Calc minimum Common Erase Size from min_common_erase_type_bits
screamer 0:a076a1bbe630 629 uint8_t type_mask = ERASE_BITMASK_TYPE1;
screamer 0:a076a1bbe630 630 for (i_ind = 0; i_ind < 4; i_ind++) {
screamer 0:a076a1bbe630 631 if (min_common_erase_type_bits & type_mask) {
screamer 0:a076a1bbe630 632 _min_common_erase_size = _erase_type_size_arr[i_ind];
screamer 0:a076a1bbe630 633 break;
screamer 0:a076a1bbe630 634 }
screamer 0:a076a1bbe630 635 type_mask = type_mask << 1;
screamer 0:a076a1bbe630 636 }
screamer 0:a076a1bbe630 637
screamer 0:a076a1bbe630 638 if (i_ind == 4) {
screamer 0:a076a1bbe630 639 // No common erase type was found between regions
screamer 0:a076a1bbe630 640 _min_common_erase_size = 0;
screamer 0:a076a1bbe630 641 }
screamer 0:a076a1bbe630 642
screamer 0:a076a1bbe630 643 return 0;
screamer 0:a076a1bbe630 644 }
screamer 0:a076a1bbe630 645
screamer 0:a076a1bbe630 646 int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size)
screamer 0:a076a1bbe630 647 {
screamer 0:a076a1bbe630 648 uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
screamer 0:a076a1bbe630 649
screamer 0:a076a1bbe630 650 qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_table, basic_table_addr /*address*/,
screamer 0:a076a1bbe630 651 basic_table_size);
screamer 0:a076a1bbe630 652 if (status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 653 tr_error("Init - Read SFDP First Table Failed");
screamer 0:a076a1bbe630 654 return -1;
screamer 0:a076a1bbe630 655 }
screamer 0:a076a1bbe630 656
screamer 0:a076a1bbe630 657 // Check address size, currently only supports 3byte addresses
screamer 0:a076a1bbe630 658 if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) {
screamer 0:a076a1bbe630 659 tr_error("Init - verify 3byte addressing Failed");
screamer 0:a076a1bbe630 660 return -1;
screamer 0:a076a1bbe630 661 }
screamer 0:a076a1bbe630 662
screamer 0:a076a1bbe630 663 // Get device density (stored in bits - 1)
screamer 0:a076a1bbe630 664 uint32_t density_bits = (
screamer 0:a076a1bbe630 665 (param_table[7] << 24) |
screamer 0:a076a1bbe630 666 (param_table[6] << 16) |
screamer 0:a076a1bbe630 667 (param_table[5] << 8) |
screamer 0:a076a1bbe630 668 param_table[4]);
screamer 0:a076a1bbe630 669 _device_size_bytes = (density_bits + 1) / 8;
screamer 0:a076a1bbe630 670
screamer 0:a076a1bbe630 671 // Set Default read/program/erase Instructions
screamer 0:a076a1bbe630 672 _read_instruction = QSPIF_READ;
screamer 0:a076a1bbe630 673 _prog_instruction = QSPIF_PP;
screamer 0:a076a1bbe630 674 _erase_instruction = QSPIF_SE;
screamer 0:a076a1bbe630 675
screamer 0:a076a1bbe630 676 _erase_instruction = _erase4k_inst;
screamer 0:a076a1bbe630 677
screamer 0:a076a1bbe630 678 // Set Page Size (QSPI write must be done on Page limits)
screamer 0:a076a1bbe630 679 _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size);
screamer 0:a076a1bbe630 680
screamer 0:a076a1bbe630 681 // Detect and Set Erase Types
screamer 0:a076a1bbe630 682 bool shouldSetQuadEnable = false;
screamer 0:a076a1bbe630 683 bool is_qpi_mode = false;
screamer 0:a076a1bbe630 684
screamer 0:a076a1bbe630 685 _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr,
screamer 0:a076a1bbe630 686 _erase_type_size_arr);
screamer 0:a076a1bbe630 687 _erase_instruction = _erase4k_inst;
screamer 0:a076a1bbe630 688
screamer 0:a076a1bbe630 689 // Detect and Set fastest Bus mode (default 1-1-1)
screamer 0:a076a1bbe630 690 _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, shouldSetQuadEnable, is_qpi_mode, _read_instruction);
screamer 0:a076a1bbe630 691 if (true == shouldSetQuadEnable) {
screamer 0:a076a1bbe630 692 _enable_fast_mdoe();
screamer 0:a076a1bbe630 693 // Set Quad Enable and QPI Bus modes if Supported
screamer 0:a076a1bbe630 694 tr_info("Init - Setting Quad Enable");
screamer 0:a076a1bbe630 695 if (0 != _sfdp_set_quad_enabled(param_table)) {
screamer 0:a076a1bbe630 696 tr_error("Device supports Quad bus, but Quad Enable Failed");
screamer 0:a076a1bbe630 697 return -1;
screamer 0:a076a1bbe630 698 }
screamer 0:a076a1bbe630 699 if (true == is_qpi_mode) {
screamer 0:a076a1bbe630 700 tr_info("Init - Setting QPI mode");
screamer 0:a076a1bbe630 701 _sfdp_set_qpi_enabled(param_table);
screamer 0:a076a1bbe630 702 }
screamer 0:a076a1bbe630 703 }
screamer 0:a076a1bbe630 704 return 0;
screamer 0:a076a1bbe630 705 }
screamer 0:a076a1bbe630 706
screamer 0:a076a1bbe630 707 int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
screamer 0:a076a1bbe630 708 uint32_t &sector_map_table_addr, size_t &sector_map_table_size)
screamer 0:a076a1bbe630 709 {
screamer 0:a076a1bbe630 710 uint8_t sfdp_header[QSPIF_SFDP_HEADER_SIZE];
screamer 0:a076a1bbe630 711 uint8_t param_header[QSPIF_PARAM_HEADER_SIZE];
screamer 0:a076a1bbe630 712 size_t data_length = QSPIF_SFDP_HEADER_SIZE;
screamer 0:a076a1bbe630 713 bd_addr_t addr = 0x0;
screamer 0:a076a1bbe630 714
screamer 0:a076a1bbe630 715 // Set 1-1-1 bus mode for SFDP header parsing
screamer 0:a076a1bbe630 716 _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 717 QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8);
screamer 0:a076a1bbe630 718
screamer 0:a076a1bbe630 719 qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length);
screamer 0:a076a1bbe630 720 if (status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 721 tr_error("Init - Read SFDP Failed");
screamer 0:a076a1bbe630 722 return -1;
screamer 0:a076a1bbe630 723 }
screamer 0:a076a1bbe630 724
screamer 0:a076a1bbe630 725 // Verify SFDP signature for sanity
screamer 0:a076a1bbe630 726 // Also check that major/minor version is acceptable
screamer 0:a076a1bbe630 727 if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) {
screamer 0:a076a1bbe630 728 tr_error("Init - _verify SFDP signature and version Failed");
screamer 0:a076a1bbe630 729 return -1;
screamer 0:a076a1bbe630 730 } else {
screamer 0:a076a1bbe630 731 tr_info("Init - verified SFDP Signature and version Successfully");
screamer 0:a076a1bbe630 732 }
screamer 0:a076a1bbe630 733
screamer 0:a076a1bbe630 734 // Discover Number of Parameter Headers
screamer 0:a076a1bbe630 735 int number_of_param_headers = (int)(sfdp_header[6]) + 1;
screamer 0:a076a1bbe630 736 tr_debug("Number of Param Headers: %d", number_of_param_headers);
screamer 0:a076a1bbe630 737
screamer 0:a076a1bbe630 738
screamer 0:a076a1bbe630 739 addr += QSPIF_SFDP_HEADER_SIZE;
screamer 0:a076a1bbe630 740 data_length = QSPIF_PARAM_HEADER_SIZE;
screamer 0:a076a1bbe630 741
screamer 0:a076a1bbe630 742 // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table)
screamer 0:a076a1bbe630 743 for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) {
screamer 0:a076a1bbe630 744
screamer 0:a076a1bbe630 745 status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_header, addr, data_length);
screamer 0:a076a1bbe630 746 if (status != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 747 tr_error("Init - Read Param Table %d Failed", i_ind + 1);
screamer 0:a076a1bbe630 748 return -1;
screamer 0:a076a1bbe630 749 }
screamer 0:a076a1bbe630 750
screamer 0:a076a1bbe630 751 // The SFDP spec indicates the standard table is always at offset 0
screamer 0:a076a1bbe630 752 // in the parameter headers, we check just to be safe
screamer 0:a076a1bbe630 753 if (param_header[2] != 1) {
screamer 0:a076a1bbe630 754 tr_error("Param Table %d - Major Version should be 1!", i_ind + 1);
screamer 0:a076a1bbe630 755 return -1;
screamer 0:a076a1bbe630 756 }
screamer 0:a076a1bbe630 757
screamer 0:a076a1bbe630 758 if ((param_header[0] == 0) && (param_header[7] == 0xFF)) {
screamer 0:a076a1bbe630 759 // Found Basic Params Table: LSB=0x00, MSB=0xFF
screamer 0:a076a1bbe630 760 tr_debug("Found Basic Param Table at Table: %d", i_ind + 1);
screamer 0:a076a1bbe630 761 basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
screamer 0:a076a1bbe630 762 // Supporting up to 64 Bytes Table (16 DWORDS)
screamer 0:a076a1bbe630 763 basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64;
screamer 0:a076a1bbe630 764
screamer 0:a076a1bbe630 765 } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) {
screamer 0:a076a1bbe630 766 // Found Sector Map Table: LSB=0x81, MSB=0xFF
screamer 0:a076a1bbe630 767 tr_debug("Found Sector Map Table at Table: %d", i_ind + 1);
screamer 0:a076a1bbe630 768 sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
screamer 0:a076a1bbe630 769 sector_map_table_size = param_header[3] * 4;
screamer 0:a076a1bbe630 770
screamer 0:a076a1bbe630 771 }
screamer 0:a076a1bbe630 772 addr += QSPIF_PARAM_HEADER_SIZE;
screamer 0:a076a1bbe630 773
screamer 0:a076a1bbe630 774 }
screamer 0:a076a1bbe630 775 return 0;
screamer 0:a076a1bbe630 776 }
screamer 0:a076a1bbe630 777
screamer 0:a076a1bbe630 778 int QSPIFBlockDevice::_sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr)
screamer 0:a076a1bbe630 779 {
screamer 0:a076a1bbe630 780 uint8_t config_reg[1];
screamer 0:a076a1bbe630 781
screamer 0:a076a1bbe630 782 // QPI 4-4-4 Enable Procedure is specified in 5 Bits
screamer 0:a076a1bbe630 783 uint8_t en_seq_444_value = (((basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE] & 0xF0) >> 4) | ((
screamer 0:a076a1bbe630 784 basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE + 1] & 0x01) << 4));
screamer 0:a076a1bbe630 785
screamer 0:a076a1bbe630 786 switch (en_seq_444_value) {
screamer 0:a076a1bbe630 787 case 1:
screamer 0:a076a1bbe630 788 case 2:
screamer 0:a076a1bbe630 789 tr_debug("_sfdp_set_qpi_enabled - send command 38h");
screamer 0:a076a1bbe630 790 if (QSPI_STATUS_OK != _qspi_send_general_command(0x38, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
screamer 0:a076a1bbe630 791 tr_error("_sfdp_set_qpi_enabled - send command 38h Failed");
screamer 0:a076a1bbe630 792 }
screamer 0:a076a1bbe630 793 break;
screamer 0:a076a1bbe630 794
screamer 0:a076a1bbe630 795 case 4:
screamer 0:a076a1bbe630 796 tr_debug("_sfdp_set_qpi_enabled - send command 35h");
screamer 0:a076a1bbe630 797 if (QSPI_STATUS_OK != _qspi_send_general_command(0x35, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
screamer 0:a076a1bbe630 798 tr_error("_sfdp_set_qpi_enabled - send command 35h Failed");
screamer 0:a076a1bbe630 799 }
screamer 0:a076a1bbe630 800 break;
screamer 0:a076a1bbe630 801
screamer 0:a076a1bbe630 802 case 8:
screamer 0:a076a1bbe630 803 tr_debug("_sfdp_set_qpi_enabled - set config bit 6 and send command 71h");
screamer 0:a076a1bbe630 804 if (QSPI_STATUS_OK != _qspi_send_general_command(0x65, 0x800003, NULL, 0, (char *)config_reg, 1)) {
screamer 0:a076a1bbe630 805 tr_error("_sfdp_set_qpi_enabled - set config bit 6 command 65h Failed");
screamer 0:a076a1bbe630 806 }
screamer 0:a076a1bbe630 807 config_reg[0] |= 0x40; //Set Bit 6
screamer 0:a076a1bbe630 808 if (QSPI_STATUS_OK != _qspi_send_general_command(0x71, 0x800003, NULL, 0, (char *)config_reg, 1)) {
screamer 0:a076a1bbe630 809 tr_error("_sfdp_set_qpi_enabled - send command 71h Failed");
screamer 0:a076a1bbe630 810 }
screamer 0:a076a1bbe630 811 break;
screamer 0:a076a1bbe630 812
screamer 0:a076a1bbe630 813 case 16:
screamer 0:a076a1bbe630 814 tr_debug("_sfdp_set_qpi_enabled - reset config bits 0-7 and send command 61h");
screamer 0:a076a1bbe630 815 if (QSPI_STATUS_OK != _qspi_send_general_command(0x65, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)config_reg, 1)) {
screamer 0:a076a1bbe630 816 tr_error("_sfdp_set_qpi_enabled - send command 65h Failed");
screamer 0:a076a1bbe630 817 }
screamer 0:a076a1bbe630 818 config_reg[0] &= 0x7F; //Reset Bit 7 of CR
screamer 0:a076a1bbe630 819 if (QSPI_STATUS_OK != _qspi_send_general_command(0x61, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)config_reg, 1)) {
screamer 0:a076a1bbe630 820 tr_error("_sfdp_set_qpi_enabled - send command 61 Failed");
screamer 0:a076a1bbe630 821 }
screamer 0:a076a1bbe630 822 break;
screamer 0:a076a1bbe630 823
screamer 0:a076a1bbe630 824 default:
screamer 0:a076a1bbe630 825 tr_warning("_sfdp_set_qpi_enabled - Unsuported En Seq 444 configuration");
screamer 0:a076a1bbe630 826 break;
screamer 0:a076a1bbe630 827 }
screamer 0:a076a1bbe630 828 return 0;
screamer 0:a076a1bbe630 829 }
screamer 0:a076a1bbe630 830
screamer 0:a076a1bbe630 831
screamer 0:a076a1bbe630 832
screamer 0:a076a1bbe630 833 int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr)
screamer 0:a076a1bbe630 834 {
screamer 0:a076a1bbe630 835 int sr_read_size = QSPI_MAX_STATUS_REGISTER_SIZE;
screamer 0:a076a1bbe630 836 int sr_write_size = QSPI_MAX_STATUS_REGISTER_SIZE;
screamer 0:a076a1bbe630 837
screamer 0:a076a1bbe630 838 char status_reg_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
screamer 0:a076a1bbe630 839 char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
screamer 0:a076a1bbe630 840
screamer 0:a076a1bbe630 841 // QUAD Enable procedure is specified by 3 bits
screamer 0:a076a1bbe630 842 uint8_t qer_value = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QER_BYTE] & 0x70) >> 4;
screamer 0:a076a1bbe630 843
screamer 0:a076a1bbe630 844
screamer 0:a076a1bbe630 845 switch (qer_value) {
screamer 0:a076a1bbe630 846 case 0:
screamer 0:a076a1bbe630 847 tr_debug("Device Does not Have a QE Bit, continue based on Read Inst");
screamer 0:a076a1bbe630 848 return 0;
screamer 0:a076a1bbe630 849
screamer 0:a076a1bbe630 850 case 1:
screamer 0:a076a1bbe630 851 case 4:
screamer 0:a076a1bbe630 852 status_reg_setup[1] = 0x02; //Bit 1 of Status Reg 2
screamer 0:a076a1bbe630 853 tr_debug("Setting QE Bit, Bit 1 of Status Reg 2");
screamer 0:a076a1bbe630 854 break;
screamer 0:a076a1bbe630 855
screamer 0:a076a1bbe630 856 case 2:
screamer 0:a076a1bbe630 857 status_reg_setup[0] = 0x40; // Bit 6 of Status Reg 1
screamer 0:a076a1bbe630 858 sr_write_size = 1;
screamer 0:a076a1bbe630 859 tr_debug("Setting QE Bit, Bit 6 of Status Reg 1");
screamer 0:a076a1bbe630 860 break;
screamer 0:a076a1bbe630 861
screamer 0:a076a1bbe630 862 case 3:
screamer 0:a076a1bbe630 863 status_reg_setup[0] = 0x80; // Bit 7 of Status Reg 1
screamer 0:a076a1bbe630 864 sr_write_size = 1;
screamer 0:a076a1bbe630 865 _write_register_inst = 0x3E;
screamer 0:a076a1bbe630 866 _read_register_inst = 0x3F;
screamer 0:a076a1bbe630 867 tr_debug("Setting QE Bit, Bit 7 of Status Reg 1");
screamer 0:a076a1bbe630 868 break;
screamer 0:a076a1bbe630 869 case 5:
screamer 0:a076a1bbe630 870 status_reg_setup[1] = 0x2; // Bit 1 of status Reg 2
screamer 0:a076a1bbe630 871 _read_register_inst = 0x35;
screamer 0:a076a1bbe630 872 sr_read_size = 1;
screamer 0:a076a1bbe630 873 tr_debug("Setting QE Bit, Bit 1 of Status Reg 2 -special read command");
screamer 0:a076a1bbe630 874 break;
screamer 0:a076a1bbe630 875 default:
screamer 0:a076a1bbe630 876 tr_warning("_setQuadEnable - Unsuported QER configuration");
screamer 0:a076a1bbe630 877 break;
screamer 0:a076a1bbe630 878 }
screamer 0:a076a1bbe630 879
screamer 0:a076a1bbe630 880 // Configure BUS Mode to 1_1_1 for all commands other than Read
screamer 0:a076a1bbe630 881 _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 882 QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
screamer 0:a076a1bbe630 883
screamer 0:a076a1bbe630 884 // Read Status Register
screamer 0:a076a1bbe630 885 if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
screamer 0:a076a1bbe630 886 status_reg,
screamer 0:a076a1bbe630 887 sr_read_size)) { // store received values in status_value
screamer 0:a076a1bbe630 888 tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]);
screamer 0:a076a1bbe630 889 } else {
screamer 0:a076a1bbe630 890 tr_error("Reading Status Register failed");
screamer 0:a076a1bbe630 891 return -1;
screamer 0:a076a1bbe630 892 }
screamer 0:a076a1bbe630 893
screamer 0:a076a1bbe630 894 // Set Bits for Quad Enable
screamer 0:a076a1bbe630 895 for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) {
screamer 0:a076a1bbe630 896 status_reg[i] |= status_reg_setup[i];
screamer 0:a076a1bbe630 897 }
screamer 0:a076a1bbe630 898
screamer 0:a076a1bbe630 899 // Write new Status Register Setup
screamer 0:a076a1bbe630 900 if (_set_write_enable() != 0) {
screamer 0:a076a1bbe630 901 tr_error("Write Enabe failed");
screamer 0:a076a1bbe630 902 return -1;
screamer 0:a076a1bbe630 903 }
screamer 0:a076a1bbe630 904
screamer 0:a076a1bbe630 905 if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, (char *)status_reg,
screamer 0:a076a1bbe630 906 sr_write_size, NULL,
screamer 0:a076a1bbe630 907 0)) { // Write QE to status_register
screamer 0:a076a1bbe630 908 tr_debug("_setQuadEnable - Writing Status Register Success: value = 0x%x",
screamer 0:a076a1bbe630 909 (int)status_reg[0]);
screamer 0:a076a1bbe630 910 } else {
screamer 0:a076a1bbe630 911 tr_error("_setQuadEnable - Writing Status Register failed");
screamer 0:a076a1bbe630 912 return -1;
screamer 0:a076a1bbe630 913 }
screamer 0:a076a1bbe630 914
screamer 0:a076a1bbe630 915 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 916 tr_error("Device not ready after write, failed");
screamer 0:a076a1bbe630 917 return -1;
screamer 0:a076a1bbe630 918 }
screamer 0:a076a1bbe630 919
screamer 0:a076a1bbe630 920
screamer 0:a076a1bbe630 921 // For Debug
screamer 0:a076a1bbe630 922 memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
screamer 0:a076a1bbe630 923 if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
screamer 0:a076a1bbe630 924 (char *)status_reg,
screamer 0:a076a1bbe630 925 sr_read_size)) { // store received values in status_value
screamer 0:a076a1bbe630 926 tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]);
screamer 0:a076a1bbe630 927 } else {
screamer 0:a076a1bbe630 928 tr_error("Reading Status Register failed");
screamer 0:a076a1bbe630 929 return -1;
screamer 0:a076a1bbe630 930 }
screamer 0:a076a1bbe630 931
screamer 0:a076a1bbe630 932 return 0;
screamer 0:a076a1bbe630 933 }
screamer 0:a076a1bbe630 934
screamer 0:a076a1bbe630 935 int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
screamer 0:a076a1bbe630 936 {
screamer 0:a076a1bbe630 937 unsigned int page_size = QSPIF_DEFAULT_PAGE_SIZE;
screamer 0:a076a1bbe630 938
screamer 0:a076a1bbe630 939 if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE) {
screamer 0:a076a1bbe630 940 // Page Size is specified by 4 Bits (N), calculated by 2^N
screamer 0:a076a1bbe630 941 int page_to_power_size = ((int)basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4;
screamer 0:a076a1bbe630 942 page_size = local_math_power(2, page_to_power_size);
screamer 0:a076a1bbe630 943 tr_debug("Detected Page Size: %d", page_size);
screamer 0:a076a1bbe630 944 } else {
screamer 0:a076a1bbe630 945 tr_debug("Using Default Page Size: %d", page_size);
screamer 0:a076a1bbe630 946 }
screamer 0:a076a1bbe630 947 return page_size;
screamer 0:a076a1bbe630 948 }
screamer 0:a076a1bbe630 949
screamer 0:a076a1bbe630 950 int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
screamer 0:a076a1bbe630 951 unsigned int &erase4k_inst,
screamer 0:a076a1bbe630 952 unsigned int *erase_type_inst_arr, unsigned int *erase_type_size_arr)
screamer 0:a076a1bbe630 953 {
screamer 0:a076a1bbe630 954 erase4k_inst = 0xff;
screamer 0:a076a1bbe630 955 bool found_4Kerase_type = false;
screamer 0:a076a1bbe630 956 uint8_t bitfield = 0x01;
screamer 0:a076a1bbe630 957
screamer 0:a076a1bbe630 958 // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K
screamer 0:a076a1bbe630 959 erase4k_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE];
screamer 0:a076a1bbe630 960
screamer 0:a076a1bbe630 961 if (basic_param_table_size > QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) {
screamer 0:a076a1bbe630 962 // Loop Erase Types 1-4
screamer 0:a076a1bbe630 963 for (int i_ind = 0; i_ind < 4; i_ind++) {
screamer 0:a076a1bbe630 964 erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
screamer 0:a076a1bbe630 965 erase_type_size_arr[i_ind] = local_math_power(2,
screamer 0:a076a1bbe630 966 basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
screamer 0:a076a1bbe630 967 tr_info("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
screamer 0:a076a1bbe630 968 erase_type_size_arr[i_ind]);
screamer 0:a076a1bbe630 969 if (erase_type_size_arr[i_ind] > 1) {
screamer 0:a076a1bbe630 970 // if size==1 type is not supported
screamer 0:a076a1bbe630 971 erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
screamer 0:a076a1bbe630 972
screamer 0:a076a1bbe630 973 if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) {
screamer 0:a076a1bbe630 974 //Set default minimal common erase for singal region
screamer 0:a076a1bbe630 975 _min_common_erase_size = erase_type_size_arr[i_ind];
screamer 0:a076a1bbe630 976 }
screamer 0:a076a1bbe630 977
screamer 0:a076a1bbe630 978 // SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction
screamer 0:a076a1bbe630 979 if (erase_type_size_arr[i_ind] == 4096) {
screamer 0:a076a1bbe630 980 found_4Kerase_type = true;
screamer 0:a076a1bbe630 981 if (erase4k_inst != erase_type_inst_arr[i_ind]) {
screamer 0:a076a1bbe630 982 //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table
screamer 0:a076a1bbe630 983 erase4k_inst = erase_type_inst_arr[i_ind];
screamer 0:a076a1bbe630 984 tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
screamer 0:a076a1bbe630 985
screamer 0:a076a1bbe630 986 }
screamer 0:a076a1bbe630 987 }
screamer 0:a076a1bbe630 988 _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt;
screamer 0:a076a1bbe630 989 }
screamer 0:a076a1bbe630 990
screamer 0:a076a1bbe630 991 tr_info("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
screamer 0:a076a1bbe630 992 erase_type_size_arr[i_ind]);
screamer 0:a076a1bbe630 993 bitfield = bitfield << 1;
screamer 0:a076a1bbe630 994 }
screamer 0:a076a1bbe630 995 }
screamer 0:a076a1bbe630 996
screamer 0:a076a1bbe630 997 if (false == found_4Kerase_type) {
screamer 0:a076a1bbe630 998 tr_warning("Couldn't find Erase Type for 4KB size");
screamer 0:a076a1bbe630 999 }
screamer 0:a076a1bbe630 1000 return 0;
screamer 0:a076a1bbe630 1001 }
screamer 0:a076a1bbe630 1002
screamer 0:a076a1bbe630 1003 int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
screamer 0:a076a1bbe630 1004 bool &set_quad_enable,
screamer 0:a076a1bbe630 1005 bool &is_qpi_mode, unsigned int &read_inst)
screamer 0:a076a1bbe630 1006 {
screamer 0:a076a1bbe630 1007 set_quad_enable = false;
screamer 0:a076a1bbe630 1008 is_qpi_mode = false;
screamer 0:a076a1bbe630 1009 uint8_t examined_byte;
screamer 0:a076a1bbe630 1010
screamer 0:a076a1bbe630 1011 do { // compound statement is the loop body
screamer 0:a076a1bbe630 1012
screamer 0:a076a1bbe630 1013 if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE) {
screamer 0:a076a1bbe630 1014 examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
screamer 0:a076a1bbe630 1015
screamer 0:a076a1bbe630 1016 if (examined_byte & 0x10) {
screamer 0:a076a1bbe630 1017 // QPI 4-4-4 Supported
screamer 0:a076a1bbe630 1018 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE];
screamer 0:a076a1bbe630 1019 set_quad_enable = true;
screamer 0:a076a1bbe630 1020 is_qpi_mode = true;
screamer 0:a076a1bbe630 1021 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1022 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1023 tr_debug("Read Bus Mode set to 4-4-4, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1024 //_inst_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1025 _address_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1026 _data_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1027
screamer 0:a076a1bbe630 1028 break;
screamer 0:a076a1bbe630 1029 }
screamer 0:a076a1bbe630 1030 }
screamer 0:a076a1bbe630 1031
screamer 0:a076a1bbe630 1032
screamer 0:a076a1bbe630 1033 examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
screamer 0:a076a1bbe630 1034 if (examined_byte & 0x40) {
screamer 0:a076a1bbe630 1035 // Fast Read 1-4-4 Supported
screamer 0:a076a1bbe630 1036 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE];
screamer 0:a076a1bbe630 1037 set_quad_enable = true;
screamer 0:a076a1bbe630 1038 // dummy cycles + mode cycles = Dummy Cycles
screamer 0:a076a1bbe630 1039 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1040 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1041 _address_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1042 _data_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1043 tr_debug("Read Bus Mode set to 1-4-4, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1044 break;
screamer 0:a076a1bbe630 1045 }
screamer 0:a076a1bbe630 1046
screamer 0:a076a1bbe630 1047 if (examined_byte & 0x80) {
screamer 0:a076a1bbe630 1048 // Fast Read 1-1-4 Supported
screamer 0:a076a1bbe630 1049 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE];
screamer 0:a076a1bbe630 1050 set_quad_enable = true;
screamer 0:a076a1bbe630 1051 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1052 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1053 _data_width = QSPI_CFG_BUS_QUAD;
screamer 0:a076a1bbe630 1054 tr_debug("Read Bus Mode set to 1-1-4, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1055 break;
screamer 0:a076a1bbe630 1056 }
screamer 0:a076a1bbe630 1057 examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
screamer 0:a076a1bbe630 1058 if (examined_byte & 0x01) {
screamer 0:a076a1bbe630 1059 // Fast Read 2-2-2 Supported
screamer 0:a076a1bbe630 1060 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE];
screamer 0:a076a1bbe630 1061 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1062 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1063 _address_width = QSPI_CFG_BUS_DUAL;
screamer 0:a076a1bbe630 1064 _data_width = QSPI_CFG_BUS_DUAL;
screamer 0:a076a1bbe630 1065 tr_info("Read Bus Mode set to 2-2-2, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1066 break;
screamer 0:a076a1bbe630 1067 }
screamer 0:a076a1bbe630 1068
screamer 0:a076a1bbe630 1069 examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
screamer 0:a076a1bbe630 1070 if (examined_byte & 0x20) {
screamer 0:a076a1bbe630 1071 // Fast Read 1-2-2 Supported
screamer 0:a076a1bbe630 1072 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE];
screamer 0:a076a1bbe630 1073 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1074 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1075 _address_width = QSPI_CFG_BUS_DUAL;
screamer 0:a076a1bbe630 1076 _data_width = QSPI_CFG_BUS_DUAL;
screamer 0:a076a1bbe630 1077 tr_debug("Read Bus Mode set to 1-2-2, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1078 break;
screamer 0:a076a1bbe630 1079 }
screamer 0:a076a1bbe630 1080 if (examined_byte & 0x01) {
screamer 0:a076a1bbe630 1081 // Fast Read 1-1-2 Supported
screamer 0:a076a1bbe630 1082 read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE];
screamer 0:a076a1bbe630 1083 _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5)
screamer 0:a076a1bbe630 1084 + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F);
screamer 0:a076a1bbe630 1085 _data_width = QSPI_CFG_BUS_DUAL;
screamer 0:a076a1bbe630 1086 tr_debug("Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1087 break;
screamer 0:a076a1bbe630 1088 }
screamer 0:a076a1bbe630 1089 tr_debug("Read Bus Mode set to 1-1-1, Instruction: 0x%xh", _read_instruction);
screamer 0:a076a1bbe630 1090 } while (false);
screamer 0:a076a1bbe630 1091
screamer 0:a076a1bbe630 1092 return 0;
screamer 0:a076a1bbe630 1093 }
screamer 0:a076a1bbe630 1094
screamer 0:a076a1bbe630 1095 int QSPIFBlockDevice::_reset_flash_mem()
screamer 0:a076a1bbe630 1096 {
screamer 0:a076a1bbe630 1097 // Perform Soft Reset of the Device prior to initialization
screamer 0:a076a1bbe630 1098 int status = 0;
screamer 0:a076a1bbe630 1099 char status_value[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
screamer 0:a076a1bbe630 1100 tr_info("_reset_flash_mem:");
screamer 0:a076a1bbe630 1101 //Read the Status Register from device
screamer 0:a076a1bbe630 1102 if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
screamer 0:a076a1bbe630 1103 QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value
screamer 0:a076a1bbe630 1104 tr_debug("Reading Status Register Success: value = 0x%x", (int)status_value[0]);
screamer 0:a076a1bbe630 1105 } else {
screamer 0:a076a1bbe630 1106 tr_error("Reading Status Register failed: value = 0x%x", (int)status_value[0]);
screamer 0:a076a1bbe630 1107 status = -1;
screamer 0:a076a1bbe630 1108 }
screamer 0:a076a1bbe630 1109
screamer 0:a076a1bbe630 1110 if (0 == status) {
screamer 0:a076a1bbe630 1111 //Send Reset Enable
screamer 0:a076a1bbe630 1112 if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RSTEN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL,
screamer 0:a076a1bbe630 1113 0)) { // store received values in status_value
screamer 0:a076a1bbe630 1114 tr_debug("Sending RSTEN Success");
screamer 0:a076a1bbe630 1115 } else {
screamer 0:a076a1bbe630 1116 tr_error("Sending RSTEN failed");
screamer 0:a076a1bbe630 1117 status = -1;
screamer 0:a076a1bbe630 1118 }
screamer 0:a076a1bbe630 1119
screamer 0:a076a1bbe630 1120
screamer 0:a076a1bbe630 1121 if (0 == status) {
screamer 0:a076a1bbe630 1122 //Send Reset
screamer 0:a076a1bbe630 1123 if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RST, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL,
screamer 0:a076a1bbe630 1124 0)) { // store received values in status_value
screamer 0:a076a1bbe630 1125 tr_debug("Sending RST Success");
screamer 0:a076a1bbe630 1126 } else {
screamer 0:a076a1bbe630 1127 tr_error("Sending RST failed");
screamer 0:a076a1bbe630 1128 status = -1;
screamer 0:a076a1bbe630 1129 }
screamer 0:a076a1bbe630 1130
screamer 0:a076a1bbe630 1131 _is_mem_ready();
screamer 0:a076a1bbe630 1132 }
screamer 0:a076a1bbe630 1133 }
screamer 0:a076a1bbe630 1134
screamer 0:a076a1bbe630 1135 return status;
screamer 0:a076a1bbe630 1136 }
screamer 0:a076a1bbe630 1137
screamer 0:a076a1bbe630 1138 bool QSPIFBlockDevice::_is_mem_ready()
screamer 0:a076a1bbe630 1139 {
screamer 0:a076a1bbe630 1140 // Check Status Register Busy Bit to Verify the Device isn't Busy
screamer 0:a076a1bbe630 1141 char status_value[QSPI_MAX_STATUS_REGISTER_SIZE];
screamer 0:a076a1bbe630 1142 int retries = 0;
screamer 0:a076a1bbe630 1143 bool mem_ready = true;
screamer 0:a076a1bbe630 1144
screamer 0:a076a1bbe630 1145 do {
screamer 0:a076a1bbe630 1146 wait_ms(1);
screamer 0:a076a1bbe630 1147 retries++;
screamer 0:a076a1bbe630 1148 //Read the Status Register from device
screamer 0:a076a1bbe630 1149 memset(status_value, 0xFF, QSPI_MAX_STATUS_REGISTER_SIZE);
screamer 0:a076a1bbe630 1150 if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
screamer 0:a076a1bbe630 1151 QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value
screamer 0:a076a1bbe630 1152 tr_error("Reading Status Register failed");
screamer 0:a076a1bbe630 1153 }
screamer 0:a076a1bbe630 1154 } while ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES);
screamer 0:a076a1bbe630 1155
screamer 0:a076a1bbe630 1156 if ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0) {
screamer 0:a076a1bbe630 1157 tr_error("_is_mem_ready FALSE: status value = 0x%x ", (int)status_value[0]);
screamer 0:a076a1bbe630 1158 mem_ready = false;
screamer 0:a076a1bbe630 1159 }
screamer 0:a076a1bbe630 1160 return mem_ready;
screamer 0:a076a1bbe630 1161 }
screamer 0:a076a1bbe630 1162
screamer 0:a076a1bbe630 1163 int QSPIFBlockDevice::_set_write_enable()
screamer 0:a076a1bbe630 1164 {
screamer 0:a076a1bbe630 1165 // Check Status Register Busy Bit to Verify the Device isn't Busy
screamer 0:a076a1bbe630 1166 char status_value[QSPI_MAX_STATUS_REGISTER_SIZE];
screamer 0:a076a1bbe630 1167 int status = -1;
screamer 0:a076a1bbe630 1168
screamer 0:a076a1bbe630 1169 do {
screamer 0:a076a1bbe630 1170 if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_WREN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
screamer 0:a076a1bbe630 1171 tr_error("Sending WREN command FAILED");
screamer 0:a076a1bbe630 1172 break;
screamer 0:a076a1bbe630 1173 }
screamer 0:a076a1bbe630 1174
screamer 0:a076a1bbe630 1175 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 1176 tr_error("Device not ready, write failed");
screamer 0:a076a1bbe630 1177 break;
screamer 0:a076a1bbe630 1178 }
screamer 0:a076a1bbe630 1179
screamer 0:a076a1bbe630 1180 memset(status_value, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
screamer 0:a076a1bbe630 1181 if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
screamer 0:a076a1bbe630 1182 QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value
screamer 0:a076a1bbe630 1183 tr_error("Reading Status Register failed");
screamer 0:a076a1bbe630 1184 break;
screamer 0:a076a1bbe630 1185 }
screamer 0:a076a1bbe630 1186
screamer 0:a076a1bbe630 1187 if ((status_value[0] & QSPIF_STATUS_BIT_WEL) == 0) {
screamer 0:a076a1bbe630 1188 tr_error("_set_write_enable failed");
screamer 0:a076a1bbe630 1189 break;
screamer 0:a076a1bbe630 1190 }
screamer 0:a076a1bbe630 1191 status = 0;
screamer 0:a076a1bbe630 1192 } while (false);
screamer 0:a076a1bbe630 1193 return status;
screamer 0:a076a1bbe630 1194 }
screamer 0:a076a1bbe630 1195
screamer 0:a076a1bbe630 1196 int QSPIFBlockDevice::_enable_fast_mdoe()
screamer 0:a076a1bbe630 1197 {
screamer 0:a076a1bbe630 1198 char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
screamer 0:a076a1bbe630 1199 unsigned int read_conf_register_inst = 0x15;
screamer 0:a076a1bbe630 1200 char status_reg_qer_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
screamer 0:a076a1bbe630 1201
screamer 0:a076a1bbe630 1202 status_reg_qer_setup[2] = 0x2; // Bit 1 of config Reg 2
screamer 0:a076a1bbe630 1203
screamer 0:a076a1bbe630 1204 // Configure BUS Mode to 1_1_1 for all commands other than Read
screamer 0:a076a1bbe630 1205 _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
screamer 0:a076a1bbe630 1206 QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
screamer 0:a076a1bbe630 1207
screamer 0:a076a1bbe630 1208 // Read Status Register
screamer 0:a076a1bbe630 1209 if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
screamer 0:a076a1bbe630 1210 &status_reg[1],
screamer 0:a076a1bbe630 1211 QSPI_MAX_STATUS_REGISTER_SIZE - 1)) { // store received values in status_value
screamer 0:a076a1bbe630 1212 tr_debug("Reading Config Register Success: value = 0x%x", (int)status_reg[2]);
screamer 0:a076a1bbe630 1213 } else {
screamer 0:a076a1bbe630 1214 tr_error("Reading Config Register failed");
screamer 0:a076a1bbe630 1215 return -1;
screamer 0:a076a1bbe630 1216 }
screamer 0:a076a1bbe630 1217
screamer 0:a076a1bbe630 1218 // Set Bits for Quad Enable
screamer 0:a076a1bbe630 1219 for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) {
screamer 0:a076a1bbe630 1220 status_reg[i] |= status_reg_qer_setup[i];
screamer 0:a076a1bbe630 1221 }
screamer 0:a076a1bbe630 1222
screamer 0:a076a1bbe630 1223 // Write new Status Register Setup
screamer 0:a076a1bbe630 1224 if (_set_write_enable() != 0) {
screamer 0:a076a1bbe630 1225 tr_error("Write Enabe failed");
screamer 0:a076a1bbe630 1226 return -1;
screamer 0:a076a1bbe630 1227 }
screamer 0:a076a1bbe630 1228
screamer 0:a076a1bbe630 1229 if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, status_reg,
screamer 0:a076a1bbe630 1230 QSPI_MAX_STATUS_REGISTER_SIZE, NULL,
screamer 0:a076a1bbe630 1231 0)) { // Write Fast mode bit to status_register
screamer 0:a076a1bbe630 1232 tr_debug("fast mode enable - Writing Config Register Success: value = 0x%x",
screamer 0:a076a1bbe630 1233 (int)status_reg[2]);
screamer 0:a076a1bbe630 1234 } else {
screamer 0:a076a1bbe630 1235 tr_error("fast mode enable - Writing Config Register failed");
screamer 0:a076a1bbe630 1236 return -1;
screamer 0:a076a1bbe630 1237 }
screamer 0:a076a1bbe630 1238
screamer 0:a076a1bbe630 1239 if (false == _is_mem_ready()) {
screamer 0:a076a1bbe630 1240 tr_error("Device not ready after write, failed");
screamer 0:a076a1bbe630 1241 return -1;
screamer 0:a076a1bbe630 1242 }
screamer 0:a076a1bbe630 1243
screamer 0:a076a1bbe630 1244 // For Debug
screamer 0:a076a1bbe630 1245 memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
screamer 0:a076a1bbe630 1246 if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
screamer 0:a076a1bbe630 1247 &status_reg[1],
screamer 0:a076a1bbe630 1248 QSPI_MAX_STATUS_REGISTER_SIZE - 1)) { // store received values in status_value
screamer 0:a076a1bbe630 1249 tr_debug("Verifying Config Register Success: value = 0x%x", (int)status_reg[2]);
screamer 0:a076a1bbe630 1250 } else {
screamer 0:a076a1bbe630 1251 tr_error("Verifying Config Register failed");
screamer 0:a076a1bbe630 1252 return -1;
screamer 0:a076a1bbe630 1253 }
screamer 0:a076a1bbe630 1254
screamer 0:a076a1bbe630 1255 return 0;
screamer 0:a076a1bbe630 1256 }
screamer 0:a076a1bbe630 1257
screamer 0:a076a1bbe630 1258 /*********************************************/
screamer 0:a076a1bbe630 1259 /************* Utility Functions *************/
screamer 0:a076a1bbe630 1260 /*********************************************/
screamer 0:a076a1bbe630 1261 int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset)
screamer 0:a076a1bbe630 1262 {
screamer 0:a076a1bbe630 1263 //Find the region to which the given offset belong to
screamer 0:a076a1bbe630 1264 if ((offset > _device_size_bytes) || (_regions_count == 0)) {
screamer 0:a076a1bbe630 1265 return -1;
screamer 0:a076a1bbe630 1266 }
screamer 0:a076a1bbe630 1267
screamer 0:a076a1bbe630 1268 if (_regions_count == 1) {
screamer 0:a076a1bbe630 1269 return 0;
screamer 0:a076a1bbe630 1270 }
screamer 0:a076a1bbe630 1271
screamer 0:a076a1bbe630 1272 for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) {
screamer 0:a076a1bbe630 1273
screamer 0:a076a1bbe630 1274 if (offset > _region_high_boundary[i_ind]) {
screamer 0:a076a1bbe630 1275 return (i_ind + 1);
screamer 0:a076a1bbe630 1276 }
screamer 0:a076a1bbe630 1277 }
screamer 0:a076a1bbe630 1278 return -1;
screamer 0:a076a1bbe630 1279
screamer 0:a076a1bbe630 1280 }
screamer 0:a076a1bbe630 1281
screamer 0:a076a1bbe630 1282 int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry)
screamer 0:a076a1bbe630 1283 {
screamer 0:a076a1bbe630 1284 // Iterate on all supported Erase Types of the Region to which the offset belong to.
screamer 0:a076a1bbe630 1285 // Iterates from highest type to lowest
screamer 0:a076a1bbe630 1286 uint8_t type_mask = ERASE_BITMASK_TYPE4;
screamer 0:a076a1bbe630 1287 int i_ind = 0;
screamer 0:a076a1bbe630 1288 int largest_erase_type = 0;
screamer 0:a076a1bbe630 1289 for (i_ind = 3; i_ind >= 0; i_ind--) {
screamer 0:a076a1bbe630 1290 if (bitfield & type_mask) {
screamer 0:a076a1bbe630 1291 largest_erase_type = i_ind;
screamer 0:a076a1bbe630 1292 if ((size > (int)(_erase_type_size_arr[largest_erase_type])) &&
screamer 0:a076a1bbe630 1293 ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) {
screamer 0:a076a1bbe630 1294 break;
screamer 0:a076a1bbe630 1295 } else {
screamer 0:a076a1bbe630 1296 bitfield &= ~type_mask;
screamer 0:a076a1bbe630 1297 }
screamer 0:a076a1bbe630 1298 }
screamer 0:a076a1bbe630 1299 type_mask = type_mask >> 1;
screamer 0:a076a1bbe630 1300 }
screamer 0:a076a1bbe630 1301
screamer 0:a076a1bbe630 1302 if (i_ind == 4) {
screamer 0:a076a1bbe630 1303 tr_error("No erase type was found for current region addr");
screamer 0:a076a1bbe630 1304 }
screamer 0:a076a1bbe630 1305 return largest_erase_type;
screamer 0:a076a1bbe630 1306
screamer 0:a076a1bbe630 1307 }
screamer 0:a076a1bbe630 1308
screamer 0:a076a1bbe630 1309 /***************************************************/
screamer 0:a076a1bbe630 1310 /*********** QSPI Driver API Functions *************/
screamer 0:a076a1bbe630 1311 /***************************************************/
screamer 0:a076a1bbe630 1312 qspi_status_t QSPIFBlockDevice::_qspi_set_frequency(int freq)
screamer 0:a076a1bbe630 1313 {
screamer 0:a076a1bbe630 1314 return _qspi.set_frequency(freq);
screamer 0:a076a1bbe630 1315 }
screamer 0:a076a1bbe630 1316
screamer 0:a076a1bbe630 1317 qspi_status_t QSPIFBlockDevice::_qspi_send_read_command(unsigned int read_inst, void *buffer, bd_addr_t addr,
screamer 0:a076a1bbe630 1318 bd_size_t size)
screamer 0:a076a1bbe630 1319 {
screamer 0:a076a1bbe630 1320 // Send Read command to device driver
screamer 0:a076a1bbe630 1321 size_t buf_len = size;
screamer 0:a076a1bbe630 1322
screamer 0:a076a1bbe630 1323 if (_qspi.read(read_inst, -1, (unsigned int)addr, (char *)buffer, &buf_len) != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 1324 tr_error("Read failed");
screamer 0:a076a1bbe630 1325 return QSPI_STATUS_ERROR;
screamer 0:a076a1bbe630 1326 }
screamer 0:a076a1bbe630 1327
screamer 0:a076a1bbe630 1328 return QSPI_STATUS_OK;
screamer 0:a076a1bbe630 1329
screamer 0:a076a1bbe630 1330 }
screamer 0:a076a1bbe630 1331
screamer 0:a076a1bbe630 1332 qspi_status_t QSPIFBlockDevice::_qspi_send_program_command(unsigned int progInst, const void *buffer, bd_addr_t addr,
screamer 0:a076a1bbe630 1333 bd_size_t *size)
screamer 0:a076a1bbe630 1334 {
screamer 0:a076a1bbe630 1335 // Send Program (write) command to device driver
screamer 0:a076a1bbe630 1336 qspi_status_t result = QSPI_STATUS_OK;
screamer 0:a076a1bbe630 1337
screamer 0:a076a1bbe630 1338 result = _qspi.write(progInst, -1, addr, (char *)buffer, (size_t *)size);
screamer 0:a076a1bbe630 1339 if (result != QSPI_STATUS_OK) {
screamer 0:a076a1bbe630 1340 tr_error("QSPI Write failed");
screamer 0:a076a1bbe630 1341 }
screamer 0:a076a1bbe630 1342
screamer 0:a076a1bbe630 1343 return result;
screamer 0:a076a1bbe630 1344 }
screamer 0:a076a1bbe630 1345
screamer 0:a076a1bbe630 1346 qspi_status_t QSPIFBlockDevice::_qspi_send_erase_command(unsigned int erase_inst, bd_addr_t addr, bd_size_t size)
screamer 0:a076a1bbe630 1347 {
screamer 0:a076a1bbe630 1348 // Send Erase Instruction command to driver
screamer 0:a076a1bbe630 1349 qspi_status_t result = QSPI_STATUS_OK;
screamer 0:a076a1bbe630 1350
screamer 0:a076a1bbe630 1351 tr_info("Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size);
screamer 0:a076a1bbe630 1352
screamer 0:a076a1bbe630 1353 result = _qspi.command_transfer(erase_inst, // command to send
screamer 0:a076a1bbe630 1354 (((int)addr) & 0x00FFF000), // Align addr to 4096
screamer 0:a076a1bbe630 1355 NULL, // do not transmit
screamer 0:a076a1bbe630 1356 0, // do not transmit
screamer 0:a076a1bbe630 1357 NULL, // just receive two bytes of data
screamer 0:a076a1bbe630 1358 0); // store received values in status_value
screamer 0:a076a1bbe630 1359
screamer 0:a076a1bbe630 1360 if (QSPI_STATUS_OK != result) {
screamer 0:a076a1bbe630 1361 tr_error("QSPI Erase failed");
screamer 0:a076a1bbe630 1362 }
screamer 0:a076a1bbe630 1363
screamer 0:a076a1bbe630 1364 return result;
screamer 0:a076a1bbe630 1365
screamer 0:a076a1bbe630 1366 }
screamer 0:a076a1bbe630 1367
screamer 0:a076a1bbe630 1368 qspi_status_t QSPIFBlockDevice::_qspi_send_general_command(unsigned int instruction, bd_addr_t addr,
screamer 0:a076a1bbe630 1369 const char *tx_buffer,
screamer 0:a076a1bbe630 1370 size_t tx_length, const char *rx_buffer, size_t rx_length)
screamer 0:a076a1bbe630 1371 {
screamer 0:a076a1bbe630 1372 // Send a general command Instruction to driver
screamer 0:a076a1bbe630 1373 qspi_status_t status = _qspi.command_transfer(instruction, (int)addr, tx_buffer, tx_length, rx_buffer, rx_length);
screamer 0:a076a1bbe630 1374
screamer 0:a076a1bbe630 1375 if (QSPI_STATUS_OK != status) {
screamer 0:a076a1bbe630 1376 tr_error("Sending Generic command: %x", instruction);
screamer 0:a076a1bbe630 1377 }
screamer 0:a076a1bbe630 1378
screamer 0:a076a1bbe630 1379 return status;
screamer 0:a076a1bbe630 1380 }
screamer 0:a076a1bbe630 1381
screamer 0:a076a1bbe630 1382 qspi_status_t QSPIFBlockDevice::_qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width,
screamer 0:a076a1bbe630 1383 qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width,
screamer 0:a076a1bbe630 1384 int dummy_cycles)
screamer 0:a076a1bbe630 1385 {
screamer 0:a076a1bbe630 1386 // Configure QSPI driver Bus format
screamer 0:a076a1bbe630 1387 qspi_status_t status = _qspi.configure_format(inst_width, address_width, address_size, alt_width, alt_size, data_width,
screamer 0:a076a1bbe630 1388 dummy_cycles);
screamer 0:a076a1bbe630 1389
screamer 0:a076a1bbe630 1390 return status;
screamer 0:a076a1bbe630 1391 }
screamer 0:a076a1bbe630 1392
screamer 0:a076a1bbe630 1393 /*********************************************/
screamer 0:a076a1bbe630 1394 /************** Local Functions **************/
screamer 0:a076a1bbe630 1395 /*********************************************/
screamer 0:a076a1bbe630 1396 static int local_math_power(int base, int exp)
screamer 0:a076a1bbe630 1397 {
screamer 0:a076a1bbe630 1398 // Integer X^Y function, used to calculate size fields given in 2^N format
screamer 0:a076a1bbe630 1399 int result = 1;
screamer 0:a076a1bbe630 1400 while (exp) {
screamer 0:a076a1bbe630 1401 result *= base;
screamer 0:a076a1bbe630 1402 exp--;
screamer 0:a076a1bbe630 1403 }
screamer 0:a076a1bbe630 1404 return result;
screamer 0:a076a1bbe630 1405 }