1 /*
2 * Copyright (c) 2017-2019, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * ======== NVSSPI25X.c ========
35 */
36
37 #include <stdint.h>
38 #include <stddef.h>
39 #include <stdbool.h>
40 #include <string.h>
41 #include <stdlib.h>
42
43 #include <ti/drivers/dpl/HwiP.h>
44 #include <ti/drivers/dpl/SemaphoreP.h>
45 #include <ti/drivers/dpl/ClockP.h>
46
47 #include <ti/drivers/NVS.h>
48 #include <ti/drivers/nvs/NVSSPI25X.h>
49
50 #include <ti/drivers/SPI.h>
51 #include <ti/drivers/GPIO.h>
52
53 /* Instruction codes */
54 #define SPIFLASH_WRITE 0x02 /**< Page Program */
55 #define SPIFLASH_READ 0x03 /**< Read Data */
56 #define SPIFLASH_READ_STATUS 0x05 /**< Read Status Register */
57 #define SPIFLASH_WRITE_ENABLE 0x06 /**< Write Enable */
58 #define SPIFLASH_SUBSECTOR_ERASE 0x20 /**< SubSector (4K Byte) Erase */
59 #define SPIFLASH_SECTOR_ERASE 0xD8 /**< Sector (64K Byte) Erase */
60 #define SPIFLASH_MASS_ERASE 0xC7 /**< Erase entire flash */
61
62 #define SPIFLASH_RDP 0xAB /**< Release from Deep Power Down */
63 #define SPIFLASH_DP 0xB9 /**< Deep Power Down */
64
65 /* Bitmasks of the status register */
66 #define SPIFLASH_STATUS_BIT_BUSY 0x01 /**< Busy bit of status register */
67
68 /* Write page size assumed by this driver */
69 #define SPIFLASH_PROGRAM_PAGE_SIZE 256
70
71 /* Highest supported SPI instance index */
72 #define MAX_SPI_INDEX 3
73
74 /* Size of hardware sector erased by SPIFLASH_SECTOR_ERASE */
75 #define SPIFLASH_SECTOR_SIZE 0x10000
76
77 static int_fast16_t checkEraseRange(NVS_Handle handle, size_t offset, size_t size);
78 static int_fast16_t doErase(NVS_Handle handle, size_t offset, size_t size);
79 static int_fast16_t doRead(NVS_Handle handle, size_t offset, void *buffer,
80 size_t bufferSize);
81 static int_fast16_t doWriteVerify(NVS_Handle handle, size_t offset,
82 void *src, size_t srcBufSize, void *dst,
83 size_t dstBufSize, bool preFlag);
84
85 static int_fast16_t extFlashSpiWrite(const uint8_t *buf, size_t len);
86 static int_fast16_t extFlashSpiRead(uint8_t *buf, size_t len);
87 static int_fast16_t extFlashPowerDown(NVS_Handle nvsHandle);
88 static int_fast16_t extFlashPowerStandby(NVS_Handle nvsHandle);
89 static int_fast16_t extFlashWaitReady(NVS_Handle nvsHandle);
90 static int_fast16_t extFlashWriteEnable(NVS_Handle nvsHandle);
91 static int_fast16_t extFlashMassErase(NVS_Handle nvsHandle);
92
93 extern NVS_Config NVS_config[];
94 extern const uint8_t NVS_count;
95
96 /* NVS function table for NVSSPI25X implementation */
97 const NVS_FxnTable NVSSPI25X_fxnTable = {
98 NVSSPI25X_close,
99 NVSSPI25X_control,
100 NVSSPI25X_erase,
101 NVSSPI25X_getAttrs,
102 NVSSPI25X_init,
103 NVSSPI25X_lock,
104 NVSSPI25X_open,
105 NVSSPI25X_read,
106 NVSSPI25X_unlock,
107 NVSSPI25X_write
108 };
109
110 /* Manage SPI indexes */
111 static SPI_Handle spiHandles[MAX_SPI_INDEX + 1];
112 static uint8_t spiHandleUsers[MAX_SPI_INDEX + 1];
113
114 /*
115 * Currently active (protected within Semaphore_pend() block)
116 * SPI handle, and CSN pin
117 */
118 static SPI_Handle spiHandle;
119 static uint32_t spiCsnGpioIndex;
120
121 /*
122 * Semaphore to synchronize access to flash region.
123 */
124 static SemaphoreP_Handle writeSem;
125
126 /*
127 * ======== NVSSPI25X_close ========
128 */
NVSSPI25X_close(NVS_Handle handle)129 void NVSSPI25X_close(NVS_Handle handle)
130 {
131 NVSSPI25X_HWAttrs const *hwAttrs;
132 NVSSPI25X_Object *object;
133
134 SemaphoreP_pend(writeSem, SemaphoreP_WAIT_FOREVER);
135
136 hwAttrs = handle->hwAttrs;
137 object = handle->object;
138
139 spiHandle = object->spiHandle;
140 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
141
142 /* Close the SPI if we opened it */
143 if (hwAttrs->spiHandle == NULL) {
144 spiHandleUsers[hwAttrs->spiIndex] -= 1;
145
146 /* Close SPI if this is the last region that uses it */
147 if (spiHandleUsers[hwAttrs->spiIndex] == 0) {
148 /* Ensure part is responsive */
149 extFlashWaitReady(handle);
150
151 /* Put the part in low power mode */
152 extFlashPowerDown(handle);
153
154 SPI_close(object->spiHandle);
155 spiHandles[hwAttrs->spiIndex] = NULL;
156 }
157 }
158
159 NVSSPI25X_deinitSpiCs(handle, spiCsnGpioIndex);
160
161 object->opened = false;
162
163 SemaphoreP_post(writeSem);
164 }
165
166 /*
167 * ======== NVSSPI25X_control ========
168 */
NVSSPI25X_control(NVS_Handle handle,uint_fast16_t cmd,uintptr_t arg)169 int_fast16_t NVSSPI25X_control(NVS_Handle handle, uint_fast16_t cmd, uintptr_t arg)
170 {
171 NVSSPI25X_HWAttrs const *hwAttrs;
172 NVSSPI25X_Object *object;
173
174 if (cmd != NVSSPI25X_CMD_MASS_ERASE) return (NVS_STATUS_UNDEFINEDCMD);
175
176 hwAttrs = handle->hwAttrs;
177 object = handle->object;
178
179 /* Set protected global variables */
180 spiHandle = object->spiHandle;
181 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
182
183 return (extFlashMassErase(handle));
184 }
185
186 /*
187 * ======== NVSSPI25X_erase ========
188 */
NVSSPI25X_erase(NVS_Handle handle,size_t offset,size_t size)189 int_fast16_t NVSSPI25X_erase(NVS_Handle handle, size_t offset, size_t size)
190 {
191 int_fast16_t status;
192
193 SemaphoreP_pend(writeSem, SemaphoreP_WAIT_FOREVER);
194
195 status = doErase(handle, offset, size);
196
197 SemaphoreP_post(writeSem);
198
199 return (status);
200 }
201
202 /*
203 * ======== NVSSPI25X_getAttrs ========
204 */
NVSSPI25X_getAttrs(NVS_Handle handle,NVS_Attrs * attrs)205 void NVSSPI25X_getAttrs(NVS_Handle handle, NVS_Attrs *attrs)
206 {
207 NVSSPI25X_HWAttrs const *hwAttrs;
208
209 hwAttrs = handle->hwAttrs;
210
211 /* FlashSectorSizeGet() returns the size of a flash sector in bytes. */
212 attrs->regionBase = NVS_REGION_NOT_ADDRESSABLE;
213 attrs->regionSize = hwAttrs->regionSize;
214 attrs->sectorSize = hwAttrs->sectorSize;
215 }
216
217 /*
218 * ======== NVSSPI25X_init ========
219 */
NVSSPI25X_init()220 void NVSSPI25X_init()
221 {
222 unsigned int key;
223 SemaphoreP_Handle tempSem;
224
225 SPI_init();
226
227 /* Speculatively create semaphore so critical section is faster */
228 tempSem = SemaphoreP_createBinary(1);
229 /* tempSem == NULL will be detected in 'open' */
230
231 key = HwiP_disable();
232
233 if (writeSem == NULL) {
234 /* First time init, assign handle */
235 writeSem = tempSem;
236
237 HwiP_restore(key);
238 }
239 else {
240 /* Init already called */
241 HwiP_restore(key);
242
243 /* Delete unused Semaphores */
244 if (tempSem) {
245 SemaphoreP_delete(tempSem);
246 }
247 }
248 }
249
250 /*
251 * ======== NVSSPI25X_lock =======
252 */
NVSSPI25X_lock(NVS_Handle handle,uint32_t timeout)253 int_fast16_t NVSSPI25X_lock(NVS_Handle handle, uint32_t timeout)
254 {
255 if (SemaphoreP_pend(writeSem, timeout) != SemaphoreP_OK) {
256 return (NVS_STATUS_TIMEOUT);
257 }
258 return (NVS_STATUS_SUCCESS);
259 }
260
261 /*
262 * ======== NVSSPI25X_open =======
263 */
NVSSPI25X_open(uint_least8_t index,NVS_Params * params)264 NVS_Handle NVSSPI25X_open(uint_least8_t index, NVS_Params *params)
265 {
266 NVSSPI25X_Object *object;
267 NVSSPI25X_HWAttrs const *hwAttrs;
268 size_t sectorSize;
269 NVS_Handle handle;
270 SPI_Params spiParams;
271
272 /* Confirm that 'init' has successfully completed */
273 if (writeSem == NULL) {
274 NVSSPI25X_init();
275 if (writeSem == NULL) {
276 return (NULL);
277 }
278 }
279
280 /* Verify NVS region index */
281 if (index >= NVS_count) {
282 return (NULL);
283 }
284
285 SemaphoreP_pend(writeSem, SemaphoreP_WAIT_FOREVER);
286
287 handle = &NVS_config[index];
288 object = NVS_config[index].object;
289 hwAttrs = NVS_config[index].hwAttrs;
290
291 if (object->opened == true) {
292 SemaphoreP_post(writeSem);
293 return (NULL);
294 }
295
296 sectorSize = hwAttrs->sectorSize;
297 object->sectorBaseMask = ~(sectorSize - 1);
298
299 /* The regionBase must be aligned on a flash page boundary */
300 if ((hwAttrs->regionBaseOffset) & (sectorSize - 1)) {
301 SemaphoreP_post(writeSem);
302 return (NULL);
303 }
304
305 /* The region cannot be smaller than a sector size */
306 if (hwAttrs->regionSize < sectorSize) {
307 SemaphoreP_post(writeSem);
308 return (NULL);
309 }
310
311 /* The region size must be a multiple of sector size */
312 if (hwAttrs->regionSize != (hwAttrs->regionSize & object->sectorBaseMask)) {
313 SemaphoreP_post(writeSem);
314 return (NULL);
315 }
316
317 if (hwAttrs->spiHandle) {
318 /* Use the provided SPI Handle */
319 object->spiHandle = *hwAttrs->spiHandle;
320 }
321 else {
322 if (hwAttrs->spiIndex > MAX_SPI_INDEX) {
323 SemaphoreP_post(writeSem);
324 return (NULL);
325 }
326 /* Open SPI if this driver hasn't already opened this SPI instance */
327 if (spiHandles[hwAttrs->spiIndex] == NULL) {
328 SPI_Handle spi;
329
330 SPI_Params_init(&spiParams);
331 spiParams.bitRate = hwAttrs->spiBitRate;
332 spiParams.mode = SPI_MASTER;
333 spiParams.transferMode = SPI_MODE_BLOCKING;
334
335 /* Attempt to open SPI. */
336 spi = SPI_open(hwAttrs->spiIndex, &spiParams);
337
338 if (spi == NULL) {
339 SemaphoreP_post(writeSem);
340 return (NULL);
341 }
342
343 spiHandles[hwAttrs->spiIndex] = spi;
344 }
345 object->spiHandle = spiHandles[hwAttrs->spiIndex];
346 /* Keep track of how many regions use the same SPI handle */
347 spiHandleUsers[hwAttrs->spiIndex] += 1;
348 }
349
350 /* Set protected global variables */
351 spiHandle = object->spiHandle;
352 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
353
354
355 /* Initialize chip select output */
356 NVSSPI25X_initSpiCs(handle, spiCsnGpioIndex);
357
358 object->opened = true;
359
360 /* Put the part in standby mode */
361 extFlashPowerStandby(handle);
362
363 SemaphoreP_post(writeSem);
364
365 return (handle);
366 }
367
368 /*
369 * ======== NVSSPI25X_read =======
370 */
NVSSPI25X_read(NVS_Handle handle,size_t offset,void * buffer,size_t bufferSize)371 int_fast16_t NVSSPI25X_read(NVS_Handle handle, size_t offset, void *buffer,
372 size_t bufferSize)
373 {
374 NVSSPI25X_HWAttrs const *hwAttrs;
375 int retval = NVS_STATUS_SUCCESS;
376
377 hwAttrs = handle->hwAttrs;
378
379 /* Validate offset and bufferSize */
380 if (offset + bufferSize > hwAttrs->regionSize) {
381 return (NVS_STATUS_INV_OFFSET);
382 }
383
384 /*
385 * Get exclusive access to the region. We don't want someone
386 * else to erase the region while we are reading it.
387 */
388 SemaphoreP_pend(writeSem, SemaphoreP_WAIT_FOREVER);
389
390 retval = doRead(handle, offset, buffer, bufferSize);
391
392 SemaphoreP_post(writeSem);
393
394 return (retval);
395 }
396
397 /*
398 * ======== NVSSPI25X_unlock =======
399 */
NVSSPI25X_unlock(NVS_Handle handle)400 void NVSSPI25X_unlock(NVS_Handle handle)
401 {
402 SemaphoreP_post(writeSem);
403 }
404
405 /*
406 * ======== NVSSPI25X_write =======
407 */
NVSSPI25X_write(NVS_Handle handle,size_t offset,void * buffer,size_t bufferSize,uint_fast16_t flags)408 int_fast16_t NVSSPI25X_write(NVS_Handle handle, size_t offset, void *buffer,
409 size_t bufferSize, uint_fast16_t flags)
410 {
411 NVSSPI25X_Object *object;
412 NVSSPI25X_HWAttrs const *hwAttrs;
413 size_t length, foffset;
414 uint32_t status = true;
415 uint8_t *srcBuf;
416 int retval = NVS_STATUS_SUCCESS;
417 uint8_t wbuf[4];
418
419 hwAttrs = handle->hwAttrs;
420 object = handle->object;
421
422 /* Validate offset and bufferSize */
423 if (offset + bufferSize > hwAttrs->regionSize) {
424 return (NVS_STATUS_INV_OFFSET);
425 }
426
427 /* Get exclusive access to the Flash region */
428 SemaphoreP_pend(writeSem, SemaphoreP_WAIT_FOREVER);
429
430 /* Set protected global variables */
431 spiHandle = object->spiHandle;
432 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
433
434 /* If erase is set, erase destination sector(s) first */
435 if (flags & NVS_WRITE_ERASE) {
436 length = bufferSize & object->sectorBaseMask;
437 if (bufferSize & (~object->sectorBaseMask)) {
438 length += hwAttrs->sectorSize;
439 }
440
441 retval = doErase(handle, offset & object->sectorBaseMask, length);
442 if (retval != NVS_STATUS_SUCCESS) {
443 SemaphoreP_post(writeSem);
444 return (retval);
445 }
446 }
447 else if (flags & NVS_WRITE_PRE_VERIFY) {
448 if ((hwAttrs->verifyBuf == NULL) || (hwAttrs->verifyBufSize == 0)) {
449 SemaphoreP_post(writeSem);
450 return (NVS_STATUS_ERROR);
451 }
452
453 retval = doWriteVerify(handle, offset, buffer, bufferSize,
454 hwAttrs->verifyBuf, hwAttrs->verifyBufSize, true);
455
456 if (retval != NVS_STATUS_SUCCESS) {
457 SemaphoreP_post(writeSem);
458 return (retval);
459 }
460 }
461
462 srcBuf = buffer;
463 length = bufferSize;
464 foffset = (size_t)hwAttrs->regionBaseOffset + offset;
465
466 while (length > 0)
467 {
468 size_t ilen; /* Interim length per instruction */
469
470 /* Wait till previous erase/program operation completes */
471 int ret = extFlashWaitReady(handle);
472
473 if (ret) {
474 status = false;
475 break;
476 }
477
478 ret = extFlashWriteEnable(handle);
479
480 if (ret) {
481 status = false;
482 break;
483 }
484
485 ilen = SPIFLASH_PROGRAM_PAGE_SIZE - (foffset % SPIFLASH_PROGRAM_PAGE_SIZE);
486 if (length < ilen) {
487 ilen = length;
488 }
489
490 wbuf[0] = SPIFLASH_WRITE;
491 wbuf[1] = (foffset >> 16) & 0xff;
492 wbuf[2] = (foffset >> 8) & 0xff;
493 wbuf[3] = foffset & 0xff;
494
495 foffset += ilen;
496 length -= ilen;
497
498 /*
499 * Up to 100ns CS hold time (which is not clear
500 * whether it's application only in between reads)
501 * is not imposed here since above instructions
502 * should be enough to delay
503 * as much.
504 */
505 NVSSPI25X_assertSpiCs(handle, spiCsnGpioIndex);
506
507 if (extFlashSpiWrite(wbuf, sizeof(wbuf)) != NVS_STATUS_SUCCESS) {
508 status = false;
509 break;
510 }
511
512 if (extFlashSpiWrite(srcBuf, ilen) != NVS_STATUS_SUCCESS) {
513 status = false;
514 break;
515 }
516
517 srcBuf += ilen;
518 NVSSPI25X_deassertSpiCs(handle, spiCsnGpioIndex);
519 }
520
521 if (status == false) {
522 retval = NVS_STATUS_ERROR;
523 }
524 else if (flags & NVS_WRITE_POST_VERIFY) {
525 if ((hwAttrs->verifyBuf == NULL) || (hwAttrs->verifyBufSize == 0)) {
526 SemaphoreP_post(writeSem);
527 return (NVS_STATUS_ERROR);
528 }
529
530 retval = doWriteVerify(handle, offset, buffer, bufferSize,
531 hwAttrs->verifyBuf, hwAttrs->verifyBufSize, false);
532 }
533
534 SemaphoreP_post(writeSem);
535
536 return (retval);
537 }
538
539 /*
540 * ======== doWriteVerify =======
541 */
doWriteVerify(NVS_Handle handle,size_t offset,void * src,size_t srcBufSize,void * dst,size_t dstBufSize,bool preFlag)542 static int_fast16_t doWriteVerify(NVS_Handle handle, size_t offset, void *src,
543 size_t srcBufSize, void *dst, size_t dstBufSize, bool preFlag)
544 {
545 size_t i, j;
546 uint8_t *srcBuf, *dstBuf;
547 bool bad;
548 int_fast16_t retval;
549
550 srcBuf = src;
551 dstBuf = dst;
552
553 j = dstBufSize;
554
555 for (i = 0; i < srcBufSize; i++, j++) {
556 if (j == dstBufSize) {
557 retval = doRead(handle, offset + i, dstBuf, j);
558 if (retval != NVS_STATUS_SUCCESS) {
559 break;
560 }
561 j = 0;
562 }
563 if (preFlag) {
564 bad = srcBuf[i] != (srcBuf[i] & dstBuf[j]);
565 }
566 else {
567 bad = srcBuf[i] != dstBuf[j];
568 }
569 if (bad) return (NVS_STATUS_INV_WRITE);
570 }
571 return (NVS_STATUS_SUCCESS);
572 }
573
574 /*
575 * ======== checkEraseRange ========
576 */
checkEraseRange(NVS_Handle handle,size_t offset,size_t size)577 static int_fast16_t checkEraseRange(NVS_Handle handle, size_t offset, size_t size)
578 {
579 NVSSPI25X_Object *object;
580 NVSSPI25X_HWAttrs const *hwAttrs;
581
582 object = handle->object;
583 hwAttrs = handle->hwAttrs;
584
585 if (offset != (offset & object->sectorBaseMask)) {
586 return (NVS_STATUS_INV_ALIGNMENT); /* Poorly aligned start address */
587 }
588
589 if (offset >= hwAttrs->regionSize) {
590 return (NVS_STATUS_INV_OFFSET); /* Offset is past end of region */
591 }
592
593 if (offset + size > hwAttrs->regionSize) {
594 return (NVS_STATUS_INV_SIZE); /* Size is too big */
595 }
596
597 if (size != (size & object->sectorBaseMask)) {
598 return (NVS_STATUS_INV_SIZE); /* Size is not a multiple of sector size */
599 }
600
601 return (NVS_STATUS_SUCCESS);
602 }
603
604 /*
605 * ======== doErase ========
606 */
doErase(NVS_Handle handle,size_t offset,size_t size)607 static int_fast16_t doErase(NVS_Handle handle, size_t offset, size_t size)
608 {
609 NVSSPI25X_HWAttrs const *hwAttrs;
610 NVSSPI25X_Object *object;
611 uint32_t sectorBase;
612 size_t eraseSize;
613 int_fast16_t rangeStatus;
614 uint8_t wbuf[4];
615
616 /* Sanity test the erase args */
617 rangeStatus = checkEraseRange(handle, offset, size);
618
619 if (rangeStatus != NVS_STATUS_SUCCESS) {
620 return (rangeStatus);
621 }
622
623 hwAttrs = handle->hwAttrs;
624 object = handle->object;
625
626 /* Set protected global variables */
627 spiHandle = object->spiHandle;
628 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
629
630 /* Start erase at this address */
631 sectorBase = (uint32_t)hwAttrs->regionBaseOffset + offset;
632
633 while (size) {
634 /* Wait till previous erase/program operation completes */
635 int ret = extFlashWaitReady(handle);
636 if (ret) {
637 return (NVS_STATUS_ERROR);
638 }
639
640 ret = extFlashWriteEnable(handle);
641 if (ret) {
642 return (NVS_STATUS_ERROR);
643 }
644
645
646 /* Determine which erase command to use */
647 if (size >= SPIFLASH_SECTOR_SIZE &&
648 ((sectorBase & (SPIFLASH_SECTOR_SIZE - 1)) == 0)){
649 /* Erase size is one sector (64kB) */
650 eraseSize = SPIFLASH_SECTOR_SIZE;
651 wbuf[0] = SPIFLASH_SECTOR_ERASE;
652 }
653 else{
654 /* Erase size is one sub-sector (4kB)*/
655 eraseSize = hwAttrs->sectorSize;
656 wbuf[0] = SPIFLASH_SUBSECTOR_ERASE;
657 }
658
659
660 /* Format command to send over SPI */
661 wbuf[1] = (sectorBase >> 16) & 0xff;
662 wbuf[2] = (sectorBase >> 8) & 0xff;
663 wbuf[3] = sectorBase & 0xff;
664
665 /* Send erase command to external flash */
666 NVSSPI25X_assertSpiCs(handle, spiCsnGpioIndex);
667 if (extFlashSpiWrite(wbuf, sizeof(wbuf))) {
668 NVSSPI25X_deassertSpiCs(handle, spiCsnGpioIndex);
669 return (NVS_STATUS_ERROR);
670 }
671 NVSSPI25X_deassertSpiCs(handle, spiCsnGpioIndex);
672
673 sectorBase += eraseSize;
674 size -= eraseSize;
675 }
676
677 return (NVS_STATUS_SUCCESS);
678 }
679
680 /*
681 * ======== doRead =======
682 */
doRead(NVS_Handle handle,size_t offset,void * buffer,size_t bufferSize)683 static int_fast16_t doRead(NVS_Handle handle, size_t offset, void *buffer,
684 size_t bufferSize)
685 {
686 NVSSPI25X_Object *object;
687 NVSSPI25X_HWAttrs const *hwAttrs;
688 size_t loffset;
689 uint8_t wbuf[4];
690 int retval = NVS_STATUS_SUCCESS;
691
692 hwAttrs = handle->hwAttrs;
693 object = handle->object;
694
695 /* Set protected global variables */
696 spiHandle = object->spiHandle;
697 spiCsnGpioIndex = hwAttrs->spiCsnGpioIndex;
698
699 loffset = offset + hwAttrs->regionBaseOffset;
700
701 /* Wait till previous erase/program operation completes */
702 retval = extFlashWaitReady(handle);
703 if (retval) {
704 return (retval);
705 }
706
707 /*
708 * SPI is driven with very low frequency (1MHz < 33MHz fR spec)
709 * in this temporary implementation.
710 * and hence it is not necessary to use fast read.
711 */
712 wbuf[0] = SPIFLASH_READ;
713 wbuf[1] = (loffset >> 16) & 0xff;
714 wbuf[2] = (loffset >> 8) & 0xff;
715 wbuf[3] = loffset & 0xff;
716
717 NVSSPI25X_assertSpiCs(handle, spiCsnGpioIndex);
718
719 if (extFlashSpiWrite(wbuf, sizeof(wbuf))) {
720 NVSSPI25X_deassertSpiCs(handle, spiCsnGpioIndex);
721 return (NVS_STATUS_ERROR);
722 }
723
724 retval = extFlashSpiRead(buffer, bufferSize);
725
726 NVSSPI25X_deassertSpiCs(handle, spiCsnGpioIndex);
727
728 return (retval);
729 }
730
731 /*
732 * ======== extFlashPowerDown =======
733 * Issue power down command
734 */
extFlashPowerDown(NVS_Handle nvsHandle)735 static int_fast16_t extFlashPowerDown(NVS_Handle nvsHandle)
736 {
737 uint8_t cmd;
738 int_fast16_t status;
739
740 cmd = SPIFLASH_DP;
741 NVSSPI25X_assertSpiCs(nvsHandle, spiCsnGpioIndex);
742 status = extFlashSpiWrite(&cmd,sizeof(cmd));
743 NVSSPI25X_deassertSpiCs(nvsHandle, spiCsnGpioIndex);
744
745 return (status);
746 }
747
748 /*
749 * ======== extFlashPowerStandby =======
750 * Issue standby command
751 */
extFlashPowerStandby(NVS_Handle nvsHandle)752 static int_fast16_t extFlashPowerStandby(NVS_Handle nvsHandle)
753 {
754 uint8_t cmd;
755 int_fast16_t status;
756
757 cmd = SPIFLASH_RDP;
758 NVSSPI25X_assertSpiCs(nvsHandle, spiCsnGpioIndex);
759 status = extFlashSpiWrite(&cmd, sizeof(cmd));
760 NVSSPI25X_deassertSpiCs(nvsHandle, spiCsnGpioIndex);
761
762 if (status == NVS_STATUS_SUCCESS) {
763 status = extFlashWaitReady(nvsHandle);
764 }
765
766 return (status);
767 }
768
769 /*
770 * ======== extFlashMassErase =======
771 * Issue mass erase command
772 */
extFlashMassErase(NVS_Handle nvsHandle)773 static int_fast16_t extFlashMassErase(NVS_Handle nvsHandle)
774 {
775 uint8_t cmd;
776 int_fast16_t status;
777
778 /* Wait for previous operation to complete */
779 if (extFlashWaitReady(nvsHandle)) {
780 return (NVS_STATUS_ERROR);
781 }
782
783 cmd = SPIFLASH_MASS_ERASE;
784 NVSSPI25X_assertSpiCs(nvsHandle, spiCsnGpioIndex);
785 status = extFlashSpiWrite(&cmd,sizeof(cmd));
786 NVSSPI25X_deassertSpiCs(nvsHandle, spiCsnGpioIndex);
787
788 if (status != NVS_STATUS_SUCCESS) {
789 return (status);
790 }
791
792 /* Wait for mass erase to complete */
793 return (extFlashWaitReady(nvsHandle));
794 }
795
796 /*
797 * ======== extFlashWaitReady =======
798 * Wait for any previous job to complete.
799 */
extFlashWaitReady(NVS_Handle nvsHandle)800 static int_fast16_t extFlashWaitReady(NVS_Handle nvsHandle)
801 {
802 const uint8_t wbuf[1] = { SPIFLASH_READ_STATUS };
803 int_fast16_t ret;
804 uint8_t buf;
805
806 NVSSPI25X_HWAttrs const *hwAttrs;
807 hwAttrs = nvsHandle->hwAttrs;
808
809 for (;;) {
810 NVSSPI25X_assertSpiCs(nvsHandle, spiCsnGpioIndex);
811 extFlashSpiWrite(wbuf, sizeof(wbuf));
812 ret = extFlashSpiRead(&buf,sizeof(buf));
813 NVSSPI25X_deassertSpiCs(nvsHandle, spiCsnGpioIndex);
814
815 if (ret != NVS_STATUS_SUCCESS) {
816 /* Error */
817 return (ret);
818 }
819 if (!(buf & SPIFLASH_STATUS_BIT_BUSY)) {
820 /* Now ready */
821 break;
822 }
823 if (hwAttrs->statusPollDelayUs){
824 /* Sleep to avoid excessive polling and starvation */
825 ClockP_usleep(hwAttrs->statusPollDelayUs);
826 }
827 }
828
829 return (NVS_STATUS_SUCCESS);
830 }
831
832 /*
833 * ======== extFlashWriteEnable =======
834 * Issue SPIFLASH_WRITE_ENABLE command
835 */
extFlashWriteEnable(NVS_Handle nvsHandle)836 static int_fast16_t extFlashWriteEnable(NVS_Handle nvsHandle)
837 {
838 const uint8_t wbuf[] = { SPIFLASH_WRITE_ENABLE };
839 int_fast16_t ret;
840
841 NVSSPI25X_assertSpiCs(nvsHandle, spiCsnGpioIndex);
842 ret = extFlashSpiWrite(wbuf,sizeof(wbuf));
843 NVSSPI25X_deassertSpiCs(nvsHandle, spiCsnGpioIndex);
844
845 return (ret);
846 }
847
848 /*
849 * ======== extFlashSpiWrite =======
850 */
extFlashSpiWrite(const uint8_t * buf,size_t len)851 static int_fast16_t extFlashSpiWrite(const uint8_t *buf, size_t len)
852 {
853 SPI_Transaction masterTransaction;
854
855 masterTransaction.rxBuf = NULL;
856
857 /*
858 * Work around SPI transfer from address 0x0
859 * transfer first byte from local buffer
860 */
861 if (buf == NULL) {
862 uint8_t byte0;
863 byte0 = *buf++;
864 masterTransaction.count = 1;
865 masterTransaction.txBuf = (void*)&byte0;
866 if (!SPI_transfer(spiHandle, &masterTransaction)) {
867 return (NVS_STATUS_ERROR);
868 }
869 len = len - 1;
870 if (len == 0) {
871 return (NVS_STATUS_SUCCESS);
872 }
873 }
874
875 masterTransaction.count = len;
876 masterTransaction.txBuf = (void*)buf;
877
878 return (SPI_transfer(spiHandle, &masterTransaction) ? NVS_STATUS_SUCCESS : NVS_STATUS_ERROR);
879 }
880
881
882 /*
883 * ======== extFlashSpiRead =======
884 */
extFlashSpiRead(uint8_t * buf,size_t len)885 static int_fast16_t extFlashSpiRead(uint8_t *buf, size_t len)
886 {
887 SPI_Transaction masterTransaction;
888
889 masterTransaction.txBuf = NULL;
890 masterTransaction.count = len;
891 masterTransaction.rxBuf = buf;
892
893 return (SPI_transfer(spiHandle, &masterTransaction) ? NVS_STATUS_SUCCESS : NVS_STATUS_ERROR);
894 }
895
896 /*
897 * Below are the default (weak) GPIO-driver based implementations of:
898 * NVSSPI25X_initSpiCs()
899 * NVSSPI25X_deinitSpiCs()
900 * NVSSPI25X_assertSpiCs()
901 * NVSSPI25X_deassertSpiCs()
902 */
903
904 /*
905 * ======== NVSSPI25X_initSpiCs =======
906 */
NVSSPI25X_initSpiCs(NVS_Handle nvsHandle,uint16_t csId)907 void __attribute__((weak)) NVSSPI25X_initSpiCs(NVS_Handle nvsHandle, uint16_t csId)
908 {
909 if (csId != NVSSPI25X_SPI_MANAGES_CS) {
910 GPIO_init();
911
912 /*
913 * Make SPI Chip Select GPIO an output, and set it high.
914 * Since the same device may be used for multiple regions, configuring
915 * the same Chip Select pin may be done multiple times. No harm done.
916 */
917 GPIO_setConfig(csId, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH);
918 }
919 }
920
921 /*
922 * ======== NVSSPI25X_deinitSpiCs =======
923 */
NVSSPI25X_deinitSpiCs(NVS_Handle nvsHandle,uint16_t csId)924 void __attribute__((weak)) NVSSPI25X_deinitSpiCs(NVS_Handle nvsHandle, uint16_t csId)
925 {
926 }
927
928 /*
929 * ======== NVSSPI25X_assertSpiCs =======
930 * Assert SPI flash /CS
931 */
NVSSPI25X_assertSpiCs(NVS_Handle nvsHandle,uint16_t csId)932 void __attribute__((weak)) NVSSPI25X_assertSpiCs(NVS_Handle nvsHandle, uint16_t csId)
933 {
934 if (csId != NVSSPI25X_SPI_MANAGES_CS) {
935 GPIO_write(csId, 0);
936 }
937 }
938
939 /*
940 * ======== NVSSPI25X_deassertSpiCs =======
941 * De-assert SPI flash /CS
942 */
NVSSPI25X_deassertSpiCs(NVS_Handle nvsHandle,uint16_t csId)943 void __attribute__((weak)) NVSSPI25X_deassertSpiCs(NVS_Handle nvsHandle, uint16_t csId)
944 {
945 if (csId != NVSSPI25X_SPI_MANAGES_CS) {
946 GPIO_write(csId, 1);
947 }
948 }
949