1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - CARD - libraries
3   File:     card_spi.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro.h>
21 
22 #include "../include/card_common.h"
23 #include "../include/card_spi.h"
24 
25 /* CARD-SPI control */
26 
27 
28 /*---------------------------------------------------------------------------*/
29 /* Constants */
30 
31 /* The reg_MI_MCCNT0 bits*/
32 
33 #define MCCNT0_SPI_CLK_MASK	0x0003 /* Baud rate settings mask */
34 #define MCCNT0_SPI_CLK_4M	0x0000 /* Baud rate 4.19MHz */
35 #define MCCNT0_SPI_CLK_2M	0x0001 /* Baud rate 2.10 MHz */
36 #define MCCNT0_SPI_CLK_1M	0x0002 /* Baud rate 1.05 MHz */
37 #define MCCNT0_SPI_CLK_524K	0x0003 /* Baud rate 524 kHz */
38 #define MCCNT0_SPI_BUSY		0x0080 /* SPI busy flag */
39 #define	MMCNT0_SEL_MASK		0x2000 /* CARD ROM / SPI selection mask */
40 #define	MMCNT0_SEL_CARD		0x0000 /* CARD ROM selection */
41 #define	MMCNT0_SEL_SPI		0x2000 /* CARD SPI selection */
42 #define MCCNT0_INT_MASK		0x4000 /* Transfer completion interrupt mask */
43 #define MCCNT0_INT_ON		0x4000 /* Enable transfer completion interrupts */
44 #define MCCNT0_INT_OFF		0x0000 /* Disable transfer completion interrupts */
45 #define MCCNT0_MASTER_MASK	0x8000 /* CARD master mask */
46 #define MCCNT0_MASTER_ON	0x8000 /* CARD master ON */
47 #define MCCNT0_MASTER_OFF	0x0000 /* CARD master OFF */
48 
49 
50 /*---------------------------------------------------------------------------*/
51 /* Variables */
52 
53 typedef struct
54 {                                      /* SPI internal management parameter. */
55     u32     rest_comm;                 /* Total remaining number of bytes to send. */
56     u32     src;                       /* Transfer source */
57     u32     dst;                       /* Transfer destination */
58     BOOL    cmp;                       /* Comparison result */
59 }
60 CARDiParam;
61 
62 static CARDiParam cardi_param;
63 
64 
65 /*---------------------------------------------------------------------------*/
66 /* functions */
67 
68 static BOOL CARDi_CommandCheckBusy(void);
69 static void CARDi_CommArray(const void *src, void *dst, u32 n, void (*func) (CARDiParam *));
70 static void CARDi_CommReadCore(CARDiParam * p);
71 static void CARDi_CommWriteCore(CARDiParam * p);
72 static void CARDi_CommVerifyCore(CARDiParam * p);
73 
74 /*---------------------------------------------------------------------------*
75   Name:         CARDi_CommArrayRead
76 
77   Description:  Post-read processing for read commands.
78 
79   Arguments:    dst: Read-target memory
80                 len: Read size
81 
82   Returns:      None.
83  *---------------------------------------------------------------------------*/
CARDi_CommArrayRead(void * dst,u32 len)84 SDK_INLINE void CARDi_CommArrayRead(void *dst, u32 len)
85 {
86     CARDi_CommArray(NULL, dst, len, CARDi_CommReadCore);
87 }
88 
89 /*---------------------------------------------------------------------------*
90   Name:         CARDi_CommArrayWrite
91 
92   Description:  Post-write processing for write commands.
93 
94   Arguments:    dst: Write source memory
95                 len: Write size
96 
97   Returns:      None.
98  *---------------------------------------------------------------------------*/
CARDi_CommArrayWrite(const void * src,u32 len)99 SDK_INLINE void CARDi_CommArrayWrite(const void *src, u32 len)
100 {
101     CARDi_CommArray(src, NULL, len, CARDi_CommWriteCore);
102 }
103 
104 /*---------------------------------------------------------------------------*
105   Name:         CARDi_CommArrayVerify
106 
107   Description:  Post-read comparisons for (comparison) read commands.
108 
109   Arguments:    src: Comparison source memory
110                 len: Comparison size
111 
112   Returns:      None.
113  *---------------------------------------------------------------------------*/
CARDi_CommArrayVerify(const void * src,u32 len)114 SDK_INLINE void CARDi_CommArrayVerify(const void *src, u32 len)
115 {
116     CARDi_CommArray(src, NULL, len, CARDi_CommVerifyCore);
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         CARDi_EnableSpi
121 
122   Description:  Enables CARD-SPI.
123 
124   Arguments:    cont: Continuous transfer flag (CSPI_CONTINUOUS_ON or OFF)
125 
126   Returns:      None.
127  *---------------------------------------------------------------------------*/
CARDi_EnableSpi(u32 cont)128 SDK_INLINE void CARDi_EnableSpi(u32 cont)
129 {
130     /*
131      * If a device with a slow clock speed is introduced in the future, MCCNT0_SPI_CLK_4M will be added to the property array, resulting in a dynamic change
132      *
133      */
134     const u16 ctrl = (u16)(MCCNT0_MASTER_ON |
135                            MCCNT0_INT_OFF | MMCNT0_SEL_SPI | MCCNT0_SPI_CLK_4M | cont);
136     reg_MI_MCCNT0 = ctrl;
137 }
138 
139 /*---------------------------------------------------------------------------*
140   Name:         CARDi_WaitBusy
141 
142   Description:  Waits for CARD-SPI completion.
143 
144   Arguments:    None.
145 
146   Returns:      None.
147  *---------------------------------------------------------------------------*/
CARDi_WaitBusy(void)148 SDK_INLINE void CARDi_WaitBusy(void)
149 {
150     while ((reg_MI_MCCNT0 & MCCNT0_SPI_BUSY) != 0)
151     {
152     }
153 }
154 
155 /*---------------------------------------------------------------------------*
156   Name:         CARDi_CommandBegin
157 
158   Description:  Declaration for starting the issuing of commands.
159 
160   Arguments:    len: Length of the command to be issued
161 
162   Returns:      None.
163  *---------------------------------------------------------------------------*/
CARDi_CommandBegin(int len)164 static void CARDi_CommandBegin(int len)
165 {
166     cardi_param.rest_comm = (u32)len;
167 }
168 
169 /*---------------------------------------------------------------------------*
170   Name:         CARDi_CommandEnd
171 
172   Description:  Command send completion process.
173 
174   Arguments:    force_wait: Forced wait time (ms)
175                 timeout: Timeout duration (ms)
176 
177   Returns:      None.
178  *---------------------------------------------------------------------------*/
CARDi_CommandEnd(u32 force_wait,u32 timeout)179 static void CARDi_CommandEnd(u32 force_wait, u32 timeout)
180 {
181     if (force_wait + timeout > 0)
182     {
183         /*
184          * If there is a forced wait, only wait for that time.
185          * Unlike what was first talked about, the FLASH wait was also forced.
186          */
187         if (force_wait > 0)
188         {
189             OS_Sleep(force_wait);
190         }
191         if (timeout > 0)
192         {
193             /*
194              * Only the PageWrite command is "forced to wait for just the first half," so this kind of special loop is used
195              *
196              */
197             int     rest = (int)(timeout - force_wait);
198             while (!CARDi_CommandCheckBusy() && (rest > 0))
199             {
200                 int     interval = (rest < 5) ? rest : 5;
201                 OS_Sleep((u32)interval);
202                 rest -= interval;
203             }
204         }
205         /*
206          * Other commands have waited the designated time, so one ReadStatus alone is acceptable
207          *
208          */
209         /* If busy at this point, then timeout */
210         if (!CARDi_CommandCheckBusy())
211         {
212             cardi_common.cmd->result = CARD_RESULT_TIMEOUT;
213         }
214     }
215 }
216 
217 /*---------------------------------------------------------------------------*
218   Name:         CARDi_CommandReadStatus
219 
220   Description:  Read status.
221 
222   Arguments:    None.
223 
224   Returns:      Status value.
225  *---------------------------------------------------------------------------*/
CARDi_CommandReadStatus(void)226 u8 CARDi_CommandReadStatus(void)
227 {
228     const u8    buf = COMM_READ_STATUS;
229     u8          dst;
230     CARDi_CommandBegin(1 + 1);
231     CARDi_CommArrayWrite(&buf, 1);
232     CARDi_CommArrayRead(&dst, 1);
233     CARDi_CommandEnd(0, 0);
234     return dst;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         CARDi_CommandCheckBusy
239 
240   Description:  Determines from the read status command whether the device is still busy.
241 
242   Arguments:    None.
243 
244   Returns:      TRUE when not busy.
245  *---------------------------------------------------------------------------*/
CARDi_CommandCheckBusy(void)246 static BOOL CARDi_CommandCheckBusy(void)
247 {
248     return ((CARDi_CommandReadStatus() & COMM_STATUS_WIP_BIT) == 0);
249 }
250 
251 /*---------------------------------------------------------------------------*
252   Name:         CARDi_WaitPrevCommand
253 
254   Description:  Busy check prior to the issuing of commands.
255                 Waits for 50ms if a busy state from the prior command exists.
256                 (This is impossible under normal circumstances as long as the library is installed and the card correctly connected.)
257 
258   Arguments:    None.
259 
260   Returns:      TRUE if the command can be correctly issued.
261  *---------------------------------------------------------------------------*/
CARDi_WaitPrevCommand(void)262 static BOOL CARDi_WaitPrevCommand(void)
263 {
264     CARDi_CommandEnd(0, 50);
265     /* No response if a timeout occurs here */
266     if (cardi_common.cmd->result == CARD_RESULT_TIMEOUT)
267     {
268         cardi_common.cmd->result = CARD_RESULT_NO_RESPONSE;
269         return FALSE;
270     }
271     return TRUE;
272 }
273 
274 /*---------------------------------------------------------------------------*
275   Name:         CARDi_CommArray
276 
277   Description:  Common processes for the issuing of commands.
278 
279   Arguments:    src: Pprocessing source memory (NULL if not used)
280                 dst: Processing destination memory (NULL if not used)
281                 len: Processing size
282                 func: Processing content
283 
284   Returns:      None.
285  *---------------------------------------------------------------------------*/
CARDi_CommArray(const void * src,void * dst,u32 len,void (* func)(CARDiParam *))286 void CARDi_CommArray(const void *src, void *dst, u32 len, void (*func) (CARDiParam *))
287 {
288     CARDiParam *const p = &cardi_param;
289     p->src = (u32)src;
290     p->dst = (u32)dst;
291     CARDi_EnableSpi(CSPI_CONTINUOUS_ON);
292     for (; len > 0; --len)
293     {
294         if (!--p->rest_comm)
295         {
296             CARDi_EnableSpi(CSPI_CONTINUOUS_OFF);
297         }
298         CARDi_WaitBusy();
299         (*func) (p);
300     }
301     if (!p->rest_comm)
302     {
303         reg_MI_MCCNT0 = (u16)(MCCNT0_MASTER_OFF | MCCNT0_INT_OFF);
304     }
305 }
306 
307 /*---------------------------------------------------------------------------*
308   Name:         CARDi_CommReadCore
309 
310   Description:  Reads a single byte.
311 
312   Arguments:    p: Command parameter
313 
314   Returns:      None.
315  *---------------------------------------------------------------------------*/
CARDi_CommReadCore(CARDiParam * p)316 void CARDi_CommReadCore(CARDiParam * p)
317 {
318     reg_MI_MCD0 = 0;
319     CARDi_WaitBusy();
320     MI_WriteByte((void *)p->dst, (u8)reg_MI_MCD0);
321     ++p->dst;
322 }
323 
324 /*---------------------------------------------------------------------------*
325   Name:         CARDi_CommWriteCore
326 
327   Description:  Writes a single byte.
328 
329   Arguments:    p: Command parameter
330 
331   Returns:      None.
332  *---------------------------------------------------------------------------*/
CARDi_CommWriteCore(CARDiParam * p)333 void CARDi_CommWriteCore(CARDiParam * p)
334 {
335     vu16    tmp;
336     reg_MI_MCD0 = (u16)MI_ReadByte((void *)p->src);
337     ++p->src;
338     CARDi_WaitBusy();
339     tmp = reg_MI_MCD0;
340 }
341 
342 /*---------------------------------------------------------------------------*
343   Name:         CARDi_CommVerifyCore
344 
345   Description:  Single byte comparison.
346 
347   Arguments:    p: Command parameter
348 
349   Returns:      None.
350  *---------------------------------------------------------------------------*/
CARDi_CommVerifyCore(CARDiParam * p)351 void CARDi_CommVerifyCore(CARDiParam * p)
352 {
353     reg_MI_MCD0 = 0;
354     CARDi_WaitBusy();
355     /*
356      * Read, and disconnect if no match.
357      * However, you must exit from continuous transmissions, and therefore need to read at least once more than required.
358      *
359      */
360     if ((u8)reg_MI_MCD0 != MI_ReadByte((void *)p->src))
361     {
362         p->cmp = FALSE;
363         if (p->rest_comm > 1)
364         {
365             p->rest_comm = 1;
366         }
367     }
368     ++p->src;
369 }
370 
371 /*---------------------------------------------------------------------------*
372   Name:         CARDi_WriteEnable
373 
374   Description:  Enables device write operations (this is needed once before every write-based command).
375 
376   Arguments:    None.
377 
378   Returns:      None.
379  *---------------------------------------------------------------------------*/
CARDi_WriteEnable(void)380 static void CARDi_WriteEnable(void)
381 {
382     static const u8 arg[1] = { COMM_WRITE_ENABLE, };
383     CARDi_CommandBegin(sizeof(arg));
384     CARDi_CommArrayWrite(arg, sizeof(arg));
385     CARDi_CommandEnd(0, 0);
386 }
387 
388 /*---------------------------------------------------------------------------*
389   Name:         CARDi_SendSpiAddressingCommand
390 
391   Description:  Sets the address specification command settings.
392 
393   Arguments:    addr: Address on the device where searches will take place
394                 mode: Command to be issued
395 
396   Returns:      None.
397  *---------------------------------------------------------------------------*/
CARDi_SendSpiAddressingCommand(u32 addr,u32 mode)398 static void CARDi_SendSpiAddressingCommand(u32 addr, u32 mode)
399 {
400     const u32 width = cardi_common.cmd->spec.addr_width;
401     u32     addr_cmd;
402     switch (width)
403     {
404     case 1:
405         /* For a 4kbit device, [A:8] becomes part of the command */
406         addr_cmd = (u32)(mode | ((addr >> 5) & 0x8) | ((addr & 0xFF) << 8));
407         break;
408     case 2:
409         addr_cmd = (u32)(mode | (addr & 0xFF00) | ((addr & 0xFF) << 16));
410         break;
411     case 3:
412         addr_cmd = (u32)(mode |
413                          ((addr >> 8) & 0xFF00) | ((addr & 0xFF00) << 8) | ((addr & 0xFF) << 24));
414         break;
415     default:
416         SDK_ASSERT(FALSE);
417         break;
418     }
419     CARDi_CommArrayWrite(&addr_cmd, (u32)(1 + width));
420 }
421 
422 /*---------------------------------------------------------------------------*
423   Name:         CARDi_InitStatusRegister
424 
425   Description:  For FRAM/EEPROM, adjusts the status register at launch.
426                 * Because changes in write protection may occur when the power is turned on when using FRAM.
427                 * Because initial values may be invalid at time of delivery when using EEPROM.
428 
429   Arguments:    None.
430 
431   Returns:      None.
432  *---------------------------------------------------------------------------*/
CARDi_InitStatusRegister(void)433 void CARDi_InitStatusRegister(void)
434 {
435     /*
436      * The status register makes appropriate adjustments when used the first time for devices that could take erroneous defaults values.
437      *
438      */
439     const u8 stat = cardi_common.cmd->spec.initial_status;
440     if (stat != 0xFF)
441     {
442         static BOOL status_checked = FALSE;
443         if (!status_checked)
444         {
445             if (CARDi_CommandReadStatus() != stat)
446             {
447                 CARDi_SetWriteProtectCore(stat);
448             }
449             status_checked = TRUE;
450         }
451     }
452 }
453 
454 
455 /********************************************************************/
456 /*
457  * Direct internal process.
458  * Exclusions, requests, and so on are all already completed with this step.
459  * The limits on the size are assumed to have been taken into consideration.
460  */
461 
462 /*---------------------------------------------------------------------------*
463   Name:         CARDi_ReadBackupCore
464 
465   Description:  The entire read command for the device.
466 
467   Arguments:    src: Read origin's device offset
468                 dst: Read target's memory address
469                 len: Read size
470 
471   Returns:      None.
472  *---------------------------------------------------------------------------*/
CARDi_ReadBackupCore(u32 src,void * dst,u32 len)473 void CARDi_ReadBackupCore(u32 src, void *dst, u32 len)
474 {
475     if (CARDi_WaitPrevCommand())
476     {
477         CARDiCommandArg *const cmd = cardi_common.cmd;
478         /* The read process is done all at once because there is no page boundary */
479         CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + len));
480         CARDi_SendSpiAddressingCommand(src, COMM_READ_ARRAY);
481         CARDi_CommArrayRead(dst, len);
482         CARDi_CommandEnd(0, 0);
483     }
484 }
485 
486 /*---------------------------------------------------------------------------*
487   Name:         CARDi_ProgramBackupCore
488 
489   Description:  The entire Program (write without delete) command for the device.
490 
491   Arguments:    dst: Write target's device offset
492                 src: Write origin's memory address
493                 len: Write size
494 
495   Returns:      None.
496  *---------------------------------------------------------------------------*/
CARDi_ProgramBackupCore(u32 dst,const void * src,u32 len)497 void CARDi_ProgramBackupCore(u32 dst, const void *src, u32 len)
498 {
499     if (CARDi_WaitPrevCommand())
500     {
501         CARDiCommandArg *const cmd = cardi_common.cmd;
502         /* Divide up the process so the write does not cross page boundaries */
503         const u32 page = cmd->spec.page_size;
504         while (len > 0)
505         {
506             const u32 mod = (u32)(dst & (page - 1));
507             u32     size = page - mod;
508             if (size > len)
509             {
510                 size = len;
511             }
512             CARDi_WriteEnable();
513             CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + size));
514             CARDi_SendSpiAddressingCommand(dst, COMM_PROGRAM_PAGE);
515             CARDi_CommArrayWrite(src, size);
516             CARDi_CommandEnd(cmd->spec.program_page, 0);
517             if (cmd->result != CARD_RESULT_SUCCESS)
518             {
519                 break;
520             }
521             src = (const void *)((u32)src + size);
522             dst += size;
523             len -= size;
524         }
525     }
526 }
527 
528 /*---------------------------------------------------------------------------*
529   Name:         CARDi_WriteBackupCore
530 
531   Description:  The entire Write (Delete + Program) command to the device.
532 
533   Arguments:    dst: Write target's device offset
534                 src: Write origin's memory address
535                 len: Write size
536 
537   Returns:      None.
538  *---------------------------------------------------------------------------*/
CARDi_WriteBackupCore(u32 dst,const void * src,u32 len)539 void CARDi_WriteBackupCore(u32 dst, const void *src, u32 len)
540 {
541     if (CARDi_WaitPrevCommand())
542     {
543         CARDiCommandArg *const cmd = cardi_common.cmd;
544         /* Divide up the process so the write does not cross page boundaries */
545         const u32 page = cmd->spec.page_size;
546         while (len > 0)
547         {
548             const u32 mod = (u32)(dst & (page - 1));
549             u32     size = page - mod;
550             if (size > len)
551             {
552                 size = len;
553             }
554             CARDi_WriteEnable();
555             CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + size));
556             CARDi_SendSpiAddressingCommand(dst, COMM_PAGE_WRITE);
557             CARDi_CommArrayWrite(src, size);
558             CARDi_CommandEnd(cmd->spec.write_page, cmd->spec.write_page_total);
559             if (cmd->result != CARD_RESULT_SUCCESS)
560             {
561                 break;
562             }
563             src = (const void *)((u32)src + size);
564             dst += size;
565             len -= size;
566         }
567     }
568 }
569 
570 /*---------------------------------------------------------------------------*
571   Name:         CARDi_VerifyBackupCore
572 
573   Description:  The entire Verify (actually this is Read + comparison) command to the device.
574 
575   Arguments:    dst: Comparison target's device offset
576                 src: Memory address of comparison source
577                 len: Comparison size
578 
579   Returns:      None.
580  *---------------------------------------------------------------------------*/
CARDi_VerifyBackupCore(u32 dst,const void * src,u32 len)581 void CARDi_VerifyBackupCore(u32 dst, const void *src, u32 len)
582 {
583     if (CARDi_WaitPrevCommand())
584     {
585         CARDiCommandArg *const cmd = cardi_common.cmd;
586         /* The read process is done all at once because there is no page boundary */
587         cardi_param.cmp = TRUE;
588         CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + len));
589         CARDi_SendSpiAddressingCommand(dst, COMM_READ_ARRAY);
590         CARDi_CommArrayVerify(src, len);
591         CARDi_CommandEnd(0, 0);
592         if ((cmd->result == CARD_RESULT_SUCCESS) && !cardi_param.cmp)
593         {
594             cmd->result = CARD_RESULT_FAILURE;
595         }
596     }
597 }
598 
599 /*---------------------------------------------------------------------------*
600   Name:         CARDi_EraseBackupSectorCore
601 
602   Description:  The entire Sector Delete command for the device.
603 
604   Arguments:    dst: Deletion target device offset
605                 len: Deletion size
606 
607   Returns:      None.
608  *---------------------------------------------------------------------------*/
CARDi_EraseBackupSectorCore(u32 dst,u32 len)609 void CARDi_EraseBackupSectorCore(u32 dst, u32 len)
610 {
611     CARDiCommandArg *const cmd = cardi_common.cmd;
612     const u32 sector = cmd->spec.sect_size;
613     /* No processing takes place if the range is not aligned to an integer multiple of sectors. */
614     if (((dst | len) & (sector - 1)) != 0)
615     {
616         cmd->result = CARD_RESULT_INVALID_PARAM;
617     }
618     else if (CARDi_WaitPrevCommand())
619     {
620         /* processed in sector-aligned units */
621         while (len > 0)
622         {
623             CARDi_WriteEnable();
624             CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + 0));
625             CARDi_SendSpiAddressingCommand(dst, COMM_SECTOR_ERASE);
626             CARDi_CommandEnd(cmd->spec.erase_sector, cmd->spec.erase_sector_total);
627             if (cmd->result != CARD_RESULT_SUCCESS)
628             {
629                 break;
630             }
631             dst += sector;
632             len -= sector;
633         }
634     }
635 }
636 
637 /*---------------------------------------------------------------------------*
638   Name:         CARDi_EraseBackupSubSectorCore
639 
640   Description:  The entire sub-sector deletion command to the device.
641 
642   Arguments:    dst: Deletion target device offset
643                 len: Deletion size
644 
645   Returns:      None.
646  *---------------------------------------------------------------------------*/
CARDi_EraseBackupSubSectorCore(u32 dst,u32 len)647 void CARDi_EraseBackupSubSectorCore(u32 dst, u32 len)
648 {
649     CARDiCommandArg *const cmd = cardi_common.cmd;
650     const u32 sector = cmd->spec.subsect_size;
651     /* No processing takes place if the processing range is not aligned to an integer multiple of sub-sectors */
652     if (((dst | len) & (sector - 1)) != 0)
653     {
654         cmd->result = CARD_RESULT_INVALID_PARAM;
655     }
656     else if (CARDi_WaitPrevCommand())
657     {
658         /* Processed in sector-aligned units */
659         while (len > 0)
660         {
661             CARDi_WriteEnable();
662             CARDi_CommandBegin((int)(1 + cmd->spec.addr_width + 0));
663             CARDi_SendSpiAddressingCommand(dst, COMM_SUBSECTOR_ERASE);
664             CARDi_CommandEnd(cmd->spec.erase_subsector, cmd->spec.erase_subsector_total);
665             if (cmd->result != CARD_RESULT_SUCCESS)
666             {
667                 break;
668             }
669             dst += sector;
670             len -= sector;
671         }
672     }
673 }
674 
675 /*---------------------------------------------------------------------------*
676   Name:         CARDi_EraseChipCore
677 
678   Description:  The entire chip delete command for the device.
679 
680   Arguments:    None.
681 
682   Returns:      None.
683  *---------------------------------------------------------------------------*/
CARDi_EraseChipCore(void)684 void CARDi_EraseChipCore(void)
685 {
686     if (CARDi_WaitPrevCommand())
687     {
688         CARDiCommandArg *const cmd = cardi_common.cmd;
689         static const u8 arg[1] = { COMM_CHIP_ERASE, };
690         CARDi_WriteEnable();
691         CARDi_CommandBegin(sizeof(arg));
692         CARDi_CommArrayWrite(arg, sizeof(arg));
693         CARDi_CommandEnd(cmd->spec.erase_chip, cmd->spec.erase_chip_total);
694     }
695 }
696 
697 /*---------------------------------------------------------------------------*
698   Name:         CARDi_SetWriteProtectCore
699 
700   Description:  The entire write-protect command for the device.
701 
702   Arguments:    stat: Protect flag to be set
703 
704   Returns:      None.
705  *---------------------------------------------------------------------------*/
CARDi_SetWriteProtectCore(u16 stat)706 void CARDi_SetWriteProtectCore(u16 stat)
707 {
708     if (CARDi_WaitPrevCommand())
709     {
710         CARDiCommandArg *const cmd = cardi_common.cmd;
711         int     retry_count = 10;
712         u8      arg[2];
713         arg[0] = COMM_WRITE_STATUS;
714         arg[1] = (u8)stat;
715         do
716         {
717             CARDi_WriteEnable();
718             CARDi_CommandBegin(1 + 1);
719             CARDi_CommArrayWrite(&arg, sizeof(arg));
720             CARDi_CommandEnd(5, 0);
721         }
722         while ((cmd->result == CARD_RESULT_TIMEOUT) && (--retry_count > 0));
723     }
724 }
725 
726 
727 #if	0
728 
729 /********************************************************************/
730 /********************************************************************/
731 /* Device-specific commands now being verified ***********************/
732 /********************************************************************/
733 /********************************************************************/
734 
735 
736 /* ID read */
737 static void CARDi_ReadIdCore(void)
738 {
739     /*
740      * These commands do not exist in EEPROM or FRAM.
741      * Do they also not exist in the ST 2Mbit FLASH?
742      * Assume that an operation is not defined when incompatible command bytes are sent. For 2-megabit FLASH, should use of these commands always be denied, or should they be broken up into CARD_BACKUP_TYPE_FLASH_2MBITS_SANYO (for example)?
743      * In any case, won't there be scenarios where an ID is required even if we've already broken them up into small categories?
744      * If there is any reserve capacity, we plan to use it internally to determine the validity.
745      *
746      *
747      *
748      */
749     cardi_common.cmd->result = CARD_RESULT_UNSUPPORTED;
750 }
751 
752 /* Commands that can only be used with 2M FLASH  *******************************/
753 
754 /* Page erase (FLASH) */
755 static void CARDi_ErasePageCore(u32 dst)
756 {
757     CARDi_WriteEnable();
758     CARDi_CommandBegin(1 + cardi_common.cmd->spec.addr_width + 0);
759     CARDi_SendSpiAddressingCommand(dst, COMM_PAGE_ERASE);
760     CARDi_CommandEnd(cardi_common.cmd->spec.erase_page, 0);
761 }
762 
763 
764 #endif
765