Mistake on this page?
Report an issue in GitHub or email us
QSPIFBlockDevice.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2018 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef MBED_QSPIF_BLOCK_DEVICE_H
17 #define MBED_QSPIF_BLOCK_DEVICE_H
18 
19 #include "drivers/QSPI.h"
20 #include "features/storage/blockdevice/BlockDevice.h"
21 
22 /** Enum qspif standard error codes
23  *
24  * @enum qspif_bd_error
25  */
26 enum qspif_bd_error {
27  QSPIF_BD_ERROR_OK = 0, /*!< no error */
28  QSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
29  QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
30  QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
31  QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
32  QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
33  QSPIF_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */
34  QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */
35 };
36 
37 /** Enum qspif polarity mode
38  *
39  * @enum qspif_polarity_mode
40  */
41 enum qspif_polarity_mode {
42  QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
43  QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
44 };
45 
46 #define QSPIF_MAX_REGIONS 10
47 #define MAX_NUM_OF_ERASE_TYPES 4
48 #define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10
49 
50 /** BlockDevice for SFDP based flash devices over QSPI bus
51  *
52  * @code
53  * // Here's an example using QSPI flash device on DISCO_L476VG target
54  * #include "mbed.h"
55  * #include "QSPIFBlockDevice.h"
56  *
57  * QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
58  * QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
59  *
60  * int main()
61  * {
62  * printf("QSPI SFDP Flash Block Device example\n");
63  *
64  * // Initialize the SPI flash device and print the memory layout
65  * block_device.init();
66  * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
67  *
68  * printf("QSPIF BD size: %llu\n", block_device.size());
69  * printf("QSPIF BD read size: %llu\n", block_device.get_read_size());
70  * printf("QSPIF BD program size: %llu\n", block_device.get_program_size());
71  * printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
72  *
73  * // Write "Hello World!" to the first block
74  * char *buffer = (char *) malloc(sector_size_at_address_0);
75  * sprintf(buffer, "Hello World!\n");
76  * block_device.erase(0, sector_size_at_address_0);
77  * block_device.program(buffer, 0, sector_size_at_address_0);
78  *
79  * // Read back what was stored
80  * block_device.read(buffer, 0, sector_size_at_address_0);
81  * printf("%s", buffer);
82  *
83  * // Deinitialize the device
84  * block_device.deinit();
85  * }
86  * @endcode
87  */
89 public:
90  /** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus
91  *
92  * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
93  * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
94  * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
95  * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
96  * @param sclk QSPI Clock pin
97  * @param csel QSPI chip select pin
98  * @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1)
99  * default value = 0
100  * @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
101  *
102  */
103  QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel,
104  int clock_mode, int freq = MBED_CONF_QSPIF_QSPI_FREQ);
105 
106  /** Initialize a block device
107  *
108  * @return QSPIF_BD_ERROR_OK(0) - success
109  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
110  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
111  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
112  */
113  virtual int init();
114 
115  /** Deinitialize a block device
116  *
117  * @return QSPIF_BD_ERROR_OK(0) - success
118  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
119  */
120  virtual int deinit();
121 
122  /** Desctruct QSPIFBlockDevie
123  */
125  {
126  deinit();
127  }
128 
129  /** Read blocks from a block device
130  *
131  * @param buffer Buffer to write blocks to
132  * @param addr Address of block to begin reading from
133  * @param size Size to read in bytes, must be a multiple of read block size
134  * @return QSPIF_BD_ERROR_OK(0) - success
135  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
136  */
137  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
138 
139  /** Program blocks to a block device
140  *
141  * The blocks must have been erased prior to being programmed
142  *
143  * @param buffer Buffer of data to write to blocks
144  * @param addr Address of block to begin writing to
145  * @param size Size to write in bytes, must be a multiple of program block size
146  * @return QSPIF_BD_ERROR_OK(0) - success
147  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
148  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
149  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
150  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
151  */
152  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
153 
154  /** Erase blocks on a block device
155  *
156  * The state of an erased block is undefined until it has been programmed
157  *
158  * @param addr Address of block to begin erasing
159  * @param size Size to erase in bytes, must be a multiple of erase block size
160  * @return QSPIF_BD_ERROR_OK(0) - success
161  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
162  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
163  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
164  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
165  * QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
166  */
167  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
168 
169  /** Get the size of a readable block
170  *
171  * @return Size of a readable block in bytes
172  */
173  virtual mbed::bd_size_t get_read_size() const;
174 
175  /** Get the size of a programable block
176  *
177  * @return Size of a program block size in bytes
178  * @note Must be a multiple of the read size
179  */
180  virtual mbed::bd_size_t get_program_size() const;
181 
182  /** Get the size of a eraseable block
183  *
184  * @return Size of a minimal erase block, common to all regions, in bytes
185  * @note Must be a multiple of the program size
186  */
187  virtual mbed::bd_size_t get_erase_size() const;
188 
189  /** Get the size of minimal eraseable sector size of given address
190  *
191  * @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
192  * @return Size of minimal erase sector size, in given address region, in bytes
193  * @note Must be a multiple of the program size
194  */
195  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr);
196 
197  /** Get the value of storage byte after it was erased
198  *
199  * If get_erase_value returns a non-negative byte value, the underlying
200  * storage is set to that value when erased, and storage containing
201  * that value can be programmed without another erase.
202  *
203  * @return The value of storage when erased, or -1 if you can't
204  * rely on the value of erased storage
205  */
206  virtual int get_erase_value() const;
207 
208  /** Get the total size of the underlying device
209  *
210  * @return Size of the underlying device in bytes
211  */
212  virtual mbed::bd_size_t size() const;
213 
214  /** Get the BlockDevice class type.
215  *
216  * @return A string represent the BlockDevice class type.
217  */
218  virtual const char *get_type() const;
219 
220 private:
221  // Internal functions
222 
223 
224  /********************************/
225  /* Different Device Csel Mgmt */
226  /********************************/
227  // Add a new QSPI device CS to existing devices list.
228  // Only one QSPIFBlockDevice instance per CS is allowed
229  int add_new_csel_instance(PinName csel);
230 
231  // Remove device CS from existing device list upon destroying object (last deinit is called)
232  int remove_csel_instance(PinName csel);
233 
234  /********************************/
235  /* Calls to QSPI Driver APIs */
236  /********************************/
237  // Send Program/Write command to Driver
238  qspi_status_t _qspi_send_program_command(mbed::qspi_inst_t prog_instruction, const void *buffer,
239  mbed::bd_addr_t addr, mbed::bd_size_t *size);
240 
241  // Send Read command to Driver
242  qspi_status_t _qspi_send_read_command(mbed::qspi_inst_t read_instruction, void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
243 
244  // Send Erase Instruction using command_transfer command to Driver
245  qspi_status_t _qspi_send_erase_command(mbed::qspi_inst_t erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
246 
247  // Send Generic command_transfer command to Driver
248  qspi_status_t _qspi_send_general_command(mbed::qspi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
249  mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);
250 
251  // Send command to read from the SFDP table
252  qspi_status_t _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length);
253 
254  // Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
255  qspi_status_t _qspi_read_status_registers(uint8_t *reg_buffer);
256 
257  // Set the contents of status registers 1 and 2 from a buffer (buffer must have a length of 2)
258  qspi_status_t _qspi_write_status_registers(uint8_t *reg_buffer);
259 
260  // Send set_frequency command to Driver
261  qspi_status_t _qspi_set_frequency(int freq);
262 
263  // Update the 4-byte addressing extension register with the MSB of the address if it is in use
264  qspi_status_t _qspi_update_4byte_ext_addr_reg(bd_addr_t addr);
265 
266  /*********************************/
267  /* Flash Configuration Functions */
268  /*********************************/
269  // Clear the device's block protection
270  int _clear_block_protection();
271 
272  // Configure Write Enable in Status Register
273  int _set_write_enable();
274 
275  // Wait on status register until write not-in-progress
276  bool _is_mem_ready();
277 
278  // Enable Fast Mode - for flash chips with low power default
279  int _enable_fast_mode();
280 
281  /****************************************/
282  /* SFDP Detection and Parsing Functions */
283  /****************************************/
284  // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist)
285  int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
286  uint32_t &sector_map_table_addr, size_t &sector_map_table_size);
287 
288  // Parse and Detect required Basic Parameters from Table
289  int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size);
290 
291  // Parse and read information required by Regions Sector Map
292  int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size);
293 
294  // Detect the soft reset protocol and reset - returns error if soft reset is not supported
295  int _sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr);
296 
297  // Detect fastest read Bus mode supported by device
298  int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
299  bool &set_quad_enable, bool &is_qpi_mode);
300 
301  // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
302  int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
303 
304  // Enable QPI mode (4-4-4)
305  int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
306 
307  // Set Page size for program
308  int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
309 
310  // Detect all supported erase types
311  int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
312 
313  // Detect 4-byte addressing mode and enable it if supported
314  int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size);
315 
316  // Query vendor ID and handle special behavior that isn't covered by SFDP data
317  int _handle_vendor_quirks();
318 
319  /***********************/
320  /* Utilities Functions */
321  /***********************/
322  // Find the region to which the given offset belong to
323  int _utils_find_addr_region(mbed::bd_size_t offset);
324 
325  // Iterate on all supported Erase Types of the Region to which the offset belong to.
326  // Iterates from highest type to lowest
327  int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry);
328 
329 private:
330  enum qspif_clear_protection_method_t {
331  QSPIF_BP_ULBPR, // Issue global protection unlock instruction
332  QSPIF_BP_CLEAR_SR, // Clear protection bits in status register 1
333  };
334 
335  // QSPI Driver Object
336  mbed::QSPI _qspi;
337 
338  // Static List of different QSPI based Flash devices csel that already exist
339  // Each QSPI Flash device csel can have only 1 QSPIFBlockDevice instance
340  // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
341  static SingletonPtr<PlatformMutex> _devices_mutex;
342  static int _number_of_active_qspif_flash_csel;
343  static PinName *_active_qspif_flash_csel_arr;
344 
345  int _unique_device_status;
346  PinName _csel;
347 
348  // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
349  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
350  PlatformMutex _mutex;
351 
352  // Command Instructions
353  mbed::qspi_inst_t _read_instruction;
354  mbed::qspi_inst_t _legacy_erase_instruction;
355 
356  // Status register write/read instructions
357  unsigned int _num_status_registers;
358  mbed::qspi_inst_t _write_status_reg_2_inst;
359  mbed::qspi_inst_t _read_status_reg_2_inst; // If three registers, this instruction reads the latter two
360 
361  // Attempt to enable 4-byte addressing. True by default, but may be disabled for some vendors
362  bool _attempt_4_byte_addressing;
363  // 4-byte addressing extension register write instruction
364  mbed::qspi_inst_t _4byte_msb_reg_write_inst;
365 
366  // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
367  mbed::qspi_inst_t _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES];
368  unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];
369 
370  // Quad mode enable status register and bit
371  int _quad_enable_register_idx;
372  int _quad_enable_bit;
373 
374  bool _needs_fast_mode;
375 
376  // Clear block protection
377  qspif_clear_protection_method_t _clear_protection_method;
378 
379  // Sector Regions Map
380  int _regions_count; //number of regions
381  int _region_size_bytes[QSPIF_MAX_REGIONS]; //regions size in bytes
382  bd_size_t _region_high_boundary[QSPIF_MAX_REGIONS]; //region high address offset boundary
383  //Each Region can support a bit combination of any of the 4 Erase Types
384  uint8_t _region_erase_types_bitfield[QSPIF_MAX_REGIONS];
385  unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists)
386 
387  unsigned int _page_size_bytes; // Page size - 256 Bytes default
388  int _freq;
389  bd_size_t _device_size_bytes;
390 
391  // Bus speed configuration
392  qspi_bus_width_t _inst_width; //Bus width for Instruction phase
393  qspi_bus_width_t _address_width; //Bus width for Address phase
394  qspi_address_size_t _address_size; //Number of bits for address
395  qspi_alt_size_t _alt_size; //Number of bits for alt
396  bool _alt_enabled; //Whether alt is enabled
397  uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode
398  qspi_bus_width_t _data_width; //Bus width for Data phase
399 
400  uint32_t _init_ref_count;
401  bool _is_initialized;
402 };
403 
404 #endif
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Program blocks to a block device.
virtual mbed::bd_size_t get_program_size() const
Get the size of a programable block.
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:47
virtual mbed::bd_size_t get_erase_size() const
Get the size of a eraseable block.
~QSPIFBlockDevice()
Desctruct QSPIFBlockDevie.
virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Read blocks from a block device.
virtual mbed::bd_size_t size() const
Get the total size of the underlying device.
QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, int clock_mode, int freq=MBED_CONF_QSPIF_QSPI_FREQ)
Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus.
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
virtual int get_erase_value() const
Get the value of storage byte after it was erased.
virtual int deinit()
Deinitialize a block device.
virtual mbed::bd_size_t get_read_size() const
Get the size of a readable block.
enum qspi_address_size qspi_address_size_t
Address size in bits.
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size)
Erase blocks on a block device.
virtual int init()
Initialize a block device.
int qspi_inst_t
Type representing a QSPI instruction.
Definition: QSPI.h:46
virtual const char * get_type() const
Get the BlockDevice class type.
uint8_t qspi_alt_size_t
Alternative size in bits.
Definition: qspi_api.h:79
enum qspi_bus_width qspi_bus_width_t
QSPI Bus width.
BlockDevice for SFDP based flash devices over QSPI bus.
A QSPI Driver, used for communicating with QSPI slave devices.
Definition: QSPI.h:86
enum qspi_status qspi_status_t
QSPI return status.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.