blob: eac3cb27f40dc1baedce2bad96cab5259ca6a2c7 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Gurjant Kalsi <me@gurjantkalsi.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <err.h>
24#include <pow2.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include <arch/arm/cm.h>
29#include <kernel/event.h>
30#include <kernel/mutex.h>
31#include <lib/bio.h>
32#include <platform/n25qxxa.h>
33#include <platform/n25q512a.h>
34#include <platform/qspi.h>
35#include <trace.h>
36
37
38#define FOUR_BYTE_ADDR_THRESHOLD (1 << 24)
39#define LOCAL_TRACE 0
40
41static QSPI_HandleTypeDef qspi_handle;
42static DMA_HandleTypeDef hdma;
43
44static const char device_name[] = "qspi-flash";
45static bdev_t qspi_flash_device;
46static bio_erase_geometry_info_t geometry;
47
48static mutex_t spiflash_mutex;
49
50// Functions exported to Block I/O handler.
51static ssize_t spiflash_bdev_read(struct bdev* device, void* buf, off_t offset, size_t len);
52static ssize_t spiflash_bdev_read_block(struct bdev* device, void* buf, bnum_t block, uint count);
53static ssize_t spiflash_bdev_write_block(struct bdev* device, const void* buf, bnum_t block, uint count);
54static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset, size_t len);
55static int spiflash_ioctl(struct bdev* device, int request, void* argp);
56
57static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data);
58
59static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction);
60static ssize_t qspi_bulk_erase(bdev_t *device);
61static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr);
62static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr);
63
64static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*);
65static HAL_StatusTypeDef qspi_tx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*, uint8_t*);
66static HAL_StatusTypeDef qspi_rx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*, uint8_t*);
67
68status_t qspi_enable_linear(void);
69
70status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi);
71
72static uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address);
73static uint32_t get_address_size(uint32_t address);
74
75static event_t cmd_event;
76static event_t rx_event;
77static event_t tx_event;
78
79status_t hal_error_to_status(HAL_StatusTypeDef hal_status);
80
81// Must hold spiflash_mutex before calling.
82static status_t qspi_write_enable_unsafe(QSPI_HandleTypeDef* hqspi)
83{
84 QSPI_CommandTypeDef s_command;
85 QSPI_AutoPollingTypeDef s_config;
86 HAL_StatusTypeDef status;
87
88 /* Enable write operations */
89 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
90 s_command.Instruction = WRITE_ENABLE_CMD;
91 s_command.AddressMode = QSPI_ADDRESS_NONE;
92 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
93 s_command.DataMode = QSPI_DATA_NONE;
94 s_command.DummyCycles = 0;
95 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
96 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
97 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
98
99 status = HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
100 if (status != HAL_OK) {
101 return hal_error_to_status(status);
102 }
103
104 /* Configure automatic polling mode to wait for write enabling */
105 s_config.Match = N25QXXA_SR_WREN;
106 s_config.Mask = N25QXXA_SR_WREN;
107 s_config.MatchMode = QSPI_MATCH_MODE_AND;
108 s_config.StatusBytesSize = 1;
109 s_config.Interval = 0x10;
110 s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
111
112 s_command.Instruction = READ_STATUS_REG_CMD;
113 s_command.DataMode = QSPI_DATA_1_LINE;
114
115 status = HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
116 if (status != HAL_OK) {
117 return hal_error_to_status(status);
118 }
119
120 return NO_ERROR;
121}
122
123// Must hold spiflash_mutex before calling.
124static status_t qspi_dummy_cycles_cfg_unsafe(QSPI_HandleTypeDef* hqspi)
125{
126 QSPI_CommandTypeDef s_command;
127 uint8_t reg;
128 HAL_StatusTypeDef status;
129
130 /* Initialize the read volatile configuration register command */
131 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
132 s_command.Instruction = READ_VOL_CFG_REG_CMD;
133 s_command.AddressMode = QSPI_ADDRESS_NONE;
134 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
135 s_command.DataMode = QSPI_DATA_1_LINE;
136 s_command.DummyCycles = 0;
137 s_command.NbData = 1;
138 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
139 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
140 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
141
142 /* Configure the command */
143 status = HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
144 if (status != HAL_OK) {
145 return hal_error_to_status(status);
146 }
147
148 /* Reception of the data */
149 status = HAL_QSPI_Receive(hqspi, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
150 if (status != HAL_OK) {
151 return hal_error_to_status(status);
152 }
153
154 /* Enable write operations */
155 status = qspi_write_enable_unsafe(hqspi);
156 if (status != NO_ERROR) {
157 return status;
158 }
159
160 /* Update volatile configuration register (with new dummy cycles) */
161 s_command.Instruction = WRITE_VOL_CFG_REG_CMD;
162 MODIFY_REG(
163 reg, N25QXXA_VCR_NB_DUMMY,
164 (N25QXXA_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25QXXA_VCR_NB_DUMMY)));
165
166 /* Configure the write volatile configuration register command */
167 status = HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
168 if (status != HAL_OK) {
169 return hal_error_to_status(status);
170 }
171
172 /* Transmission of the data */
173 status = HAL_QSPI_Transmit(hqspi, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
174 if (status != HAL_OK) {
175 return hal_error_to_status(status);
176 }
177
178 return NO_ERROR;
179}
180
181// Must hold spiflash_mutex before calling.
182static status_t qspi_auto_polling_mem_ready_unsafe(QSPI_HandleTypeDef* hqspi)
183{
184 QSPI_CommandTypeDef s_command;
185 QSPI_AutoPollingTypeDef s_config;
186 HAL_StatusTypeDef status;
187
188 /* Configure automatic polling mode to wait for memory ready */
189 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
190 s_command.Instruction = READ_STATUS_REG_CMD;
191 s_command.AddressMode = QSPI_ADDRESS_NONE;
192 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
193 s_command.DataMode = QSPI_DATA_1_LINE;
194 s_command.DummyCycles = 0;
195 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
196 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
197 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
198
199 s_config.Match = 0;
200 s_config.Mask = N25QXXA_SR_WIP;
201 s_config.MatchMode = QSPI_MATCH_MODE_AND;
202 s_config.StatusBytesSize = 1;
203 s_config.Interval = 0x10;
204 s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
205
206 status = HAL_QSPI_AutoPolling_IT(hqspi, &s_command, &s_config);
207 if (status != HAL_OK) {
208 return hal_error_to_status(status);
209 }
210
211 return NO_ERROR;
212}
213
214// Must hold spiflash_mutex before calling.
215static status_t qspi_reset_memory_unsafe(QSPI_HandleTypeDef* hqspi)
216{
217 QSPI_CommandTypeDef s_command;
218 HAL_StatusTypeDef status;
219
220 /* Initialize the reset enable command */
221 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
222 s_command.Instruction = RESET_ENABLE_CMD;
223 s_command.AddressMode = QSPI_ADDRESS_NONE;
224 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
225 s_command.DataMode = QSPI_DATA_NONE;
226 s_command.DummyCycles = 0;
227 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
228 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
229 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
230
231 /* Send the command */
232 status = qspi_cmd(hqspi, &s_command);
233 if (status != HAL_OK) {
234 return hal_error_to_status(status);
235 }
236
237 /* Send the reset memory command */
238 s_command.Instruction = RESET_MEMORY_CMD;
239 status = qspi_cmd(hqspi, &s_command);
240 if (status != HAL_OK) {
241 return hal_error_to_status(status);
242 }
243
244 /* Configure automatic polling mode to wait the memory is ready */
245 status = qspi_auto_polling_mem_ready_unsafe(hqspi);
246 if (status != NO_ERROR) {
247 return hal_error_to_status(status);
248 }
249
250 return NO_ERROR;
251}
252
253static ssize_t spiflash_bdev_read_block(struct bdev* device, void* buf,
254 bnum_t block, uint count)
255{
256 LTRACEF("device %p, buf %p, block %u, count %u\n",
257 device, buf, block, count);
258
259 if (!IS_ALIGNED((uintptr_t)buf, CACHE_LINE)) {
260 DEBUG_ASSERT(IS_ALIGNED((uintptr_t)buf, CACHE_LINE));
261 return ERR_INVALID_ARGS;
262 }
263
264 count = bio_trim_block_range(device, block, count);
265 if (count == 0)
266 return 0;
267
268 QSPI_CommandTypeDef s_command;
269 HAL_StatusTypeDef status;
270
271 uint64_t largest_offset = (block + count) * device->block_size - 1;
272
273 // /* Initialize the read command */
274 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
275 s_command.Instruction = get_specialized_instruction(QUAD_OUT_FAST_READ_CMD, largest_offset);
276 s_command.AddressMode = QSPI_ADDRESS_1_LINE;
277 s_command.AddressSize = get_address_size(largest_offset);
278 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
279 s_command.DataMode = QSPI_DATA_4_LINES;
280 s_command.DummyCycles = N25QXXA_DUMMY_CYCLES_READ_QUAD;
281 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
282 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
283 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
284
285 s_command.NbData = device->block_size;
286
287 ssize_t retcode = 0;
288
289 mutex_acquire(&spiflash_mutex);
290
291 s_command.Address = block * device->block_size;
292 for (uint i = 0; i < count; i++) {
293
294 status = HAL_QSPI_Command(&qspi_handle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
295 if (status != HAL_OK) {
296 retcode = hal_error_to_status(status);
297 goto err;
298 }
299
300 // /* Reception of the data */
301 status = qspi_rx_dma(&qspi_handle, &s_command, buf);
302 if (status != HAL_OK) {
303 retcode = hal_error_to_status(status);
304 goto err;
305 }
306
307 buf += device->block_size;
308 retcode += device->block_size;
309 s_command.Address += device->block_size;
310 }
311
312err:
313 mutex_release(&spiflash_mutex);
314 return retcode;
315}
316
317static ssize_t spiflash_bdev_write_block(struct bdev* device, const void* _buf,
318 bnum_t block, uint count)
319{
320 count = bio_trim_block_range(device, block, count);
321 if (count == 0) {
322 return 0;
323 }
324
325 const uint8_t *buf = _buf;
326
327 mutex_acquire(&spiflash_mutex);
328
329 ssize_t total_bytes_written = 0;
330 for (; count > 0; count--, block++) {
331 ssize_t bytes_written = qspi_write_page_unsafe(block * N25QXXA_PAGE_SIZE, buf);
332 if (bytes_written < 0) {
333 printf("qspi_write_page_unsafe failed\n");
334 total_bytes_written = bytes_written;
335 goto err;
336 }
337
338 buf += N25QXXA_PAGE_SIZE;
339 total_bytes_written += bytes_written;
340 }
341
342err:
343 mutex_release(&spiflash_mutex);
344 return total_bytes_written;
345}
346
347static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset,
348 size_t len)
349{
350 len = bio_trim_range(device, offset, len);
351 if (len == 0) {
352 return 0;
353 }
354
355 ssize_t total_erased = 0;
356
357 mutex_acquire(&spiflash_mutex);
358
359 // Choose an erase strategy based on the number of bytes being erased.
360 if (len == device->total_size && offset == 0) {
361 // Bulk erase the whole flash.
362 total_erased = qspi_bulk_erase(device);
363 goto finish;
364 }
365
366 // Erase as many sectors as necessary, then switch to subsector erase for
367 // more fine grained erasure.
368 while (((ssize_t)len - total_erased) >= N25QXXA_SECTOR_SIZE) {
369 ssize_t erased = qspi_erase_sector(device, offset);
370 if (erased < 0) {
371 total_erased = erased;
372 goto finish;
373 }
374 total_erased += erased;
375 offset += erased;
376 }
377
378 while (total_erased < (ssize_t)len) {
379 ssize_t erased = qspi_erase_subsector(device, offset);
380 if (erased < 0) {
381 total_erased = erased;
382 goto finish;
383 }
384 total_erased += erased;
385 offset += erased;
386 }
387
388finish:
389 mutex_release(&spiflash_mutex);
390 return total_erased;
391}
392
393static int spiflash_ioctl(struct bdev* device, int request, void* argp)
394{
395 int ret = NO_ERROR;
396
397 switch (request) {
398 case BIO_IOCTL_GET_MEM_MAP:
399 /* put the device into linear mode */
400 ret = qspi_enable_linear();
401 // Fallthrough.
402 case BIO_IOCTL_GET_MAP_ADDR:
403 if (argp)
404 *(void **)argp = (void*)QSPI_BASE;
405 break;
406 default:
407 ret = ERR_NOT_SUPPORTED;
408 }
409
410 return ret;
411}
412
413static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data)
414{
415 if (!IS_ALIGNED(addr, N25QXXA_PAGE_SIZE)) {
416 return ERR_INVALID_ARGS;
417 }
418
419 HAL_StatusTypeDef status;
420
421 QSPI_CommandTypeDef s_command = {
422 .InstructionMode = QSPI_INSTRUCTION_1_LINE,
423 .Instruction = get_specialized_instruction(QUAD_IN_FAST_PROG_CMD, addr),
424 .AddressMode = QSPI_ADDRESS_1_LINE,
425 .AddressSize = get_address_size(addr),
426 .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
427 .DataMode = QSPI_DATA_4_LINES,
428 .DummyCycles = 0,
429 .DdrMode = QSPI_DDR_MODE_DISABLE,
430 .DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY,
431 .SIOOMode = QSPI_SIOO_INST_EVERY_CMD,
432 .Address = addr,
433 .NbData = N25QXXA_PAGE_SIZE
434 };
435
436 status_t write_enable_result = qspi_write_enable_unsafe(&qspi_handle);
437 if (write_enable_result != NO_ERROR) {
438 return write_enable_result;
439 }
440
441 status = HAL_QSPI_Command(&qspi_handle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
442 if (status != HAL_OK) {
443 return hal_error_to_status(status);
444 }
445
446 status = qspi_tx_dma(&qspi_handle, &s_command, (uint8_t*)data);
447 if (status != HAL_OK) {
448 return hal_error_to_status(status);
449 }
450
451 status_t auto_polling_mem_ready_result =
452 qspi_auto_polling_mem_ready_unsafe(&qspi_handle);
453 if (auto_polling_mem_ready_result != NO_ERROR) {
454 return auto_polling_mem_ready_result;
455 }
456
457 return N25QXXA_PAGE_SIZE;
458}
459
460
461status_t qspi_flash_init(size_t flash_size)
462{
463 status_t result = NO_ERROR;
464
465 event_init(&cmd_event, false, EVENT_FLAG_AUTOUNSIGNAL);
466 event_init(&tx_event, false, EVENT_FLAG_AUTOUNSIGNAL);
467 event_init(&rx_event, false, EVENT_FLAG_AUTOUNSIGNAL);
468
469 mutex_init(&spiflash_mutex);
470 result = mutex_acquire(&spiflash_mutex);
471 if (result != NO_ERROR) {
472 return result;
473 }
474
475 qspi_handle.Instance = QUADSPI;
476
477 HAL_StatusTypeDef status;
478
479 // Enable the QuadSPI memory interface clock
480 __HAL_RCC_QSPI_CLK_ENABLE();
481
482 // Reset the QuadSPI memory interface
483 __HAL_RCC_QSPI_FORCE_RESET();
484 __HAL_RCC_QSPI_RELEASE_RESET();
485
486 // Setup the QSPI Flash device.
487 qspi_handle.Init.ClockPrescaler = 1;
488 qspi_handle.Init.FifoThreshold = 4;
489 qspi_handle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
490 qspi_handle.Init.FlashSize = POSITION_VAL(flash_size) - 1;
491 qspi_handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
492 qspi_handle.Init.ClockMode = QSPI_CLOCK_MODE_0;
493 qspi_handle.Init.FlashID = QSPI_FLASH_ID_1;
494 qspi_handle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
495
496 status = HAL_QSPI_Init(&qspi_handle);
497 if (status != HAL_OK) {
498 result = hal_error_to_status(status);
499 goto err;
500 }
501
502 // enable the qspi interrupt
503 HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
504
505 result = qspi_reset_memory_unsafe(&qspi_handle);
506 if (result != NO_ERROR) {
507 goto err;
508 }
509
510 result = qspi_dummy_cycles_cfg_unsafe(&qspi_handle);
511 if (result != NO_ERROR) {
512 goto err;
513 }
514
515 result = qspi_dma_init(&qspi_handle);
516 if (result != NO_ERROR) {
517 goto err;
518 }
519
520 // Initialize the QSPI Flash and register it as a Block I/O device.
521 geometry.erase_size = log2_uint(N25QXXA_SUBSECTOR_SIZE);
522 geometry.erase_shift = log2_uint(N25QXXA_SUBSECTOR_SIZE);
523 geometry.start = 0;
524 geometry.size = flash_size;
525
526 bio_initialize_bdev(&qspi_flash_device, device_name, N25QXXA_PAGE_SIZE,
527 (flash_size / N25QXXA_PAGE_SIZE), 1, &geometry,
528 BIO_FLAG_CACHE_ALIGNED_READS);
529
530 // qspi_flash_device.read: Use default hook.
531 qspi_flash_device.read_block = &spiflash_bdev_read_block;
532 // qspi_flash_device.write has a default hook that will be okay
533 qspi_flash_device.write_block = &spiflash_bdev_write_block;
534 qspi_flash_device.erase = &spiflash_bdev_erase;
535 qspi_flash_device.ioctl = &spiflash_ioctl;
536
537 /* we erase to 0xff */
538 qspi_flash_device.erase_byte = 0xff;
539
540 bio_register_device(&qspi_flash_device);
541
542err:
543 mutex_release(&spiflash_mutex);
544 return result;
545}
546
547status_t hal_error_to_status(HAL_StatusTypeDef hal_status)
548{
549 switch (hal_status) {
550 case HAL_OK:
551 return NO_ERROR;
552 case HAL_ERROR:
553 return ERR_GENERIC;
554 case HAL_BUSY:
555 return ERR_BUSY;
556 case HAL_TIMEOUT:
557 return ERR_TIMED_OUT;
558 default:
559 return ERR_GENERIC;
560 }
561}
562
563static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction)
564{
565 if (instruction == BULK_ERASE_CMD && block_addr != 0) {
566 // This call was probably not what the user intended since the
567 // block_addr is irrelevant when performing a bulk erase.
568 return ERR_INVALID_ARGS;
569 }
570
571 QSPI_CommandTypeDef erase_cmd;
572
573 ssize_t num_erased_bytes;
574 switch (instruction) {
575 case SUBSECTOR_ERASE_CMD: {
576 num_erased_bytes = N25QXXA_SUBSECTOR_SIZE;
577 erase_cmd.AddressSize = get_address_size(block_addr);
578 erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr);
579 erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
580 erase_cmd.Address = block_addr;
581
582 break;
583 }
584 case SECTOR_ERASE_CMD: {
585 num_erased_bytes = N25QXXA_SECTOR_SIZE;
586 erase_cmd.AddressSize = get_address_size(block_addr);
587 erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr);
588 erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
589 erase_cmd.Address = block_addr;
590
591 break;
592 }
593 case BULK_ERASE_CMD: {
594 num_erased_bytes = device->total_size;
595 erase_cmd.AddressMode = QSPI_ADDRESS_NONE;
596 erase_cmd.Instruction = instruction;
597 break;
598 }
599 default: {
600 // Instruction must be a valid erase instruction.
601 return ERR_INVALID_ARGS;
602 }
603 }
604
605 erase_cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
606 erase_cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
607 erase_cmd.DataMode = QSPI_DATA_NONE;
608 erase_cmd.DummyCycles = 0;
609 erase_cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
610 erase_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
611 erase_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
612
613
614 /* Enable write operations */
615 status_t qspi_write_enable_result = qspi_write_enable_unsafe(&qspi_handle);
616 if (qspi_write_enable_result != NO_ERROR) {
617 return qspi_write_enable_result;
618 }
619
620 /* Send the command */
621 if (qspi_cmd(&qspi_handle, &erase_cmd) != HAL_OK) {
622 return ERR_GENERIC;
623 }
624
625 /* Configure automatic polling mode to wait for end of erase */
626 status_t auto_polling_mem_ready_result =
627 qspi_auto_polling_mem_ready_unsafe(&qspi_handle);
628 if (auto_polling_mem_ready_result != NO_ERROR) {
629 return auto_polling_mem_ready_result;
630 }
631
632 return num_erased_bytes;
633}
634
635static ssize_t qspi_bulk_erase(bdev_t *device)
636{
637 return qspi_erase(device, 0, BULK_ERASE_CMD);
638}
639
640static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr)
641{
642 return qspi_erase(device, block_addr, SECTOR_ERASE_CMD);
643}
644
645static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr)
646{
647 return qspi_erase(device, block_addr, SUBSECTOR_ERASE_CMD);
648}
649
650static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef* qspi_handle,
651 QSPI_CommandTypeDef* s_command)
652{
653 HAL_StatusTypeDef result = HAL_QSPI_Command_IT(qspi_handle, s_command);
654 event_wait(&cmd_event);
655 return result;
656}
657
658// Send data and wait for interrupt.
659static HAL_StatusTypeDef qspi_tx_dma(QSPI_HandleTypeDef* qspi_handle, QSPI_CommandTypeDef* s_command, uint8_t* buf)
660{
661 // Make sure cache is flushed to RAM before invoking the DMA controller.
662 arch_clean_cache_range((addr_t)buf, s_command->NbData);
663
664 HAL_StatusTypeDef result = HAL_QSPI_Transmit_DMA(qspi_handle, buf);
665 event_wait(&tx_event);
666
667 return result;
668}
669
670// Send data and wait for interrupt.
671static HAL_StatusTypeDef qspi_rx_dma(QSPI_HandleTypeDef* qspi_handle, QSPI_CommandTypeDef* s_command, uint8_t* buf)
672{
673 // Make sure the front and back of the buffer are cache aligned.
674 DEBUG_ASSERT(IS_ALIGNED((uintptr_t)buf, CACHE_LINE));
675 DEBUG_ASSERT(IS_ALIGNED(((uintptr_t)buf) + s_command->NbData, CACHE_LINE));
676
677 arch_invalidate_cache_range((addr_t)buf, s_command->NbData);
678
679 HAL_StatusTypeDef result = HAL_QSPI_Receive_DMA(qspi_handle, buf);
680 event_wait(&rx_event);
681
682 return result;
683}
684
685void stm32_QUADSPI_IRQ(void)
686{
687 arm_cm_irq_entry();
688 HAL_QSPI_IRQHandler(&qspi_handle);
689 arm_cm_irq_exit(true);
690}
691
692void stm32_DMA2_Stream7_IRQ(void)
693{
694 arm_cm_irq_entry();
695 HAL_DMA_IRQHandler(&hdma);
696 arm_cm_irq_exit(true);
697}
698
699/* IRQ Context */
700void HAL_QSPI_CmdCpltCallback(QSPI_HandleTypeDef *hqspi)
701{
702 event_signal(&cmd_event, false);
703}
704
705/* IRQ Context */
706void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi)
707{
708 event_signal(&rx_event, false);
709}
710
711/* IRQ Context */
712void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi)
713{
714 event_signal(&tx_event, false);
715}
716
717status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi)
718{
719 /* QSPI DMA Controller Clock */
720 __HAL_RCC_DMA2_CLK_ENABLE();
721
722 hdma.Init.Channel = DMA_CHANNEL_3;
723 hdma.Init.PeriphInc = DMA_PINC_DISABLE;
724 hdma.Init.MemInc = DMA_MINC_ENABLE;
725 hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
726 hdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
727 hdma.Init.Mode = DMA_NORMAL;
728 hdma.Init.Priority = DMA_PRIORITY_LOW;
729 hdma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
730 hdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
731 hdma.Init.MemBurst = DMA_MBURST_SINGLE;
732 hdma.Init.PeriphBurst = DMA_PBURST_SINGLE;
733 hdma.Instance = DMA2_Stream7;
734
735 __HAL_LINKDMA(hqspi, hdma, hdma);
736 HAL_StatusTypeDef hal_result = HAL_DMA_Init(&hdma);
737 if (hal_result != HAL_OK) {
738 return hal_error_to_status(hal_result);
739 }
740
741 HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
742
743 return NO_ERROR;
744}
745
746static uint32_t get_address_size(uint32_t address)
747{
748 if (address >= FOUR_BYTE_ADDR_THRESHOLD) {
749 return QSPI_ADDRESS_32_BITS;
750 }
751 return QSPI_ADDRESS_24_BITS;
752}
753
754// Converts a 3 byte instruction into a 4 byte instruction if necessary.
755static uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address)
756{
757 if (address < FOUR_BYTE_ADDR_THRESHOLD) {
758 return instruction;
759 }
760
761 switch (instruction) {
762 case READ_CMD:
763 return READ_4_BYTE_ADDR_CMD;
764 case FAST_READ_CMD:
765 return FAST_READ_4_BYTE_ADDR_CMD;
766 case DUAL_OUT_FAST_READ_CMD:
767 return DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD;
768 case DUAL_INOUT_FAST_READ_CMD:
769 return DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD;
770 case QUAD_OUT_FAST_READ_CMD:
771 return QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD;
772 case QUAD_INOUT_FAST_READ_CMD:
773 return QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD;
774 case PAGE_PROG_CMD:
775 return PAGE_PROG_4_BYTE_ADDR_CMD;
776 case QUAD_IN_FAST_PROG_CMD:
777 return QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD;
778 case SUBSECTOR_ERASE_CMD:
779 return SUBSECTOR_ERASE_4_BYTE_ADDR_CMD;
780 case SECTOR_ERASE_CMD:
781 return SECTOR_ERASE_4_BYTE_ADDR_CMD;
782 }
783
784 return instruction;
785}
786
787status_t qspi_enable_linear(void)
788{
789 status_t result = NO_ERROR;
790
791 mutex_acquire(&spiflash_mutex);
792
793 result = qspi_dummy_cycles_cfg_unsafe(&qspi_handle);
794
795 QSPI_CommandTypeDef s_command = {
796 .InstructionMode = QSPI_INSTRUCTION_1_LINE,
797 .AddressSize = QSPI_ADDRESS_24_BITS,
798 .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
799 .DdrMode = QSPI_DDR_MODE_DISABLE,
800 .DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY,
801 .AddressMode = QSPI_ADDRESS_1_LINE,
802 .Instruction = QUAD_OUT_FAST_READ_CMD,
803 .DataMode = QSPI_DATA_4_LINES,
804 .DummyCycles = 10,
805 .SIOOMode = QSPI_SIOO_INST_EVERY_CMD
806 };
807
808 QSPI_MemoryMappedTypeDef linear_mode_cfg = {
809 .TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE,
810 };
811
812 HAL_StatusTypeDef hal_result = HAL_QSPI_MemoryMapped(&qspi_handle, &s_command, &linear_mode_cfg);
813 if (hal_result != HAL_OK) {
814 result = hal_error_to_status(hal_result);
815 goto err;
816 }
817
818err:
819 mutex_release(&spiflash_mutex);
820 return result;
821}