Mistake on this page?
Report an issue in GitHub or email us
OSPIFBlockDevice.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2020 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_OSPIF_BLOCK_DEVICE_H
18 #define MBED_OSPIF_BLOCK_DEVICE_H
19 
20 #include "drivers/OSPI.h"
21 #include "blockdevice/internal/SFDP.h"
22 #include "blockdevice/BlockDevice.h"
23 #include "platform/Callback.h"
24 
25 #ifndef MBED_CONF_OSPIF_OSPI_IO0
26 #define MBED_CONF_OSPIF_OSPI_IO0 NC
27 #endif
28 #ifndef MBED_CONF_OSPIF_OSPI_IO1
29 #define MBED_CONF_OSPIF_OSPI_IO1 NC
30 #endif
31 #ifndef MBED_CONF_OSPIF_OSPI_IO2
32 #define MBED_CONF_OSPIF_OSPI_IO2 NC
33 #endif
34 #ifndef MBED_CONF_OSPIF_OSPI_IO3
35 #define MBED_CONF_OSPIF_OSPI_IO3 NC
36 #endif
37 #ifndef MBED_CONF_OSPIF_OSPI_IO4
38 #define MBED_CONF_OSPIF_OSPI_IO4 NC
39 #endif
40 #ifndef MBED_CONF_OSPIF_OSPI_IO5
41 #define MBED_CONF_OSPIF_OSPI_IO5 NC
42 #endif
43 #ifndef MBED_CONF_OSPIF_OSPI_IO6
44 #define MBED_CONF_OSPIF_OSPI_IO6 NC
45 #endif
46 #ifndef MBED_CONF_OSPIF_OSPI_IO7
47 #define MBED_CONF_OSPIF_OSPI_IO7 NC
48 #endif
49 #ifndef MBED_CONF_OSPIF_OSPI_SCK
50 #define MBED_CONF_OSPIF_OSPI_SCK NC
51 #endif
52 #ifndef MBED_CONF_OSPIF_OSPI_CSN
53 #define MBED_CONF_OSPIF_OSPI_CSN NC
54 #endif
55 #ifndef MBED_CONF_OSPIF_OSPI_DQS
56 #define MBED_CONF_OSPIF_OSPI_DQS NC
57 #endif
58 #ifndef MBED_CONF_OSPIF_OSPI_POLARITY_MODE
59 #define MBED_CONF_OSPIF_OSPI_POLARITY_MODE 0
60 #endif
61 #ifndef MBED_CONF_OSPIF_OSPI_FREQ
62 #define MBED_CONF_OSPIF_OSPI_FREQ 40000000
63 #endif
64 
65 /** Enum ospif standard error codes
66  *
67  * @enum ospif_bd_error
68  */
69 enum ospif_bd_error {
70  OSPIF_BD_ERROR_OK = 0, /*!< no error */
71  OSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
72  OSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
73  OSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
74  OSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
75  OSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
76  OSPIF_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */
77  OSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active OSPIF devices exceeded */
78 };
79 
80 enum _mode {
81  SPI,
82  SOPI,
83  DOPI
84 };
85 
86 /** Enum ospif polarity mode
87  *
88  * @enum ospif_polarity_mode
89  */
90 enum ospif_polarity_mode {
91  OSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
92  OSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
93 };
94 
95 #define OSPIF_MAX_ACTIVE_FLASH_DEVICES 10
96 
97 /** BlockDevice for SFDP based flash devices over OSPI bus
98  *
99  * @code
100  * // Here's an example using OSPI flash device on NUCLEO_L4R9I target
101  * #include "mbed.h"
102  * #include "OSPIFBlockDevice.h"
103  *
104  * OSPIFBlockDevice block_device(OSPI_FLASH1_IO0, OSPI_FLASH1_IO1, OSPI_FLASH1_IO2, OSPI_FLASH1_IO3, OSPI_FLASH1_IO4, OSPI_FLASH1_IO5, OSPI_FLASH1_IO6, OSPI_FLASH1_IO7
105  * OSPI_FLASH1_SCK, OSPI_FLASH1_CSN, OSPI_FLASH1_DQS, OSPIF_POLARITY_MODE_0, MBED_CONF_OSPIF_OSPI_FREQ);
106  *
107  * int main()
108  * {
109  * printf("OSPI SFDP Flash Block Device example\n");
110  *
111  * // Initialize the OSPI flash device and print the memory layout
112  * block_device.init();
113  * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
114  *
115  * printf("OSPIF BD size: %llu\n", block_device.size());
116  * printf("OSPIF BD read size: %llu\n", block_device.get_read_size());
117  * printf("OSPIF BD program size: %llu\n", block_device.get_program_size());
118  * printf("OSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
119  *
120  * // Write "Hello World!" to the first block
121  * char *buffer = (char *) malloc(sector_size_at_address_0);
122  * sprintf(buffer, "Hello World!\n");
123  * block_device.erase(0, sector_size_at_address_0);
124  * block_device.program(buffer, 0, sector_size_at_address_0);
125  *
126  * // Read back what was stored
127  * block_device.read(buffer, 0, sector_size_at_address_0);
128  * printf("%s", buffer);
129  *
130  * // Deinitialize the device
131  * block_device.deinit();
132  * }
133  * @endcode
134  */
136 public:
137  /** Create OSPIFBlockDevice - An SFDP based Flash Block Device over OSPI bus
138  *
139  * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
140  * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
141  * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
142  * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
143  * @param io4 5th IO pin used for sending/receiving data during data phase of a transaction
144  * @param io5 6th IO pin used for sending/receiving data during data phase of a transaction
145  * @param io6 7th IO pin used for sending/receiving data during data phase of a transaction
146  * @param io7 8th IO pin used for sending/receiving data during data phase of a transaction
147  * @param sclk OSPI Clock pin
148  * @param csel OSPI chip select pin
149  * @param dqs OSPI dqs pin
150  * @param clock_mode specifies the OSPI Clock Polarity mode (OSPIF_POLARITY_MODE_0/OSPIF_POLARITY_MODE_1)
151  * default value = 0
152  * @param freq Clock frequency of the OSPI bus (defaults to 40MHz)
153  */
154  OSPIFBlockDevice(PinName io0 = MBED_CONF_OSPIF_OSPI_IO0,
155  PinName io1 = MBED_CONF_OSPIF_OSPI_IO1,
156  PinName io2 = MBED_CONF_OSPIF_OSPI_IO2,
157  PinName io3 = MBED_CONF_OSPIF_OSPI_IO3,
158  PinName io4 = MBED_CONF_OSPIF_OSPI_IO4,
159  PinName io5 = MBED_CONF_OSPIF_OSPI_IO5,
160  PinName io6 = MBED_CONF_OSPIF_OSPI_IO6,
161  PinName io7 = MBED_CONF_OSPIF_OSPI_IO7,
162  PinName sclk = MBED_CONF_OSPIF_OSPI_SCK,
163  PinName csel = MBED_CONF_OSPIF_OSPI_CSN,
164  PinName dqs = MBED_CONF_OSPIF_OSPI_DQS,
165  int clock_mode = MBED_CONF_OSPIF_OSPI_POLARITY_MODE,
166  int freq = MBED_CONF_OSPIF_OSPI_FREQ);
167 
168  /** Initialize a block device
169  *
170  * @return OSPIF_BD_ERROR_OK(0) - success
171  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
172  * OSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
173  * OSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
174  */
175  virtual int init();
176 
177  /** Deinitialize a block device
178  *
179  * @return OSPIF_BD_ERROR_OK(0) - success
180  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
181  */
182  virtual int deinit();
183 
184  /** Desctruct OSPIFBlockDevie
185  */
187  {
188  deinit();
189  }
190 
191  /** Read blocks from a block device
192  *
193  * @param buffer Buffer to write blocks to
194  * @param addr Address of block to begin reading from
195  * @param size Size to read in bytes, must be a multiple of read block size
196  * @return OSPIF_BD_ERROR_OK(0) - success
197  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
198  */
199  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
200 
201  /** Program blocks to a block device
202  *
203  * The blocks must have been erased prior to being programmed
204  *
205  * @param buffer Buffer of data to write to blocks
206  * @param addr Address of block to begin writing to
207  * @param size Size to write in bytes, must be a multiple of program block size
208  * @return OSPIF_BD_ERROR_OK(0) - success
209  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
210  * OSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
211  * OSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
212  * OSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
213  */
214  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
215 
216  /** Erase blocks on a block device
217  *
218  * The state of an erased block is undefined until it has been programmed
219  *
220  * @param addr Address of block to begin erasing
221  * @param size Size to erase in bytes, must be a multiple of erase block size
222  * @return OSPIF_BD_ERROR_OK(0) - success
223  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
224  * OSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
225  * OSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
226  * OSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
227  * OSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
228  */
229  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
230 
231  /** Get the size of a readable block
232  *
233  * @return Size of a readable block in bytes
234  */
235  virtual mbed::bd_size_t get_read_size() const;
236 
237  /** Get the size of a programable block
238  *
239  * @return Size of a program block size in bytes
240  * @note Must be a multiple of the read size
241  */
242  virtual mbed::bd_size_t get_program_size() const;
243 
244  /** Get the size of a eraseable block
245  *
246  * @return Size of a minimal erase block, common to all regions, in bytes
247  * @note Must be a multiple of the program size
248  */
249  virtual mbed::bd_size_t get_erase_size() const;
250 
251  /** Get the size of minimal eraseable sector size of given address
252  *
253  * @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
254  * @return Size of minimal erase sector size, in given address region, in bytes
255  * @note Must be a multiple of the program size
256  */
257  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr);
258 
259  /** Get the value of storage byte after it was erased
260  *
261  * If get_erase_value returns a non-negative byte value, the underlying
262  * storage is set to that value when erased, and storage containing
263  * that value can be programmed without another erase.
264  *
265  * @return The value of storage when erased, or -1 if you can't
266  * rely on the value of erased storage
267  */
268  virtual int get_erase_value() const;
269 
270  /** Get the total size of the underlying device
271  *
272  * @return Size of the underlying device in bytes
273  */
274  virtual mbed::bd_size_t size() const;
275 
276  /** Get the BlockDevice class type.
277  *
278  * @return A string represent the BlockDevice class type.
279  */
280  virtual const char *get_type() const;
281 
282  /** Change the operation mode(SPI, SOPI or DOPI) of flash.
283  *
284  * @return OSPIF_BD_ERROR_OK(0) - success
285  * OSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
286  * OSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
287  * OSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
288  * OSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
289  * OSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
290  */
291  virtual int change_mode(int mode);
292 
293 private:
294  /********************************/
295  /* Different Device Csel Mgmt */
296  /********************************/
297  // Add a new OSPI device CS to existing devices list.
298  // Only one OSPIFBlockDevice instance per CS is allowed
299  int add_new_csel_instance(PinName csel);
300 
301  // Remove device CS from existing device list upon destroying object (last deinit is called)
302  int remove_csel_instance(PinName csel);
303 
304  /********************************/
305  /* Calls to OSPI Driver APIs */
306  /********************************/
307  // Send Program/Write command to Driver
308  ospi_status_t _ospi_send_program_command(mbed::ospi_inst_t prog_instruction, const void *buffer,
309  mbed::bd_addr_t addr, mbed::bd_size_t *size);
310 
311  // Send Read command to Driver
312  ospi_status_t _ospi_send_read_command(mbed::ospi_inst_t read_instruction, void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
313 
314  // Send Erase Instruction using command_transfer command to Driver
315  ospi_status_t _ospi_send_erase_command(mbed::ospi_inst_t erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
316 
317  // Send Generic command_transfer command to Driver
318  ospi_status_t _ospi_send_general_command(mbed::ospi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
319  mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);
320 
321  // Send command to read from the SFDP table
322  int _ospi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length);
323 
324  // Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
325  ospi_status_t _ospi_read_status_registers(uint8_t *reg_buffer);
326 
327  // Set the contents of status registers 1 and 2 from a buffer (buffer must have a length of 2)
328  ospi_status_t _ospi_write_status_registers(uint8_t *reg_buffer);
329 
330  // Send set_frequency command to Driver
331  ospi_status_t _ospi_set_frequency(int freq);
332 
333  // Update the 4-byte addressing extension register with the MSB of the address if it is in use
334  ospi_status_t _ospi_update_4byte_ext_addr_reg(bd_addr_t addr);
335 
336  /*********************************/
337  /* Flash Configuration Functions */
338  /*********************************/
339  // Clear the device's block protection
340  int _clear_block_protection();
341 
342  // Configure Write Enable in Status Register
343  int _set_write_enable();
344 
345  // Wait on status register until write not-in-progress
346  bool _is_mem_ready();
347 
348  // Enable Fast Mode - for flash chips with low power default
349  int _enable_fast_mode();
350 
351  // Enable OPI Mode
352  int _enable_opi_mdoe();
353 
354  // Query vendor ID and handle special behavior that isn't covered by SFDP data
355  int _handle_vendor_quirks();
356 
357  /****************************************/
358  /* SFDP Detection and Parsing Functions */
359  /****************************************/
360  // Parse and Detect required Basic Parameters from Table
361  int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
362  mbed::sfdp_hdr_info &sfdp_info);
363 
364  // Parse and Detect 4-Byte Address Instruction Parameters from Table
365  int _sfdp_parse_4_byte_inst_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
366  mbed::sfdp_hdr_info &sfdp_info);
367 
368  // Detect the soft reset protocol and reset - returns error if soft reset is not supported
369  int _sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr);
370 
371  // Detect fastest read Bus mode supported by device
372  int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
373  bool &set_quad_enable, bool &is_qpi_mode, bool &is_opi_mode);
374 
375  // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
376  int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
377 
378  // Enable QPI mode (4-4-4)
379  int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
380 
381  // Detect 4-byte addressing mode and enable it if supported
382  int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size);
383 
384 private:
385  enum ospif_clear_protection_method_t {
386  OSPIF_BP_ULBPR, // Issue global protection unlock instruction
387  OSPIF_BP_CLEAR_SR, // Clear protection bits in status register 1
388  };
389 
390  // OSPI Driver Object
391  mbed::OSPI _ospi;
392 
393  // Static List of different OSPI based Flash devices csel that already exist
394  // Each OSPI Flash device csel can have only 1 OSPIFBlockDevice instance
395  // _devices_mutex is used to lock csel list - only one OSPIFBlockDevice instance per csel is allowed
396  static SingletonPtr<PlatformMutex> _devices_mutex;
397  static int _number_of_active_ospif_flash_csel;
398  static PinName *_active_ospif_flash_csel_arr;
399 
400  int _unique_device_status;
401  PinName _csel;
402 
403  // Mutex is used to protect Flash device for some OSPI Driver commands that must be done sequentially with no other commands in between
404  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
405  PlatformMutex _mutex;
406 
407  // Command Instructions
408  mbed::ospi_inst_t _read_instruction;
409  mbed::ospi_inst_t _prog_instruction;
410  mbed::ospi_inst_t _legacy_erase_instruction;
411 
412  // Status register write/read instructions
413  unsigned int _num_status_registers;
414  mbed::ospi_inst_t _write_status_reg_2_inst;
415  mbed::ospi_inst_t _read_status_reg_2_inst; // If three registers, this instruction reads the latter two
416 
417  // Attempt to enable 4-byte addressing. True by default, but may be disabled for some vendors
418  bool _attempt_4_byte_addressing;
419  // 4-byte addressing extension register write instruction
420  mbed::ospi_inst_t _4byte_msb_reg_write_inst;
421 
422  // Flash support 4-Byte instructions,like READ4B(0x13).
423  bool _support_4_byte_inst;
424 
425  // Quad mode enable status register and bit
426  int _quad_enable_register_idx;
427  int _quad_enable_bit;
428 
429  bool _needs_fast_mode;
430 
431  // Clear block protection
432  ospif_clear_protection_method_t _clear_protection_method;
433 
434  // Data extracted from the devices SFDP structure
435  mbed::sfdp_hdr_info _sfdp_info;
436 
437  unsigned int _page_size_bytes; // Page size - 256 Bytes default
438  int _freq;
439 
440  // Bus speed configuration
441  ospi_bus_width_t _inst_width; //Bus width for Instruction phase
442  ospi_inst_size_t _inst_size; //Instruction Size
443  ospi_bus_width_t _address_width; //Bus width for Address phase
444  ospi_address_size_t _address_size; //Number of bits for address
445  ospi_alt_size_t _alt_size; //Number of bits for alt
446  bool _alt_enabled; //Whether alt is enabled
447  uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode
448  ospi_bus_width_t _data_width; //Bus width for Data phase
449 
450  uint32_t _init_ref_count;
451  bool _is_initialized;
452 };
453 
454 #endif
virtual int get_erase_value() const
Get the value of storage byte after it was erased.
virtual int deinit()
Deinitialize a block device.
BlockDevice for SFDP based flash devices over OSPI bus.
virtual int change_mode(int mode)
Change the operation mode(SPI, SOPI or DOPI) of flash.
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:48
A OSPI Driver, used for communicating with OSPI slave devices.
Definition: OSPI.h:87
virtual const char * get_type() const
Get the BlockDevice class type.
virtual mbed::bd_size_t get_read_size() const
Get the size of a readable block.
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size)
Erase blocks on a block device.
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
virtual int init()
Initialize a block device.
SFDP JEDEC Parameter Table info.
Definition: SFDP.h:79
virtual mbed::bd_size_t get_erase_size() const
Get the size of a eraseable block.
virtual mbed::bd_size_t size() const
Get the total size of the underlying device.
virtual mbed::bd_size_t get_program_size() const
Get the size of a programable block.
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Program blocks to a block device.
int ospi_inst_t
Type representing a OSPI instruction.
Definition: OSPI.h:46
virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Read blocks from a block device.
OSPIFBlockDevice(PinName io0=NC, PinName io1=NC, PinName io2=NC, PinName io3=NC, PinName io4=NC, PinName io5=NC, PinName io6=NC, PinName io7=NC, PinName sclk=NC, PinName csel=NC, PinName dqs=NC, int clock_mode=0, int freq=40000000)
Create OSPIFBlockDevice - An SFDP based Flash Block Device over OSPI bus.
~OSPIFBlockDevice()
Desctruct OSPIFBlockDevie.
Callback class based on template specialization.
Definition: Callback.h:53
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.