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