Mbed OS and Pelion Device Management example over WIFI for DISCO_L475VG_IOT01 board

Dependencies:   X_NUCLEO_COMMON ST_INTERFACES

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 on the following platforms:

DISCO_L475E_IOT01A

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

Example functionality

This example showcases the following device functionality:

  • Read onboard temperature and humidity sensors, and report them as Pelion LWM2M resources (see image below).
  • 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.
  • Uses all onboard sensors and reports them as Pelion LWM2M resources.

/media/uploads/screamer/pelion_st_humidity_reading.png?v=2

Use this example with Mbed CLI

1. Import the application into your desktop:

mbed import https://os.mbed.com/teams/ST/code/pelion-example-disco-iot01

cd pelion-example-disco-iot01

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 DISCO_L475VG_IOT01A

(supported toolchains : GCC_ARM / ARM / IAR)

5. You can connect on a virtual terminal/COM port to the platform using:

mbed sterm -b 115200

This should give you an output similar to:

[BOOT] Mbed Bootloader
[BOOT] ARM: 00000000000000000000
[BOOT] OEM: 00000000000000000000
[BOOT] Layout: 0 80096F4
[BOOT] Active firmware integrity check:
[BOOT] SHA256: 0660E360D432225D5251461998FD8617B017098C5F1F90D5FB607BF8C27ED530
[BOOT] Version: 1553615309
[BOOT] Slot 0 is empty
[BOOT] Active firmware up-to-date
[BOOT] Application's start address: 0x8010400
[BOOT] Application's jump address: 0x8011041
[BOOT] Application's stack address: 0x20018000
[BOOT] Forwarding to application...

Starting Simple Pelion Device Management Client example
You can hold the user button during boot to format the storage and change the device identity.

Sensors configuration:
Invalid new address!
HTS221  humidity & temperature    = 0xBC
LPS22HB pressure & temperature    = 0xB1
LIS3MDL magnetometer              = 0x3D
LSM6DSL accelerometer & gyroscope = 0x6A

Connecting to the network using Wifi...
Connected to the network successfully. IP address: 192.168.1.3
Initializing Pelion Device Management Client...
Initialized Pelion Client. Registering...
Registered to Pelion Device Management. Endpoint Name: 0169********************001002d5

ADC temp:     23.0037 C,  vref:      0.3661 V
HTS221 temp:   28.700 C,  humidity:   31.90 %
LPS22HB temp:  29.600 C,  pressure: 1032.01 mbar
LIS3MDL mag:    0.217 x,  -0.284 y,  -0.053 z [gauss]
LSM6DSL acc:    0.005 x,  -0.014 y,   1.029 z [g]
LSM6DSL gyro:   0.910 x,  -0.910 y,   1.120 z [dps]
VL53L0X dist:    1855 mm
Committer:
screamer
Date:
Mon Mar 11 11:28:07 2019 +0000
Revision:
31:da14aa77f977
Parent:
10:b27c962b3c3f
Revert back to Mbed OS 5.10.4 due to issues to fit in RAM2 on GCC_ARM

Who changed what in which revision?

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