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