1 /*
2  * Copyright 2018, 2020 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 /*! *********************************************************************************
10 *************************************************************************************
11 * Include
12 *************************************************************************************
13 ********************************************************************************** */
14 #include "fsl_common.h"
15 #include "fsl_adapter_spi.h"
16 #include "fsl_adapter_gpio.h"
17 #include "fsl_adapter_eeprom.h"
18 /*! *********************************************************************************
19 *************************************************************************************
20 * Private macros
21 *************************************************************************************
22 ********************************************************************************** */
23 #if (!defined(GCOV_DO_COVERAGE) || (GCOV_DO_COVERAGE == 0))
24 #define EEPROM_STATIC static
25 #define EEPROM_PUBLIC
26 #else
27 #define EEPROM_STATIC __WEAK
28 #define EEPROM_PUBLIC __WEAK
29 #endif
30 
31 #define EEPROM_RDSR    0xD7U
32 #define EEPROM_READ    0x03U
33 #define EEPROM_READ_HF 0x0BU
34 
35 #define EEPROM_ERASE_256B 0x81U
36 #define EEPROM_ERASE_2K   0x50U
37 
38 #define EEPROM_WRITE_BYTES 0x02U
39 
40 #define EEPROM_BUSY_FLAG_MASK 0x80U
41 #define EEPROM_PAGE_SIZE      (256U)
42 #define EEPROM_BLOCK_SIZE     (8U * EEPROM_PAGE_SIZE)
43 #define EEPROM_PAGE_MASK      (EEPROM_PAGE_SIZE - 1U)
44 
45 /* adress mask */
46 #define ADDRESS_MASK 0x000000FFUL
47 /******************************************************************************
48 *******************************************************************************
49 * Private Prototypes
50 *******************************************************************************
51 ******************************************************************************/
52 typedef struct _eeprom_state
53 {
54     uint8_t eepromEraseBitmap[32];
55     GPIO_HANDLE_DEFINE(gpioHandle);          /*!< gpio handle*/
56     HAL_SPI_MASTER_HANDLE_DEFINE(spiHandle); /*!< spi handle*/
57     eeprom_type_t eeType;                    /*!< eeprom type*/
58 } eeprom_state_t;
59 
60 EEPROM_STATIC eeprom_state_t s_eeState;
61 /*! *********************************************************************************
62 *************************************************************************************
63 * Private Memory Declarations
64 *************************************************************************************
65 ********************************************************************************** */
66 
67 /*! *********************************************************************************
68 *************************************************************************************
69 * Private Memory function
70 *************************************************************************************
71 ********************************************************************************** */
EEPROM_AssertCsGpio(void)72 EEPROM_STATIC void EEPROM_AssertCsGpio(void)
73 {
74     (void)HAL_GpioSetOutput(s_eeState.gpioHandle, 0);
75 }
76 
EEPROM_DeassertCsGpio(void)77 EEPROM_STATIC void EEPROM_DeassertCsGpio(void)
78 {
79     (void)HAL_GpioSetOutput(s_eeState.gpioHandle, 1);
80 }
81 
EEPROM_SetSpiTransferValue(hal_spi_transfer_t * transferValue,uint8_t * txData,uint8_t * rxData,size_t dataSize)82 EEPROM_STATIC void EEPROM_SetSpiTransferValue(hal_spi_transfer_t *transferValue,
83                                               uint8_t *txData,
84                                               uint8_t *rxData,
85                                               size_t dataSize)
86 {
87     transferValue->txData   = txData;
88     transferValue->rxData   = rxData;
89     transferValue->dataSize = dataSize;
90 }
91 
EEPROM_ReadStatusReq(void)92 EEPROM_STATIC uint16_t EEPROM_ReadStatusReq(void)
93 {
94     const uint8_t cmd = EEPROM_RDSR;
95     hal_spi_transfer_t xfer;
96     uint8_t data[2] = {0U, 0U};
97 
98     EEPROM_AssertCsGpio();
99 
100     EEPROM_SetSpiTransferValue(&xfer, (uint8_t *)(uint32_t)cmd, NULL, sizeof(cmd));
101     (void)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
102 
103     EEPROM_SetSpiTransferValue(&xfer, NULL, data, 2);
104     (void)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
105 
106     EEPROM_DeassertCsGpio();
107 
108     return *((uint16_t *)((void *)data));
109 }
EEPROM_isBusy(void)110 EEPROM_STATIC uint8_t EEPROM_isBusy(void)
111 {
112     return ((EEPROM_ReadStatusReq() & EEPROM_BUSY_FLAG_MASK) == 0U) ? 1U : 0U;
113 }
EEPROM_WaitForReady(bool isInfinite)114 EEPROM_STATIC eeprom_status_t EEPROM_WaitForReady(bool isInfinite)
115 {
116     volatile uint16_t wait = 0x400; /* near 50 ms @ 50 us/cycle */
117 
118     /* Byte1 - Bit:   7       6      5:2       1         0
119      *             RDY/BUSY  COMP  DENSITY  PROTECT  PAGE_SIZE
120      *
121      * Byte2 - Bit:   7       6    5    4    3    2    1    0
122      *             RDY/BUSY  RES  EPE  RES  SLE  PS2  PS1  ES
123      */
124     while ((bool)EEPROM_isBusy())
125     {
126         if (!isInfinite)
127         {
128             if (0U != wait)
129             {
130                 wait--;
131             }
132             else
133             {
134                 break;
135             }
136         }
137     }
138 
139     if (0U != wait)
140     {
141         return kStatus_EeSuccess;
142     }
143     return kStatus_EeError;
144 }
145 
EEPROM_PrepareForWrite(uint32_t noOfBytes,uint32_t addre)146 EEPROM_STATIC eeprom_status_t EEPROM_PrepareForWrite(uint32_t noOfBytes, uint32_t addre)
147 {
148     uint32_t i;
149     eeprom_status_t ret = kStatus_EeSuccess;
150     uint32_t startBlk, endBlk;
151     /* Obtain the block number */
152     startBlk = addre / EEPROM_BLOCK_SIZE;
153     endBlk   = (addre + noOfBytes) / EEPROM_BLOCK_SIZE;
154 
155     if (0U != ((addre + noOfBytes) % EEPROM_BLOCK_SIZE))
156     {
157         endBlk++;
158     }
159 
160     for (i = startBlk; i <= endBlk; i++)
161     {
162         if (0U == (s_eeState.eepromEraseBitmap[i >> 3U] & (1U << (i & 7U))))
163         {
164             (void)EEPROM_EraseBlock(i * EEPROM_BLOCK_SIZE, EEPROM_BLOCK_SIZE);
165 
166             s_eeState.eepromEraseBitmap[i >> 3U] |= (1U << (i & 7U));
167             (void)EEPROM_WaitForReady(true);
168         }
169     }
170     return ret;
171 }
172 
EEPROM_Command(uint8_t opCode,uint32_t addre)173 EEPROM_STATIC eeprom_status_t EEPROM_Command(uint8_t opCode, uint32_t addre)
174 {
175     uint8_t cmd[4];
176     hal_spi_transfer_t xfer;
177 
178     cmd[0] = opCode;
179     cmd[1] = (uint8_t)((addre >> 16) & ADDRESS_MASK);
180     cmd[2] = (uint8_t)((addre >> 8) & ADDRESS_MASK);
181     cmd[3] = (uint8_t)((addre >> 0) & ADDRESS_MASK);
182 
183     EEPROM_AssertCsGpio();
184     EEPROM_SetSpiTransferValue(&xfer, (uint8_t *)cmd, NULL, sizeof(cmd));
185     return (eeprom_status_t)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
186 }
EEPROM_WritePage(uint32_t noOfBytes,uint32_t addre,uint8_t * Outbuf)187 EEPROM_STATIC eeprom_status_t EEPROM_WritePage(uint32_t noOfBytes, uint32_t addre, uint8_t *Outbuf)
188 {
189     hal_spi_transfer_t xfer;
190     if (0U == noOfBytes)
191     {
192         return kStatus_EeSuccess;
193     }
194 
195     while (0U != EEPROM_isBusy())
196     {
197     }
198 
199     /*CS will remain ASSERTED */
200     if (kStatus_EeSuccess != EEPROM_Command(EEPROM_WRITE_BYTES, addre))
201     {
202         EEPROM_DeassertCsGpio();
203         return kStatus_EeError;
204     }
205     EEPROM_SetSpiTransferValue(&xfer, Outbuf, NULL, noOfBytes);
206     if (kStatus_HAL_SpiSuccess != HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer))
207     {
208         EEPROM_DeassertCsGpio();
209         return kStatus_EeError;
210     }
211 
212     EEPROM_DeassertCsGpio();
213 
214     return kStatus_EeSuccess;
215 }
216 /*!*********************************************************************************
217 *************************************************************************************
218 * Public Functions
219 *************************************************************************************
220 ********************************************************************************** */
221 
EEPROM_Init(eeprom_config_t * eepromConfig)222 eeprom_status_t EEPROM_Init(eeprom_config_t *eepromConfig)
223 {
224     static uint8_t initialized = 0U;
225     eeprom_status_t retval;
226     hal_spi_transfer_t xfer;
227     hal_gpio_pin_config_t controlPin;
228 
229     uint8_t cmd[] = {0x3D, 0x2A, 0x80, 0xA6};
230 
231     hal_spi_master_config_t spiMasterConfig = {
232         .srcClock_Hz  = eepromConfig->spiSrcClock_Hz,
233         .baudRate_Bps = 500000U,
234         .enableMaster = true,
235         .polarity     = kHAL_SpiClockPolarityActiveHigh,
236         .phase        = kHAL_SpiClockPhaseFirstEdge,
237         .direction    = kHAL_SpiMsbFirst,
238     };
239 
240     uint32_t i;
241 
242     /* Mark Flash as Unerased */
243     for (i = 0; i < sizeof(s_eeState.eepromEraseBitmap) / sizeof(s_eeState.eepromEraseBitmap[0]); i++)
244     {
245         s_eeState.eepromEraseBitmap[i] = 0;
246     }
247 
248     if (0U == initialized)
249     {
250         s_eeState.eeType = eepromConfig->eeType;
251 
252         (void)HAL_SpiMasterInit((hal_spi_master_handle_t)s_eeState.spiHandle, (void *)&spiMasterConfig);
253         controlPin.port      = eepromConfig->csGpioPort;
254         controlPin.pin       = eepromConfig->csGpiopin;
255         controlPin.direction = kHAL_GpioDirectionOut;
256         controlPin.level     = 0U;
257         (void)HAL_GpioInit((hal_gpio_handle_t)s_eeState.gpioHandle, &controlPin);
258 
259         retval = EEPROM_WaitForReady(false);
260         if (kStatus_EeSuccess != retval)
261         {
262             return retval;
263         }
264         /* Set page size to 256bits: */
265         EEPROM_AssertCsGpio();
266         EEPROM_SetSpiTransferValue(&xfer, (uint8_t *)cmd, NULL, sizeof(cmd));
267         (void)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
268         EEPROM_DeassertCsGpio();
269         initialized = 1;
270     }
271 
272     return kStatus_EeSuccess;
273 }
274 
275 /*****************************************************************************
276  *  EEPROM_ChipErase
277  *
278  *  Erase all memory to 0xFF
279  *
280  *****************************************************************************/
EEPROM_ChipErase(void)281 eeprom_status_t EEPROM_ChipErase(void)
282 {
283     uint8_t cmd[] = {0xC7, 0x94, 0x80, 0x9A};
284     hal_spi_transfer_t xfer;
285     (void)EEPROM_WaitForReady(true);
286 
287     EEPROM_AssertCsGpio();
288     EEPROM_SetSpiTransferValue(&xfer, (uint8_t *)cmd, NULL, sizeof(cmd));
289     (void)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
290     EEPROM_DeassertCsGpio();
291 
292     return kStatus_EeSuccess;
293 }
294 
295 /*****************************************************************************
296  *  EEPROM_EraseBlock
297  *
298  *  Erase a block of memory to 0xFF
299  *
300  *****************************************************************************/
EEPROM_EraseBlock(uint32_t addr2eeprom,uint32_t size)301 eeprom_status_t EEPROM_EraseBlock(uint32_t addr2eeprom, uint32_t size)
302 {
303     uint8_t cmd[4];
304     hal_spi_transfer_t xfer;
305     eeprom_status_t status = kStatus_EeSuccess;
306     (void)EEPROM_WaitForReady(true);
307 
308     switch (size)
309     {
310         case EEPROM_BLOCK_SIZE:
311             cmd[0] = EEPROM_ERASE_2K;
312             break;
313         case EEPROM_PAGE_SIZE:
314             cmd[0] = EEPROM_ERASE_256B;
315             break;
316         default:
317             status = kStatus_EeError;
318             break;
319     }
320 
321     cmd[1] = (uint8_t)((addr2eeprom >> 16) & ADDRESS_MASK);
322     cmd[2] = (uint8_t)((addr2eeprom >> 8) & ADDRESS_MASK);
323     cmd[3] = (uint8_t)((addr2eeprom >> 0) & ADDRESS_MASK);
324 
325     EEPROM_AssertCsGpio();
326     EEPROM_SetSpiTransferValue(&xfer, (uint8_t *)cmd, NULL, sizeof(cmd));
327     (void)HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer);
328     EEPROM_DeassertCsGpio();
329 
330     return status;
331 }
332 
333 /*****************************************************************************
334  *  EEPROM_WriteData
335  *
336  *  Writes a data buffer into EEPROM, at a given address
337  *
338  *****************************************************************************/
EEPROM_WriteData(uint32_t noOfBytes,uint32_t addr2eeprom,uint8_t * Outbuf)339 eeprom_status_t EEPROM_WriteData(uint32_t noOfBytes, uint32_t addr2eeprom, uint8_t *Outbuf)
340 {
341     eeprom_status_t retval;
342     if (0U == noOfBytes)
343     {
344         return kStatus_EeSuccess;
345     }
346 
347     (void)EEPROM_WaitForReady(true);
348 
349     (void)EEPROM_PrepareForWrite(noOfBytes, addr2eeprom);
350 
351     (void)EEPROM_WaitForReady(true);
352 
353     while ((addr2eeprom & EEPROM_PAGE_MASK) + noOfBytes > EEPROM_PAGE_MASK)
354     {
355         uint32_t bytes = EEPROM_PAGE_SIZE - (addr2eeprom & EEPROM_PAGE_MASK);
356 
357         retval = EEPROM_WritePage(bytes, addr2eeprom, Outbuf);
358         noOfBytes -= bytes;
359         addr2eeprom += bytes;
360 
361         for (uint32_t j = 0; j < bytes; j++)
362         {
363             Outbuf++; /*Outbuf += bytes;*/
364         }
365 
366         if (kStatus_EeSuccess != retval)
367         {
368             return retval;
369         }
370     }
371     retval = EEPROM_WritePage(noOfBytes, addr2eeprom, Outbuf);
372 
373     return retval;
374 }
375 
376 /*****************************************************************************
377  *  EEPROM_ReadData
378  *
379  *  Reads a data buffer from EEPROM, from a given address
380  *
381  *****************************************************************************/
EEPROM_ReadData(uint16_t noOfBytes,uint32_t addr2eeprom,uint8_t * inbuf)382 eeprom_status_t EEPROM_ReadData(uint16_t noOfBytes, uint32_t addr2eeprom, uint8_t *inbuf)
383 {
384     hal_spi_transfer_t xfer;
385     (void)EEPROM_WaitForReady(true);
386 
387     if (kStatus_EeSuccess != EEPROM_Command(EEPROM_READ, addr2eeprom))
388     {
389         EEPROM_DeassertCsGpio();
390         return kStatus_EeError;
391     }
392     EEPROM_SetSpiTransferValue(&xfer, NULL, inbuf, noOfBytes);
393     if (kStatus_HAL_SpiSuccess != HAL_SpiMasterTransferBlocking(s_eeState.spiHandle, &xfer))
394     {
395         EEPROM_DeassertCsGpio();
396         return kStatus_EeError;
397     }
398     EEPROM_DeassertCsGpio();
399 
400     return kStatus_EeSuccess;
401 }
402 
403 #if (defined(GET_EEPROM_SIZE) && (GET_EEPROM_SIZE > 0))
EEPROM_GetProperty(eeprom_property_tag_t property,uint32_t * value)404 eeprom_status_t EEPROM_GetProperty(eeprom_property_tag_t property, uint32_t *value)
405 {
406     eeprom_status_t status = kStatus_EeSuccess;
407     if (NULL == value)
408     {
409         return kStatus_EeInvalidArgument;
410     }
411 
412     if (property == kEEPROM_PropertyTotalSize)
413     {
414         if (s_eeState.eeType == kEEPROM_DeviceAT45DB161E)
415         {
416             *value = 0x00200000U; /* 2 MBytes */
417         }
418         else if (s_eeState.eeType == kEEPROM_DeviceAT26DF081A)
419         {
420             *value = 0x00100000U; /* 1 MBytes */
421         }
422         else if (s_eeState.eeType == kEEPROM_DeviceAT45DB021E)
423         {
424             *value = 0x00040000U; /* 256 KBytes */
425         }
426         else if (s_eeState.eeType == kEEPROM_DeviceAT45DB041E)
427         {
428             *value = 0x00080000U; /* 512 KBytes */
429         }
430         else
431         {
432             /*MISRA rule 15.7*/
433         }
434     }
435     else if (property == kEEPROM_PropertySectorSize)
436     {
437         if (s_eeState.eeType == kEEPROM_DeviceAT45DB161E)
438         {
439             *value = (4 * 1024); /* 4 KBytes */
440         }
441         else if (s_eeState.eeType == kEEPROM_DeviceAT26DF081A)
442         {
443             *value = (4 * 1024); /* 4 KBytes */
444         }
445         else if (s_eeState.eeType == kEEPROM_DeviceAT45DB021E)
446         {
447             *value = (2 * 1024); /* 2 KBytes */
448         }
449         else if (s_eeState.eeType == kEEPROM_DeviceAT45DB041E)
450         {
451             *value = (2 * 1024); /* 2 KBytes */
452         }
453         else
454         {
455             /*MISRA rule 15.7*/
456         }
457     }
458     else /* catch inputs that are not recognized */
459     {
460         status = kStatus_EeInvalidArgument;
461     }
462 
463     return status;
464 }
465 #endif
466