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