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