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