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