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