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