]> rtime.felk.cvut.cz Git - arc.git/blob - drivers/Fls_SST25xx.c
Merge branch 'mikulka' of git@rtime.felk.cvut.cz:arc into mikulka
[arc.git] / drivers / Fls_SST25xx.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 \r
17 \r
18 \r
19 \r
20 \r
21 \r
22 \r
23 #if 1\r
24 \r
25 \r
26 /* CONFIGURATION NOTES\r
27  *   The configuration is simple, use the template supplied.\r
28  *   Changing the configuration is NOT recommended.\r
29  */\r
30 \r
31 /* REQUIREMENTS:\r
32  * - Variant PB is supported not PC ( FLS203,FLS204 )\r
33  * - Since DEM is NOT supported all those requirements are not supported.\r
34  * - AC is not supported since it makes no sense for a SPI flash.\r
35  *\r
36  */\r
37 \r
38 /* IMPLEMENTATION NOTES\r
39  * - The only SPI flash supported is the SST25VF016B although the\r
40  *   entire SST25XX should work through configuration changes\r
41  * - Commands that are used by this module are:\r
42  *   WREN,WRDI,WRSR,byte write and erase 4K\r
43  * - AC is not supported since the there's no use for it.\r
44  * - Supports 64 bytes read, byte write and 4K erase\r
45  * - The implementation very much dependent on the configuration\r
46  *   of the SPI( Spi_Cfg.c )\r
47  * - Calls from SPI are not checked( Only makes sense if DEM is supported )\r
48  *\r
49  */\r
50 \r
51 \r
52 \r
53 #include "Fls.h"\r
54 #include "Fls_SST25xx.h"\r
55 #include "Spi.h"\r
56 #include "Det.h"\r
57 #if defined(USE_DEM)\r
58 #include "Dem.h"\r
59 #endif\r
60 #include <stdlib.h>\r
61 #include <assert.h>\r
62 //#include <stdio.h>\r
63 #include <string.h>\r
64 \r
65 //#define USE_LDEBUG_PRINTF\r
66 #include "debug.h"\r
67 #define MODULE_NAME     "/driver/Fls_25"\r
68 \r
69 \r
70 /* The width in bytes used by this flash */\r
71 #define ADDR_LENGTH             3\r
72 \r
73 /* Helper macro for the process function */\r
74 #define SET_STATE(_done,_state) done=(_done);job->state=(_state)\r
75 \r
76 /* How many loops to wait for SPI to go back to "normal" state after\r
77  * read/write/erase */\r
78  #define TIMER_BUSY_WAIT  100000\r
79 \r
80 #if FLS_SST25XX_DEV_ERROR_DETECT\r
81 #define FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(_addr, _api, _rv)\\r
82   int sectorIndex;\\r
83   int addrOk=0;\\r
84   Fls_SectorType sector;\\r
85   for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {\\r
86     sector = Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];\\r
87     if((((uint32)_addr-sector.FlsSectorStartaddress) / sector.FlsSectorSize)<sector.FlsNumberOfSectors){\\r
88       /* Within the right adress space */\\r
89       if (!(((uint32)_addr-sector.FlsSectorStartaddress) % sector.FlsSectorSize)){\\r
90         /* Address is correctly aligned */\\r
91         addrOk=1;\\r
92         break;\\r
93       }\\r
94     }\\r
95   }\\r
96   if (1!=addrOk){\\r
97   Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_ADDRESS ); \\r
98   return _rv; \\r
99   }\r
100 \r
101 #define FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(_addr, _api, _rv)\\r
102   int sectorIndex;\\r
103   int addrOk=0;\\r
104   Fls_SectorType sector;\\r
105   for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {\\r
106     sector = Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];\\r
107     if((((uint32)_addr-sector.FlsSectorStartaddress) / sector.FlsSectorSize)<sector.FlsNumberOfSectors){\\r
108       /* Within the right adress space */\\r
109       if (!(((uint32)_addr-sector.FlsSectorStartaddress) % sector.FlsPageSize)){\\r
110         /* Address is correctly aligned */\\r
111         addrOk=1;\\r
112         break;\\r
113       }\\r
114     }\\r
115   }\\r
116   if (1!=addrOk){\\r
117   Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_ADDRESS ); \\r
118   return _rv; \\r
119   }\r
120 \r
121 #define FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(_addr, _length, _api, _rv)\\r
122   int i;\\r
123   int lengthOk=0;\\r
124   const Fls_SectorType* sectorPtr= &Fls_SST25xx_Global.config->FlsSectorList[0];\\r
125   for (i=0; i<Fls_SST25xx_Global.config->FlsSectorListSize;i++) {\\r
126     if ((sectorPtr->FlsSectorStartaddress + (sectorPtr->FlsNumberOfSectors * sectorPtr->FlsSectorSize))>=(uint32_t)(_addr+(_length))){\\r
127       if ((0!=_length)&&!(_length % sectorPtr->FlsPageSize)){\\r
128         lengthOk=1;\\r
129         break;\\r
130       }\\r
131     }\\r
132     sectorPtr++;\\r
133   }\\r
134   if (!lengthOk){\\r
135     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_LENGTH ); \\r
136     return _rv; \\r
137   }\r
138 \r
139 #define FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(_addr, _length, _api, _rv)\\r
140   int i;\\r
141   int lengthOk=0;\\r
142   const Fls_SectorType* sectorPtr= &Fls_SST25xx_Global.config->FlsSectorList[0];\\r
143   for (i=0; i<Fls_SST25xx_Global.config->FlsSectorListSize;i++) {\\r
144     if ((sectorPtr->FlsSectorStartaddress + (sectorPtr->FlsNumberOfSectors * sectorPtr->FlsSectorSize))>=(uint32_t)(_addr+(_length))){\\r
145       if ((0!=_length)&& !(_length % sectorPtr->FlsSectorSize)){\\r
146         lengthOk=1;\\r
147         break;\\r
148       }\\r
149     }\\r
150     sectorPtr++;\\r
151   }\\r
152   if (!lengthOk){\\r
153     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_LENGTH ); \\r
154     return _rv; \\r
155   }\r
156 \r
157 #define FLS_VALIDATE_STATUS_UNINIT_W_RV(_status, _api, _rv)\\r
158   if (MEMIF_UNINIT == _status){\\r
159     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_UNINIT); \\r
160     return _rv; \\r
161   }\r
162 \r
163 #define FLS_VALIDATE_STATUS_BUSY(_status, _api)\\r
164   if (MEMIF_BUSY == _status){\\r
165     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_BUSY); \\r
166     return; \\r
167   }\r
168 \r
169 #define FLS_VALIDATE_STATUS_BUSY_W_RV(_status, _api, _rv)\\r
170   if (MEMIF_BUSY == _status){\\r
171     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_BUSY); \\r
172     return _rv; \\r
173   }\r
174 \r
175 #define FLS_VALIDATE_PARAM_DATA_W_RV(_ptr,_api, _rv) \\r
176   if( (_ptr)==((void *)0)) { \\r
177     Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_DATA); \\r
178     return _rv; \\r
179   }\r
180 #else\r
181   #define FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(_addr, _api, _rv)\r
182   #define FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(_addr, _api, _rv)\r
183   #define FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(_addr, _length, _api, _rv)\r
184   #define FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(_addr, _length, _api, _rv)\r
185   #define FLS_VALIDATE_STATUS_UNINIT_W_RV(_status, _api, _rv)\r
186   #define FLS_VALIDATE_STATUS_BUSY(_status, _api)\r
187   #define FLS_VALIDATE_STATUS_BUSY_W_RV(_status, _api, _rv)\r
188   #define FLS_VALIDATE_PARAM_DATA_W_RV(_ptr,_api,_rv)\r
189 #endif\r
190 \r
191 #if ( FLS_DEV_ERROR_DETECT == STD_ON )\r
192 #define VALIDATE_CONFIG(_x) assert(_x)\r
193 #define DET_REPORTERROR(_x,_y,_z,_q) Det_ReportError(MODULE_ID_FLS, _y, _z, _q)\r
194 #else\r
195 #define VALIDATE_CONFIG(_x)\r
196 #define DET_REPORTERROR(_x,_y,_z,_q)\r
197 #endif\r
198 \r
199 #if ( FLS_GET_JOB_RESULT_API == STD_ON )\r
200 #define FEE_JOB_END_NOTIFICATION() \\r
201   if( Fls_SST25xx_Global.config->FlsJobEndNotification != NULL ) { \\r
202     Fls_SST25xx_Global.config->FlsJobEndNotification(); \\r
203   }\r
204 #define FEE_JOB_ERROR_NOTIFICATION() \\r
205   if( Fls_SST25xx_Global.config->FlsJobErrorNotification != NULL ) { \\r
206     Fls_SST25xx_Global.config->FlsJobErrorNotification(); \\r
207   }\r
208 #else\r
209 #define FEE_JOB_END_NOTIFICATION()\r
210 #define FEE_JOB_ERROR_NOTIFICATION()\r
211 #endif\r
212 \r
213 \r
214 \r
215 #if ( FLS_SST25XX_DEV_ERROR_DETECT == STD_ON ) // Report DEV errors\r
216 #define VALIDATE(_exp,_api,_err ) \\r
217         if( !(_exp) ) { \\r
218           Det_ReportError(MODULE_ID_FLS,0,_api,_err); \\r
219           return; \\r
220         }\r
221 #endif\r
222 \r
223 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \\r
224         if( !(_exp) ) { \\r
225           Det_ReportError(MODULE_ID_FLS,0,_api,_err); \\r
226           return (_rv); \\r
227         }\r
228 \r
229 #define VALID_CHANNEL(_ch)    ( Gpt_Global.configured & (1<<(_ch)) )\r
230 \r
231 #else // Validate but do not report\r
232 #define VALIDATE(_exp,_api,_err )\\r
233         if( !(_exp) ) { \\r
234           return; \\r
235         }\r
236 #define VALIDATE_W_RV(_exp,_api,_err,_rv )\\r
237         if( !(_exp) ) { \\r
238           return (_rv); \\r
239         }\r
240 #endif\r
241 \r
242 const Fls_ConfigType* _Fls_SST25xx_ConfigPtr;\r
243 \r
244 #if ( FLS_SST25XX_VERSION_INFO_API == STD_ON )\r
245 static Std_VersionInfoType Fls_SST25XX_VersionInfo = {\r
246     .vendorID                   = (uint16)1,\r
247     .moduleID                   = (uint16) MODULE_ID_FLS,\r
248     .instanceID                 = (uint8)1,\r
249     /* Vendor numbers */\r
250     .sw_major_version   = (uint8)FLS_SST25XX_SW_MAJOR_VERSION,\r
251     .sw_minor_version   = (uint8)FLS_SST25XX_SW_MINOR_VERSION,\r
252     .sw_patch_version   = (uint8)FLS_SST25XX_SW_PATCH_VERSION,\r
253     .ar_major_version   = (uint8)FLS_SST25XX_AR_MAJOR_VERSION,\r
254     .ar_minor_version   = (uint8)FLS_SST25XX_AR_MINOR_VERSION,\r
255     .ar_patch_version   = (uint8)FLS_SST25XX_AR_PATCH_VERSION,\r
256 };\r
257 #endif\r
258 \r
259 /* Job state */\r
260 typedef enum {\r
261   FLS_SST25XX_NONE,\r
262   FLS_SST25XX_COMPARE,\r
263   FLS_SST25XX_ERASE,\r
264   FLS_SST25XX_READ,\r
265   FLS_SST25XX_WRITE,\r
266 } Fls_SST25xx_Arc_JobType;\r
267 \r
268 /* Spi job state */\r
269 typedef enum {\r
270         JOB_MAIN,\r
271         JOB_READ_STATUS,\r
272         JOB_READ_STATUS_RESULT,\r
273 } Job_StateType;\r
274 \r
275 /* Information about a job */\r
276 typedef struct {\r
277         uint8 *targetAddr;\r
278         Fls_AddressType flsAddr;\r
279         uint32 left;\r
280         Job_StateType state;\r
281         Fls_SST25xx_Arc_JobType mainState;\r
282         Spi_SequenceType currSeq;\r
283         uint32 chunkSize;\r
284 } Fls_SST25xx_JobInfoType;\r
285 \r
286 #define JOB_SET_STATE(_x,_y)            job->state=(_x);job->mainState=(_y)\r
287 \r
288 \r
289 typedef struct {\r
290   const Fls_ConfigType *config;\r
291 \r
292   // Status of driver\r
293   MemIf_StatusType status;\r
294   MemIf_JobResultType jobResultType;\r
295   Fls_SST25xx_Arc_JobType jobType;\r
296 \r
297   // Saved information from API calls.\r
298   Fls_AddressType flsAddr;\r
299   uint8 *targetAddr;\r
300   Fls_LengthType length;\r
301 \r
302   // Data containers for EB buffers\r
303   Spi_DataType ebCmd;\r
304   Spi_DataType ebReadStatus;\r
305   Spi_DataType ebFlsAddr[ADDR_LENGTH];\r
306 \r
307   // What mode we are in ( normal/fast )\r
308   MemIf_ModeType mode;\r
309 \r
310   // Hold job information\r
311   Fls_SST25xx_JobInfoType job;\r
312 \r
313 } Fls_SST25xx_GlobalType;\r
314 \r
315 Fls_SST25xx_GlobalType Fls_SST25xx_Global;\r
316 \r
317 #if 0\r
318 #define SPI_TRANSMIT_FUNC(_x)   Spi_SyncTransmit(_x)\r
319 #else\r
320 #define SPI_TRANSMIT_FUNC(_x,_y)        Fls_SST25xx_AsyncTransmit(_x,_y)\r
321 \r
322 Std_ReturnType Fls_SST25xx_AsyncTransmit(Spi_SequenceType Sequence,Fls_SST25xx_JobInfoType *job) {\r
323         Std_ReturnType rv;\r
324         job->currSeq = Sequence;\r
325         rv = Spi_AsyncTransmit(Sequence);\r
326         return rv;\r
327 }\r
328 #endif\r
329 \r
330 \r
331 /**\r
332  * Convert Fls_AddressType to something used by SPI\r
333  *\r
334  * @param spiAddr Address to convert to SPI address\r
335  * @param addr Pointer to the SPI address to be written\r
336  *\r
337  */\r
338 static void Spi_ConvertToSpiAddr(Spi_DataType *spiAddr, Fls_AddressType addr ) {\r
339 \r
340         spiAddr[0] = (addr>>16)&0xff;           // MSB first\r
341         spiAddr[1] = (addr>>8)&0xff;\r
342         spiAddr[2] = (addr)&0xff;\r
343 \r
344 }\r
345 \r
346 /**\r
347  * Get configuration sector information from a flash address\r
348  *\r
349  * @param addr The address\r
350  */\r
351 \r
352 static const Fls_SectorType * Fls_SST25xx_GetSector( Fls_AddressType addr ) {\r
353   int sectorIndex;\r
354   const Fls_SectorType *sector;\r
355 \r
356   for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {\r
357     sector = &Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];\r
358     if((((uint32)addr-sector->FlsSectorStartaddress) / sector->FlsSectorSize)<sector->FlsNumberOfSectors){\r
359       return sector;\r
360     }\r
361   }\r
362   assert(0);\r
363   return NULL;\r
364  }\r
365 \r
366 void Fls_SST25xx_Init( const Fls_ConfigType* ConfigPtr ){\r
367 \r
368         FLS_VALIDATE_STATUS_BUSY(Fls_SST25xx_Global.status, FLS_INIT_ID);\r
369 \r
370 #if ( FLS_SST25XX_VARIANT_PB == STD_ON )\r
371   VALIDATE( (ConfigPtr != NULL) , FLS_INIT_ID, FLS_E_PARAM_CONFIG );\r
372 #endif\r
373 \r
374   Fls_SST25xx_Global.config = ConfigPtr;\r
375   Spi_DataType data = 0;\r
376   int timer = 0;\r
377   Std_ReturnType rv = E_OK;\r
378   Spi_DataType jedecId[3];\r
379 \r
380 \r
381 \r
382   // Do some basic testing of configuration data, FLS205\r
383   VALIDATE_CONFIG(ConfigPtr->FlsMaxReadFastMode != 0 );\r
384   VALIDATE_CONFIG(ConfigPtr->FlsMaxReadNormalMode != 0 );\r
385   VALIDATE_CONFIG(ConfigPtr->FlsMaxWriteFastMode != 0 );\r
386   VALIDATE_CONFIG(ConfigPtr->FlsMaxWriteNormalMode != 0 );\r
387 \r
388   VALIDATE_CONFIG(ConfigPtr->FlsAcWrite == NULL );   // NOT supported\r
389   VALIDATE_CONFIG(ConfigPtr->FlsAcErase == NULL );   // NOT supported\r
390 \r
391   // Setup External buffers for jobs and sequences\r
392   Spi_SetupEB( SPI_CH_FLASH_CMD,  &Fls_SST25xx_Global.ebCmd,NULL,sizeof(Fls_SST25xx_Global.ebCmd)/sizeof(Fls_SST25xx_Global.ebCmd));\r
393   Spi_SetupEB( SPI_CH_FLASH_ADDR,  Fls_SST25xx_Global.ebFlsAddr,NULL,sizeof(Fls_SST25xx_Global.ebFlsAddr)/sizeof(Fls_SST25xx_Global.ebFlsAddr[0]));\r
394   Spi_SetupEB( SPI_CH_FLASH_WREN,  NULL,NULL,1);\r
395   Spi_SetupEB( SPI_CH_FLASH_WRDI,  NULL,NULL,1);\r
396   Spi_SetupEB( SPI_CH_FLASH_WRSR,  NULL,NULL,1);\r
397 \r
398   /* Check that the JEDEC ID can be read */\r
399   Spi_SetupEB( SPI_CH_FLASH_DATA, NULL ,jedecId,3);\r
400 \r
401   Fls_SST25xx_Global.ebCmd = FLASH_JEDEC_ID;\r
402   Spi_SyncTransmit(SPI_SEQ_FLASH_CMD_DATA );\r
403 \r
404   if( ((jedecId[0]<<16) + (jedecId[1]<<8) + jedecId[2]) != 0xbf2541 ) {\r
405    LDEBUG_PRINTF("JEDEC: %02x %02x %02x\n",jedecId[0],jedecId[1],jedecId[2]);\r
406     assert(0);\r
407   }\r
408 \r
409   /* The flash comes locked from factory so it must be unlocked.\r
410    * The unlock is done in here instead before each write to reduce overhead.\r
411    * ( The flash is still protected by WREN )\r
412    */\r
413 \r
414   /* Unlock flash with sync API. */\r
415   Spi_SetupEB( SPI_CH_FLASH_DATA, &data, NULL,1);\r
416   rv = Spi_SyncTransmit(SPI_SEQ_FLASH_WRSR);\r
417 \r
418         // Busy wait\r
419         Spi_SetupEB( SPI_CH_FLASH_DATA, NULL, &Fls_SST25xx_Global.ebReadStatus, 1);\r
420         do {\r
421                 Fls_SST25xx_Global.ebCmd = FLASH_RDSR;\r
422                 Spi_SyncTransmit(SPI_SEQ_FLASH_CMD2);\r
423                 timer++;\r
424         } while( (Fls_SST25xx_Global.ebReadStatus != 0) && (timer < TIMER_BUSY_WAIT ));\r
425 \r
426         assert(timer!=TIMER_BUSY_WAIT);\r
427 \r
428   Fls_SST25xx_Global.status     = MEMIF_IDLE;\r
429   Fls_SST25xx_Global.jobResultType  = MEMIF_JOB_PENDING;\r
430 \r
431   // Set currSeq to any sequence we use\r
432   Fls_SST25xx_Global.job.currSeq = SPI_SEQ_FLASH_WRSR;\r
433 \r
434 }\r
435 \r
436 #if ( FLS_SST25XX_SET_MODE_API == STD_ON )\r
437 void Fls_SST25xx_SetMode( MemIf_ModeType Mode ){\r
438   VALIDATE( ( Fls_SST25xx_Global.status != MEMIF_UNINIT ), FLS_SET_MODE_ID, FLS_E_UNINIT );\r
439   VALIDATE( ( Fls_SST25xx_Global.status != MEMIF_BUSY ), FLS_SET_MODE_ID, FLS_E_BUSY );\r
440 \r
441   Fls_SST25xx_Global.mode = Mode;\r
442 }\r
443 #endif\r
444 \r
445 Std_ReturnType Fls_SST25xx_Read ( Fls_AddressType SourceAddress,\r
446                            uint8 *TargetAddressPtr,\r
447                            Fls_LengthType Length )\r
448 {\r
449         Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;\r
450 \r
451   FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_READ_ID, E_NOT_OK);\r
452   FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_READ_ID, E_NOT_OK);\r
453   FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(SourceAddress, FLS_READ_ID, E_NOT_OK);\r
454   FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(SourceAddress, Length, FLS_READ_ID, E_NOT_OK);\r
455   FLS_VALIDATE_PARAM_DATA_W_RV((void*)TargetAddressPtr, FLS_READ_ID, E_NOT_OK)\r
456 \r
457   Fls_SST25xx_Global.status = MEMIF_BUSY;\r
458   Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;\r
459   Fls_SST25xx_Global.jobType = FLS_SST25XX_READ;\r
460 \r
461   if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {\r
462      job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadFastMode;\r
463   } else {\r
464      job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadNormalMode;\r
465   }\r
466 \r
467   job->flsAddr = SourceAddress;\r
468   job->targetAddr = TargetAddressPtr;\r
469   job->left = Length;\r
470 \r
471   JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_READ);\r
472 \r
473   return E_OK;\r
474 \r
475 }\r
476 \r
477 Std_ReturnType Fls_SST25xx_Erase( Fls_AddressType   TargetAddress, Fls_LengthType    Length ){\r
478         Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;\r
479 \r
480   FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_ERASE_ID, E_NOT_OK);\r
481   FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_ERASE_ID, E_NOT_OK);\r
482   FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(TargetAddress, FLS_ERASE_ID, E_NOT_OK);\r
483   FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(TargetAddress, Length, FLS_ERASE_ID, E_NOT_OK);\r
484 \r
485   Fls_SST25xx_Global.status = MEMIF_BUSY;\r
486   Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;\r
487   Fls_SST25xx_Global.jobType = FLS_SST25XX_ERASE;\r
488 \r
489   job->flsAddr = TargetAddress;\r
490   // Not used, so set to illegal value\r
491   job->targetAddr = (uint8 *)0;\r
492   job->left = Length;\r
493   job->chunkSize = Fls_SST25xx_GetSector(TargetAddress)->FlsSectorSize;\r
494 \r
495   JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_ERASE);\r
496 \r
497   return E_OK;\r
498 }\r
499 \r
500 Std_ReturnType Fls_SST25xx_Write( Fls_AddressType TargetAddress, const uint8* SourceAddressPtr, Fls_LengthType Length ){\r
501 \r
502         Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;\r
503 \r
504   FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_WRITE_ID, E_NOT_OK);\r
505   FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_WRITE_ID, E_NOT_OK);\r
506   FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(TargetAddress, FLS_WRITE_ID, E_NOT_OK);\r
507   FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(TargetAddress, Length, FLS_WRITE_ID, E_NOT_OK);\r
508   FLS_VALIDATE_PARAM_DATA_W_RV(SourceAddressPtr, FLS_WRITE_ID, E_NOT_OK)\r
509 \r
510         Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;\r
511         Fls_SST25xx_Global.status = MEMIF_BUSY;\r
512         Fls_SST25xx_Global.jobType = FLS_SST25XX_WRITE;\r
513 \r
514         if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {\r
515                 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxWriteFastMode;\r
516         } else {\r
517                 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxWriteNormalMode;\r
518         }\r
519 \r
520   job->flsAddr = TargetAddress;\r
521   job->targetAddr = (uint8 *)SourceAddressPtr;\r
522   job->left = Length;\r
523 \r
524   JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_WRITE);\r
525 \r
526   return E_OK;\r
527 }\r
528 \r
529 \r
530 Std_ReturnType Fls_SST25xx_Compare( Fls_AddressType SourceAddress, uint8 *TargetAddressPtr, Fls_LengthType Length )\r
531 {\r
532         Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;\r
533 \r
534   FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_COMPARE_ID, E_NOT_OK);\r
535   FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_COMPARE_ID, E_NOT_OK);\r
536   FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(SourceAddress, FLS_COMPARE_ID, E_NOT_OK);\r
537   FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(SourceAddress, Length, FLS_COMPARE_ID, E_NOT_OK);\r
538   FLS_VALIDATE_PARAM_DATA_W_RV((void*)SourceAddress,FLS_COMPARE_ID, E_NOT_OK)\r
539 \r
540   Fls_SST25xx_Global.status = MEMIF_BUSY;\r
541   Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;\r
542   Fls_SST25xx_Global.jobType = FLS_SST25XX_COMPARE;\r
543 \r
544   /* This is a compare job but the compare jobs really issues read in portions\r
545    * big enough to fit it's static buffers\r
546    */\r
547   if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {\r
548      job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadFastMode;\r
549   } else {\r
550      job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadNormalMode;\r
551   }\r
552 \r
553   job->flsAddr = SourceAddress;\r
554   job->targetAddr = TargetAddressPtr;\r
555   job->left = Length;\r
556 \r
557   JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_COMPARE);\r
558 \r
559   return E_OK;\r
560 }\r
561 \r
562 \r
563 #if ( FLS_SST25XX_CANCEL_API == STD_ON )\r
564 \r
565 /* API NOT SUPPORTED */\r
566 \r
567 void Fls_SST25xx_Cancel( void ){\r
568   if (Fls_SST25xx_Global.config->FlsJobEndNotification!=NULL) Fls_SST25xx_Global.config->FlsJobEndNotification();\r
569 \r
570   if (MEMIF_JOB_PENDING==Fls_SST25xx_Global.jobResultType) {\r
571         Fls_SST25xx_Global.jobResultType=MEMIF_JOB_CANCELLED;\r
572   }\r
573 \r
574   Fls_SST25xx_Global.status = MEMIF_IDLE;\r
575 }\r
576 #endif\r
577 \r
578 \r
579 #if ( FLS_GET_STATUS_API == STD_ON )\r
580 MemIf_StatusType Fls_SST25xx_GetStatus( void ){\r
581   return Fls_SST25xx_Global.status;\r
582 }\r
583 #endif\r
584 \r
585 MemIf_JobResultType Fls_SST25xx_GetJobResult( void ){\r
586   return Fls_SST25xx_Global.jobResultType;\r
587 }\r
588 \r
589 \r
590 /**\r
591  * Function that process read/write/erase requests to the SPI\r
592  *\r
593  * @param job The present job\r
594  */\r
595 \r
596 static Spi_SeqResultType Fls_SST25xx_ProcessJob( Fls_SST25xx_JobInfoType *job ) {\r
597   Spi_SeqResultType rv;\r
598   _Bool done = 0;\r
599 \r
600   /* Check if previous sequence is OK */\r
601   rv = Spi_GetSequenceResult(job->currSeq);\r
602   if( rv != SPI_SEQ_OK ) {\r
603         return rv;\r
604   }\r
605 \r
606   rv = SPI_SEQ_PENDING;\r
607 \r
608   do {\r
609                 switch(job->state ) {\r
610                 case JOB_READ_STATUS:\r
611                         DEBUG(DEBUG_LOW,"%s: READ_STATUS\n",MODULE_NAME);\r
612                         /* Check status from erase cmd, read status from flash */\r
613                         Spi_SetupEB( SPI_CH_FLASH_DATA, NULL, &Fls_SST25xx_Global.ebReadStatus, 1);\r
614                         Fls_SST25xx_Global.ebCmd = FLASH_RDSR;\r
615                         if( SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_CMD2,job ) != E_OK ) {\r
616                                 assert(0);\r
617                         }\r
618                         SET_STATE(1,JOB_READ_STATUS_RESULT);\r
619                         break;\r
620 \r
621                 case JOB_READ_STATUS_RESULT:\r
622                         DEBUG(DEBUG_LOW,"%s: READ_STATUS_RESULT\n",MODULE_NAME);\r
623                         if( Fls_SST25xx_Global.ebReadStatus&1 ) {\r
624                                 SET_STATE(0,JOB_READ_STATUS);\r
625                         } else {\r
626                                 SET_STATE(0,JOB_MAIN);\r
627                         }\r
628                         break;\r
629 \r
630                 case JOB_MAIN:\r
631                         if( job->left != 0 ) {\r
632                                 if( job->left <= job->chunkSize ) {\r
633                                         job->chunkSize = job->left;\r
634                                 }\r
635 \r
636                                 Spi_ConvertToSpiAddr(Fls_SST25xx_Global.ebFlsAddr,job->flsAddr);\r
637 \r
638                                 switch(job->mainState) {\r
639                                 case FLS_SST25XX_ERASE:\r
640                                         DEBUG(DEBUG_LOW,"%s: Erase 4K s:%04x\n",MODULE_NAME,job->flsAddr);\r
641                                         Fls_SST25xx_Global.ebCmd = FLASH_ERASE_4K;\r
642                                         SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_WRITE,job );\r
643                                         break;\r
644 \r
645                                 case FLS_SST25XX_READ:\r
646                                 case FLS_SST25XX_COMPARE:\r
647                                   DEBUG(DEBUG_LOW,"%s: READ s:%04x d:%04x l:%04x\n",MODULE_NAME,job->flsAddr, job->targetAddr, job->left);\r
648                                         Fls_SST25xx_Global.ebCmd = FLASH_READ_25;\r
649                                         Spi_SetupEB( SPI_CH_FLASH_DATA, NULL ,job->targetAddr,job->chunkSize);\r
650                                         SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_READ,job );\r
651                                         break;\r
652 \r
653                                 case FLS_SST25XX_WRITE:\r
654                                         DEBUG(DEBUG_LOW,"%s: WRITE d:%04x s:%04x first data:%02x\n",MODULE_NAME,job->flsAddr,job->targetAddr,*job->targetAddr);\r
655                                         Fls_SST25xx_Global.ebCmd = FLASH_BYTE_WRITE;\r
656                                         Spi_ConvertToSpiAddr(Fls_SST25xx_Global.ebFlsAddr,job->flsAddr);\r
657                                         Spi_SetupEB( SPI_CH_FLASH_DATA, job->targetAddr, NULL, job->chunkSize);\r
658                                         SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_WRITE,job );\r
659                                         break;\r
660 \r
661                                 default:\r
662                                         assert(0);\r
663                                         break;\r
664                                 }\r
665 \r
666                                 job->flsAddr += job->chunkSize;\r
667                                 job->targetAddr += job->chunkSize;\r
668                                 job->left -= job->chunkSize;\r
669                                 SET_STATE(1,JOB_READ_STATUS);\r
670 \r
671                         } else {\r
672                                 /* We are done :) */\r
673                                 SET_STATE(1,JOB_MAIN);\r
674                                 job->mainState = FLS_SST25XX_NONE;\r
675                                 rv = SPI_SEQ_OK;\r
676                         }\r
677                         break;\r
678 \r
679                 default:\r
680                         assert(0);\r
681                         break;\r
682 \r
683                 }\r
684         } while(!done);\r
685   return rv;\r
686 }\r
687 \r
688 \r
689 #define CMP_BUFF_SIZE SPI_EB_MAX_LENGTH\r
690 \r
691 void Fls_SST25xx_MainFunction( void )\r
692 {\r
693   Spi_SeqResultType jobResult;\r
694 \r
695   if( Fls_SST25xx_Global.jobResultType == MEMIF_JOB_PENDING ) {\r
696         switch (Fls_SST25xx_Global.jobType) {\r
697                 case FLS_SST25XX_COMPARE: {\r
698                         static Fls_SST25xx_JobInfoType readJob;\r
699                         static uint8 Fls_SST25xx_CompareBuffer[SPI_EB_MAX_LENGTH];\r
700                         Fls_SST25xx_JobInfoType *gJob = &Fls_SST25xx_Global.job;\r
701                         static _Bool firstTime = 1;\r
702                         static uint32 readSize;\r
703 \r
704                         /* Compare jobs must use a local buffer to hold one portion\r
705                          * of the job. Since Fls_SST25xx_ProcessJob() also manipulates the\r
706                          * job structure we need to create a new local job each time.\r
707                          * The global job updates is updated for each process job.\r
708                          */\r
709 \r
710                         if (firstTime == 1) {\r
711                                 readJob = *gJob;\r
712 \r
713                                 if ( gJob->left <= CMP_BUFF_SIZE ) {\r
714                                         readSize = gJob->left;\r
715                                 } else {\r
716                                         readSize = CMP_BUFF_SIZE;\r
717                                 }\r
718                                 readJob.left = readSize;\r
719                                 readJob.targetAddr = Fls_SST25xx_CompareBuffer;\r
720                                 firstTime = 0;\r
721                         }\r
722 \r
723                         jobResult = Fls_SST25xx_ProcessJob(&readJob);\r
724 \r
725                         if( jobResult == SPI_SEQ_PENDING ) {\r
726                                 /* Do nothing */\r
727                         } else if( jobResult == SPI_SEQ_OK ) {\r
728 \r
729                                 if( memcmp(Fls_SST25xx_CompareBuffer,gJob->targetAddr, readSize) != 0 ) {\r
730 #if defined(USE_DEM)\r
731                                         Dem_ReportErrorStatus(FLS_E_COMPARE_FAILED, DEM_EVENT_STATUS_FAILED);\r
732 #endif\r
733                                         FEE_JOB_ERROR_NOTIFICATION();\r
734                                         return;\r
735                                 }\r
736                                 // Update the global comare job\r
737                                 gJob->targetAddr += readSize;\r
738                                 gJob->flsAddr += readSize;\r
739                                 gJob->left -= readSize;\r
740 \r
741                                 // Check if we are done\r
742                                 if( gJob->left == 0 ) {\r
743                                         Fls_SST25xx_Global.jobResultType = MEMIF_JOB_OK;\r
744                                         Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;\r
745                                         Fls_SST25xx_Global.status = MEMIF_IDLE;\r
746                                         FEE_JOB_END_NOTIFICATION();\r
747                                         firstTime = 1;\r
748                                         return;\r
749                                 }\r
750                                 // Calculate new readSize\r
751                                 if ( gJob->left <= CMP_BUFF_SIZE ) {\r
752                                         readSize = gJob->left;\r
753                                 } else {\r
754                                         readSize = CMP_BUFF_SIZE;\r
755                                 }\r
756 \r
757                                 // Update the readjob for next session\r
758                                 readJob = *gJob;\r
759                                 readJob.left = readSize;\r
760                                 readJob.targetAddr = Fls_SST25xx_CompareBuffer;\r
761                         } else {\r
762                           // all other cases are bad\r
763                           firstTime = 1;\r
764         Fls_SST25xx_Global.jobResultType = MEMIF_JOB_FAILED;\r
765         Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;\r
766         Fls_SST25xx_Global.status = MEMIF_IDLE;\r
767 \r
768 #if defined(USE_DEM)\r
769                                 Dem_ReportErrorStatus(FLS_E_COMPARE_FAILED, DEM_EVENT_STATUS_FAILED);\r
770 #endif\r
771                                 FEE_JOB_ERROR_NOTIFICATION();\r
772                         }\r
773                 }\r
774                 break;\r
775 \r
776     case FLS_SST25XX_ERASE:\r
777     case FLS_SST25XX_READ:\r
778     case FLS_SST25XX_WRITE:\r
779 \r
780         jobResult =  Fls_SST25xx_ProcessJob(&Fls_SST25xx_Global.job);\r
781 \r
782         if( jobResult == SPI_SEQ_OK ) {\r
783 \r
784                 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_OK;\r
785                 Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;\r
786                 Fls_SST25xx_Global.status = MEMIF_IDLE;\r
787         FEE_JOB_END_NOTIFICATION();\r
788       } else if( jobResult == SPI_SEQ_PENDING )  {\r
789         /* Busy, Do nothing */\r
790       } else {\r
791         // Error\r
792         Fls_SST25xx_Global.jobResultType = MEMIF_JOB_FAILED;\r
793 \r
794         switch(Fls_SST25xx_Global.jobType) {\r
795         case FLS_SST25XX_ERASE:\r
796 #if defined(USE_DEM)\r
797                                         Dem_ReportErrorStatus(FLS_E_ERASED_FAILED, DEM_EVENT_STATUS_FAILED);\r
798 #endif\r
799                                         break;\r
800         case FLS_SST25XX_READ:\r
801 #if defined(USE_DEM)\r
802                                         Dem_ReportErrorStatus(FLS_E_READ_FAILED, DEM_EVENT_STATUS_FAILED);\r
803 #endif\r
804                                         break;\r
805         case FLS_SST25XX_WRITE:\r
806 #if defined(USE_DEM)\r
807                                         Dem_ReportErrorStatus(FLS_E_WRITE_FAILED, DEM_EVENT_STATUS_FAILED);\r
808 #endif\r
809                                         break;\r
810         default:\r
811                 assert(0);\r
812         }\r
813 \r
814         FEE_JOB_ERROR_NOTIFICATION();\r
815       }\r
816         break;\r
817     case FLS_SST25XX_NONE:\r
818       assert(0);\r
819       break;\r
820     }\r
821   }\r
822 }\r
823 \r
824 \r
825 #if ( FLS_SST25XX_VERSION_INFO_API == STD_ON )\r
826 void Fls_SST25XX_GetVersionInfo( Std_VersionInfoType *VersioninfoPtr )\r
827 {\r
828   memcpy(VersioninfoPtr, &Fls_SST25XX_VersionInfo, sizeof(Std_VersionInfoType));\r
829 }\r
830 \r
831 #endif\r
832 \r