source: umon/main/common/sd.c @ 98883c2

Last change on this file since 98883c2 was 98883c2, checked in by Ed Sutter <edsutterjr@…>, on 08/04/15 at 00:20:34

fix incorred verbose help text

  • Property mode set to 100644
File size: 13.0 KB
RevLine 
[87db514]1/**************************************************************************
2 *
3 * Copyright (c) 2013 Alcatel-Lucent
4 *
5 * Alcatel Lucent licenses this file to You under the Apache License,
6 * Version 2.0 (the "License"); you may not use this file except in
7 * compliance with the License.  A copy of the License is contained the
8 * file LICENSE at the top level of this repository.
9 * You may also obtain a copy of the License at:
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 **************************************************************************
20 *
21 * sd.c:
22 *
23 * This code is the user interface portion of the sd (compact flash)
24 * command for uMon.
25 * This command is intended to be the "interface" portion of some
26 * other command (for example "fatfs").  Refer to the discussion in
27 * fatfs.c for more details.
28 *
29 * Original author:     Ed Sutter (ed.sutter@alcatel-lucent.com)
30 *
31 */
32
33#include "config.h"
34#if INCLUDE_SD
35#include "stddefs.h"
36#include "genlib.h"
37#include "cli.h"
38#include "timer.h"
39#include "tfs.h"
40#include "tfsprivate.h"
41#include "sd.h"
42
43struct sdinfo sdInfoTbl[SD_DEVTOT];
44char sdVerbose;
45static int sdInum;              /* Interface number: to support multiple SD interfaces.
46                                                 * Typically this will always be zero.
47                                                 */
48
49
50static struct sdcmd sdCardCmdTbl[] = {
51        { GO_IDLE_STATE,                        R1_RLEN,        R1      },
52        { SEND_OP_COND,                         R1_RLEN,        R1      },
53        { SWITCH_FUNC,                          R1_RLEN,        R1      },
54        { SEND_IF_COND,                         R7_RLEN,        R7      },
55        { SEND_CSD,                                     R1_RLEN,        R1      },
56        { SEND_CID,                                     R1_RLEN,        R1      },
57        { STOP_TRANSMISSION,            R1_RLEN,        R1B     },
58        { SEND_STATUS,                          R2_RLEN,        R2      },
59        { SET_BLOCKLEN,                         R1_RLEN,        R1      },
60        { READ_SINGLE_BLK,                      R1_RLEN,        R1      },
61        { READ_MULTIPLE_BLK,            R1_RLEN,        R1      },
62        { WRITE_BLK,                            R1_RLEN,        R1B     },
63        { WRITE_MULTIPLE_BLK,           R1_RLEN,        R1B     },
64        { PROGRAM_CSD,                          R1_RLEN,        R1      },
65        { SET_WRITE_PROT,                       R1_RLEN,        R1B     },
66        { CLR_WRITE_PROT,                       R1_RLEN,        R1B     },
67        { SEND_WRITE_PROT,                      R1_RLEN,        R1      },
68        { ERASE_WR_BLK_START_ADDR,      R1_RLEN,        R1      },
69        { ERASE_WR_BLK_END_ADDR,        R1_RLEN,        R1      },
70        { ERASE,                                        R1_RLEN,        R1B     },
71        { LOCK_UNLOCK,                          R1_RLEN,        R1      },
72        { APP_CMD,                                      R1_RLEN,        R1      },
73        { GEN_CMD,                                      R1_RLEN,        R1      },
74        { READ_OCR,                                     R3_RLEN,        R3      },
75        { CRC_ON_OFF,                           R1_RLEN,        R1      },
76        { SD_SEND_OP_COND,                      R1_RLEN,        R1      },
77        { -1,-1,-1      }
78};
79
80char *SdHelp[] = {
81        "Secure Digital Flash Interface",
82        "[options] {operation} [args]...",
83#if INCLUDE_VERBOSEHELP
84        "",
85        "Options:",
86        " -i ##  interface # (default is 0)",
87        " -v     additive verbosity",
88        "",
89        "Operations:",
90        " init [prefix]",
91        " cmd {cmdnum} [arg]",
92        " read {dest} {blk} {blktot}",
[98883c2]93        " write {src} {blk} {blktot}",
[87db514]94#endif
95        0
96};
97
98int
99SdCmd(int argc, char *argv[])
100{
101        char *cmd, *buf, *prefix, varname[16];
102        int opt, verbose, sdret, blknum, blkcnt;
103
104        verbose = 0;
105        while ((opt=getopt(argc,argv,"i:v")) != -1) {
106                switch(opt) {
107                        case 'i':
108                                sdInum = atoi(optarg);  /* sticky */
109                                break;
110                        case 'v':
111                                verbose++;
112                                break;
113                        default:
114                                return(CMD_PARAM_ERROR);
115                }
116        }
117
118        if (argc < optind + 1)
119                return(CMD_PARAM_ERROR);
120
121        cmd = argv[optind];
122
123        if (sdInum >= SD_DEVTOT) {
124                printf("Configured to support %d SD interface%s\n",
125                        SD_DEVTOT,SD_DEVTOT == 1 ? "" : "s");
126                return(CMD_FAILURE);
127        }
128
129        if (sdInstalled(sdInum) == 0) {
130                printf("SDCard not installed\n");
131                return(CMD_FAILURE);
132        }
133
134        if (strcmp(cmd,"init") == 0) {
135                sdret = sdInit(sdInum, verbose);
136                if (sdret < 0) {
137                        printf("sdInit returned %d\n",sdret);
138                        return(CMD_FAILURE);
139                }
140
141                // If prefix is specified, then load shell variables:
142                if (argc == optind+2) {
143                        prefix = argv[optind+1];
144                        if (strlen(prefix)+4 > sizeof(varname)) {
145                                printf("prefix %s too long\n",prefix);
146                                return(CMD_PARAM_ERROR);
147                        }
148
149                        sprintf(varname,"%s_RD",prefix);
150                        shell_sprintf(varname,"0x%lx",(long)sdRead);
151
152                        sprintf(varname,"%s_WR",prefix);
153                        shell_sprintf(varname,"0x%lx",(long)sdWrite);
154                }
155
156                shell_sprintf("SD_BLKSIZE","0x%lx",SD_BLKSIZE);
157        }
158        else if (strcmp(cmd,"cmd") == 0) {
159                ulong cmdarg;
160                uchar resp[8];
161                int rtot, i, cmdnum;
162
163                cmdarg = 0;
164                memset((char *)resp,0xff,sizeof(resp));
165
166                if ((argc != (optind+2)) && (argc != (optind+3)))
167                        return(CMD_PARAM_ERROR);
168
169                cmdnum = (uchar)strtoul(argv[optind+1],0,0);
170                if (argc == optind+3)
171                        cmdarg = strtoul(argv[optind+2],0,0);
172                sdret = sdCardCmd(sdInum, cmdnum , cmdarg ,resp);
173                if (sdret < 0) {
174                        printf("sdCardCmd returned %d\n",sdret);
175                        return(CMD_FAILURE);
176                }
177
178                rtot = sdCmdrlen(cmdnum);
179
180                printf("CMD_%d resp: ",cmdnum);
181                for(i=0;i<rtot;i++)
182                        printf("%02x ",resp[i]);
183                printf("\n");
184        }
185        else if (strcmp(cmd,"read") == 0) {
186                if (argc != optind+4)
187                        return(CMD_PARAM_ERROR);
188
189                buf = (char *)strtoul(argv[optind+1],0,0);
190                blknum = strtoul(argv[optind+2],0,0);
191                blkcnt = strtoul(argv[optind+3],0,0);
192
193                sdret = sdRead(sdInum,buf,blknum,blkcnt);
194                if (sdret < 0) {
195                        printf("sdRead returned %d\n",sdret);
196                        return(CMD_FAILURE);
197                }
198        }
199        else if (strcmp(cmd,"write") == 0) {
200                if (argc != optind+4)
201                        return(CMD_PARAM_ERROR);
202                buf = (char *)strtoul(argv[optind+1],0,0);
203                blknum = strtoul(argv[optind+2],0,0);
204                blkcnt = strtoul(argv[optind+3],0,0);
205
206                sdret = sdWrite(sdInum,buf,blknum,blkcnt);
207                if (sdret < 0) {
208                        printf("sdWrite returned %d\n",sdret);
209                        return(CMD_FAILURE);
210                }
211        }
212        else {
213                printf("sd op <%s> not found\n",cmd);
214                return(CMD_FAILURE);
215        }
216
217        return(CMD_SUCCESS);
218}
219
220/* sdCmdrlen():
221 * Given the command number, return the response length.
222 */
223int
224sdCmdrlen(int cmd)
225{
226        struct sdcmd *sdp = sdCardCmdTbl;
227
228        while(sdp->cmd != -1) {
229                if (cmd == sdp->cmd)
230                        return(sdp->rlen);
231                sdp++;
232        }
233        return(-1);
234}
235       
236/* sdCmdrtype():
237 * Given the command number, return the response type.
238 */
239int
240sdCmdrtype(int cmd)
241{
242        struct sdcmd *sdp = sdCardCmdTbl;
243
244        while(sdp->cmd != -1) {
245                if (cmd == sdp->cmd)
246                        return(sdp->rtype);
247                sdp++;
248        }
249        return(-1);
250}
251
252static char *months[] = {
253        "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
254        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
255};
256
257void
258sdShowCID(uchar *cid)
259{
260        int             year, mon;
261
262        printf("  Manufacturer ID:    x%02x\n", cid[0]);
263        printf("  OEM/Application ID: x%02x%02x\n", cid[1],cid[2]);
264        printf("  Product name:       %c%c%c%c%c\n",
265                cid[3],cid[4],cid[5],cid[6],cid[7]);
266        printf("  Product rev:        x%02x\n", cid[8]);
267        printf("  Product serialno:   x%02x%02x%02x%02x\n",
268                cid[9],cid[10],cid[11],cid[12]);
269
270        year = (((cid[13] & 0x0f) << 4) | ((cid[14] & 0xf0) >> 4));
271        mon = (cid[14] & 0x0f);
272        if ((mon < 1) || (mon > 12))
273                mon = 0;
274        printf("  Manufactured:       %s/%d\n",months[mon],2000+year);
275}
276
277void
278sdShowCSD(uchar *csd)
279{
280        uchar csdver;
281        long long capacity;
282        int mult, csize, csm, rbl;
283        int blocknr, blocklen, i;
284
285        printf("  CSD Response: ");
286        for(i=0;i<16;i++)
287                printf("%02x ",csd[i]);
288        printf("\n");
289
290        mult = csize = csm = rbl = 0;
291
292        if ((csd[0] & 0xc0) == 0)
293                csdver = 1;
294        else if ((csd[0] & 0xc0) == 0x40)
295                csdver = 2;
296        else {
297                printf("Invalid CSD structure type\n");
298                return;
299        }
300
301        printf("  CSD version %d.0\n",csdver);
302        if (csdver == 1) {
303                rbl = csd[5] & 0x0f;
304                csize = ((csd[8] & 0xC0) >> 6);
305                csize |= (csd[7] << 2);
306                csize |= ((csd[6] & 0x03) << 10);
307                csm = (csd[9] & 0x03);
308                csm <<= 1;
309                csm |= ((csd[10] & 0x80) >> 7);
310
311                mult = (1 << (csm+2));
312                blocknr = (csize+1)*mult;
313                blocklen = (1 << rbl);
314                capacity = (long long)((long long)blocknr * (long long)blocklen);
315                //printf("  (csm=%d, csize=%d, rbl=%d, mult=%d, blknr=%d, blkln=%d)\n",
316                //      csm, csize, rbl, mult, blocknr, blocklen);
317        }
318        else if (csdver == 2) {
319                rbl = csd[5] & 0x0f;
320                csize = (csd[7] & 0x3f) << 16;
321                csize |= (csd[8] << 8);
322                csize |= csd[9];
323                capacity = (long long)((long long)(csize + 1) * 512LL * 1024LL);
324        }
325        else {
326                printf("  Unrecognized CSD version.\n");
327                return;
328        }
329        printf("  Card capacity: %lld bytes\n",capacity);
330}
331
332/* sdGenericStartup():
333 * Called by the interface-specific sdInit() code to do the generic
334 * portion of the SD-Card initialization.
335 *
336 * Refer to the flowchart shown in figure 7.2 of the Simplified
337 * Physical Layer Specification for an overview of the initialization.
338 *
339 * The card wakes up in SD bus mode, so the first thing we need to d
340 * here (after the very basic initialization of the SPI pin config) is
341 * to get the card into SPI mode.
342 * By default, the card assumes CRC checking is disabled.  The field used
343 * to hold the CRC is still part of the protocol, but it is ignored.  If
344 * needed, the master can turn it on with CMD59.
345 */
346int
347sdGenericStartup(int interface)
348{
349        ulong   hcs;
350        uchar   resp[16], cid[16], csd[16];
351        int             retry, rc, version;
352    struct elapsed_tmr tmr;
353        int check_pattern_retry = 2;
354
355        sdInfoTbl[interface].initialized = 0;
356
357        rc = 0;
358        check_pattern_retry = 2;
359
360        // Start with at least 74 clocks to powerup the card...
361        sdPowerup(10);
362
363        // Put card in SPI mode:
364
365        // This command always seems to fail on the first try after a
366        // powerup, so give it a few attempts...
367        for(retry=0;retry<3;retry++) {
368                if ((rc = sdCardCmd(interface,GO_IDLE_STATE,0,resp)) != -1)
369                        break;
370        }
371
372        if (retry == 3) {
373                printf("\nSD GO_IDLE_STATE failed, card installed?\n");
374                return(-1);
375        }
376
377        // According to Physical Layer Simplified Spec (PLSS), it is mandatory
378        // for the host compliant to Version 2.00 to send CMD8 (SEND_IF_COND).
379        // If CMD8 is not recognized (illegal command), then we can assume that
380        // the card is version 1.00.
381        // The argument sent with the command is defined in section 4.3.13
382        // of the PLSS. 
383        // The spec says that if the check-patter test fails, to retry...
384        do {
385                if ((rc = sdCardCmd(interface,SEND_IF_COND,SEND_IF_COND_ARG,resp)) == -1)
386                        return(-1);
387               
388                if (resp[0] & R1_ILLEGAL_CMD) {
389                        version = VERSION_10;
390                        hcs = 0;
391                        break;  // Check pattern only applies to V2 and later
392                }
393                else {
394                        // The card should echo back the VHS and check pattern...
395                        if (resp[3] != VHS27_36) {
396                                if (sdVerbose & 2)
397                                        printf("SDCARD not 3.3v compliant!\n");
398                                return(-1);
399                        }
400                        if (resp[4] != CHECK_PATTERN) {
401                                if (--check_pattern_retry <= 0) {
402                                        if (sdVerbose & 2)
403                                                printf("SDCARD check-pattern failed.\n");
404                                        return(-1);
405                                }
406                        }       
407                        version = VERSION_20;
408                        hcs = HCS;
409                }
410        } while(resp[4] != CHECK_PATTERN);
411
412        // Read OCR to make sure the card will run at 3.3v...
413        if ((rc = sdCardCmd(interface,READ_OCR,hcs,resp)) == -1)
414                return(-1);
415
416        if ((resp[2] & MSK_OCR_33) != MSK_OCR_33) {
417                if (sdVerbose & 2)
418                        printf("SDCARD: OCR_33 failed, card isn't 3.3v capable\n");
419                return(-1);
420        }
421
422        // Wait for card to complete initialization:
423    startElapsedTimer(&tmr,1000);
424        while(1) {
425                if ((rc = sdCardCmd(interface,SD_SEND_OP_COND,HCS,resp)) == -1)
426                        return(-1);
427                if ((resp[0] & R1_IDLE) == 0)
428                        break;
429        if(msecElapsed(&tmr)) {
430                        printf("SDCARD: gaveup waiting for init to complete.\n");
431                        return(-1);
432                }
433        }
434
435        if (version == VERSION_20) {
436                // Get CCS...
437                if ((rc = sdCardCmd(interface,READ_OCR,0,resp)) == -1)
438                        return(-1);
439        }
440        else {
441                if ((rc = sdCardCmd(interface,SET_BLOCKLEN,SD_BLKSIZE,resp)) == -1)
442                        return(-1);
443        }
444
445        if (sdVerbose) {
446                printf("SD/SPI Initialized (version %s)\n",
447                        version == VERSION_10 ? "1.0" : ">=2.0");
448        }
449
450        sdInfoTbl[interface].cardversion = version;
451
452        sdReadCxD(interface,cid,SEND_CID);
453        if (sdVerbose)
454                sdShowCID(cid);
455        sdReadCxD(interface,csd,SEND_CSD);
456        if (sdVerbose)
457                sdShowCSD(csd);
458
459        if ((csd[0] & 0xc0) == 0x00)
460                sdInfoTbl[interface].highcapacity = 0;
461        else
462                sdInfoTbl[interface].highcapacity = 1;
463
464        sdInfoTbl[interface].initialized = 1;
465        return(0);
466}
467
468/* Got this crc7 code off the web...
469 * The original text claimed "use-as-you-wish"...
470 */
471#define POLYNOM (0x9)        // polynomical value to XOR when 1 pops out.
472
473static unsigned char
474Encode(uchar seed, uchar input, uchar depth)
475{
476        uchar regval, count, cc;
477
478        regval = seed;
479        cc = input; 
480
481        for (count = depth ; count--   ;  cc <<= 1) {
482                regval = (regval << 1) + ((cc & 0x80) ? 1 : 0);
483                if (regval & 0x80)
484                        regval ^= POLYNOM;
485        }
486        return(regval & 0x7f); // return lower 7 bits of CRC as value to use.
487}
488
489uchar
490crc7(uchar seed, uchar *buf, int len)
491{
492        int i;
493        uchar crc;
494
495        crc = seed;
496        for (i = 0; i < len; i++)
497                crc = Encode(crc, buf[i], 8);
498
499        crc = Encode(crc,0,7);
500        crc = (crc << 1) + 1;
501        return(crc);
502}
503
504#ifdef INCLUDE_SD_DUMMY_FUNCS
505/* This code is included here just for simulating the SD
506 * interface (temporarily if a real one isn't ready.  In a real system,
507 * the INCLUDE_SD_DUMMY_FUNCS definition would be off.
508 */
509
510int
511sdInit(int interface, int verbose)
512{
513        if (interface != 0)
514                return(-1);
515
516        return(0);
517}
518
519int
520sdRead(int interface, char *buf, int blk, int blkcnt)
521{
522        char *from;
523        int     size;
524
525        if (interface != 0)
526                return(-1);
527
528        from = (char *)(blk * SD_BLKSIZE);
529        size = blkcnt * SD_BLKSIZE;
530        memcpy(buf,from,size);
531        return(0);
532}
533
534int
535sdWrite(int interface, char *buf, int blk, int blkcnt)
536{
537        char *to;
538        int     size;
539
540        if (interface != 0)
541                return(-1);
542
543        to = (char *)(blk * SD_BLKSIZE);
544        size = blkcnt * SD_BLKSIZE;
545        memcpy(to,buf,size);
546        return(0);
547}
548
549/* sdInstalled():
550 * Return 1 if installed, 0 if not installed or -1 if
551 * the hardware can't detect installation.
552 */
553int
554sdInstalled(int interface)
555{
556        return(-1);
557}
558
559#endif
560
561#endif
Note: See TracBrowser for help on using the repository browser.