source: umon/main/common/sd.c @ a7b6f00

Last change on this file since a7b6f00 was a7b6f00, checked in by Ed Sutter <edsutterjr@…>, on 08/04/15 at 01:35:50

tree cleanup using 'astyle --unpad-paren --align-pointer=name --lineend=linux --add-brackets --convert-tabs --style=knf -A4 FILENAME'

  • Property mode set to 100644
File size: 15.4 KB
Line 
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}",
93    " write {src} {blk} {blktot}",
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
122    cmd = argv[optind];
123
124    if(sdInum >= SD_DEVTOT) {
125        printf("Configured to support %d SD interface%s\n",
126               SD_DEVTOT,SD_DEVTOT == 1 ? "" : "s");
127        return(CMD_FAILURE);
128    }
129
130    if(sdInstalled(sdInum) == 0) {
131        printf("SDCard not installed\n");
132        return(CMD_FAILURE);
133    }
134
135    if(strcmp(cmd,"init") == 0) {
136        sdret = sdInit(sdInum, verbose);
137        if(sdret < 0) {
138            printf("sdInit returned %d\n",sdret);
139            return(CMD_FAILURE);
140        }
141
142        // If prefix is specified, then load shell variables:
143        if(argc == optind+2) {
144            prefix = argv[optind+1];
145            if(strlen(prefix)+4 > sizeof(varname)) {
146                printf("prefix %s too long\n",prefix);
147                return(CMD_PARAM_ERROR);
148            }
149
150            sprintf(varname,"%s_RD",prefix);
151            shell_sprintf(varname,"0x%lx",(long)sdRead);
152
153            sprintf(varname,"%s_WR",prefix);
154            shell_sprintf(varname,"0x%lx",(long)sdWrite);
155        }
156
157        shell_sprintf("SD_BLKSIZE","0x%lx",SD_BLKSIZE);
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
170        cmdnum = (uchar)strtoul(argv[optind+1],0,0);
171        if(argc == optind+3) {
172            cmdarg = strtoul(argv[optind+2],0,0);
173        }
174        sdret = sdCardCmd(sdInum, cmdnum , cmdarg ,resp);
175        if(sdret < 0) {
176            printf("sdCardCmd returned %d\n",sdret);
177            return(CMD_FAILURE);
178        }
179
180        rtot = sdCmdrlen(cmdnum);
181
182        printf("CMD_%d resp: ",cmdnum);
183        for(i=0; i<rtot; i++) {
184            printf("%02x ",resp[i]);
185        }
186        printf("\n");
187    } else if(strcmp(cmd,"read") == 0) {
188        if(argc != optind+4) {
189            return(CMD_PARAM_ERROR);
190        }
191
192        buf = (char *)strtoul(argv[optind+1],0,0);
193        blknum = strtoul(argv[optind+2],0,0);
194        blkcnt = strtoul(argv[optind+3],0,0);
195
196        sdret = sdRead(sdInum,buf,blknum,blkcnt);
197        if(sdret < 0) {
198            printf("sdRead returned %d\n",sdret);
199            return(CMD_FAILURE);
200        }
201    } else if(strcmp(cmd,"write") == 0) {
202        if(argc != optind+4) {
203            return(CMD_PARAM_ERROR);
204        }
205        buf = (char *)strtoul(argv[optind+1],0,0);
206        blknum = strtoul(argv[optind+2],0,0);
207        blkcnt = strtoul(argv[optind+3],0,0);
208
209        sdret = sdWrite(sdInum,buf,blknum,blkcnt);
210        if(sdret < 0) {
211            printf("sdWrite returned %d\n",sdret);
212            return(CMD_FAILURE);
213        }
214    } else {
215        printf("sd op <%s> not found\n",cmd);
216        return(CMD_FAILURE);
217    }
218
219    return(CMD_SUCCESS);
220}
221
222/* sdCmdrlen():
223 * Given the command number, return the response length.
224 */
225int
226sdCmdrlen(int cmd)
227{
228    struct sdcmd *sdp = sdCardCmdTbl;
229
230    while(sdp->cmd != -1) {
231        if(cmd == sdp->cmd) {
232            return(sdp->rlen);
233        }
234        sdp++;
235    }
236    return(-1);
237}
238
239/* sdCmdrtype():
240 * Given the command number, return the response type.
241 */
242int
243sdCmdrtype(int cmd)
244{
245    struct sdcmd *sdp = sdCardCmdTbl;
246
247    while(sdp->cmd != -1) {
248        if(cmd == sdp->cmd) {
249            return(sdp->rtype);
250        }
251        sdp++;
252    }
253    return(-1);
254}
255
256static char *months[] = {
257    "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
258    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
259};
260
261void
262sdShowCID(uchar *cid)
263{
264    int     year, mon;
265
266    printf("  Manufacturer ID:    x%02x\n", cid[0]);
267    printf("  OEM/Application ID: x%02x%02x\n", cid[1],cid[2]);
268    printf("  Product name:       %c%c%c%c%c\n",
269           cid[3],cid[4],cid[5],cid[6],cid[7]);
270    printf("  Product rev:        x%02x\n", cid[8]);
271    printf("  Product serialno:   x%02x%02x%02x%02x\n",
272           cid[9],cid[10],cid[11],cid[12]);
273
274    year = (((cid[13] & 0x0f) << 4) | ((cid[14] & 0xf0) >> 4));
275    mon = (cid[14] & 0x0f);
276    if((mon < 1) || (mon > 12)) {
277        mon = 0;
278    }
279    printf("  Manufactured:       %s/%d\n",months[mon],2000+year);
280}
281
282void
283sdShowCSD(uchar *csd)
284{
285    uchar csdver;
286    long long capacity;
287    int mult, csize, csm, rbl;
288    int blocknr, blocklen, i;
289
290    printf("  CSD Response: ");
291    for(i=0; i<16; i++) {
292        printf("%02x ",csd[i]);
293    }
294    printf("\n");
295
296    mult = csize = csm = rbl = 0;
297
298    if((csd[0] & 0xc0) == 0) {
299        csdver = 1;
300    } else if((csd[0] & 0xc0) == 0x40) {
301        csdver = 2;
302    } else {
303        printf("Invalid CSD structure type\n");
304        return;
305    }
306
307    printf("  CSD version %d.0\n",csdver);
308    if(csdver == 1) {
309        rbl = csd[5] & 0x0f;
310        csize = ((csd[8] & 0xC0) >> 6);
311        csize |= (csd[7] << 2);
312        csize |= ((csd[6] & 0x03) << 10);
313        csm = (csd[9] & 0x03);
314        csm <<= 1;
315        csm |= ((csd[10] & 0x80) >> 7);
316
317        mult = (1 << (csm+2));
318        blocknr = (csize+1)*mult;
319        blocklen = (1 << rbl);
320        capacity = (long long)((long long)blocknr * (long long)blocklen);
321        //printf("  (csm=%d, csize=%d, rbl=%d, mult=%d, blknr=%d, blkln=%d)\n",
322        //  csm, csize, rbl, mult, blocknr, blocklen);
323    } else if(csdver == 2) {
324        rbl = csd[5] & 0x0f;
325        csize = (csd[7] & 0x3f) << 16;
326        csize |= (csd[8] << 8);
327        csize |= csd[9];
328        capacity = (long long)((long long)(csize + 1) * 512LL * 1024LL);
329    } else {
330        printf("  Unrecognized CSD version.\n");
331        return;
332    }
333    printf("  Card capacity: %lld bytes\n",capacity);
334}
335
336/* sdGenericStartup():
337 * Called by the interface-specific sdInit() code to do the generic
338 * portion of the SD-Card initialization.
339 *
340 * Refer to the flowchart shown in figure 7.2 of the Simplified
341 * Physical Layer Specification for an overview of the initialization.
342 *
343 * The card wakes up in SD bus mode, so the first thing we need to d
344 * here (after the very basic initialization of the SPI pin config) is
345 * to get the card into SPI mode.
346 * By default, the card assumes CRC checking is disabled.  The field used
347 * to hold the CRC is still part of the protocol, but it is ignored.  If
348 * needed, the master can turn it on with CMD59.
349 */
350int
351sdGenericStartup(int interface)
352{
353    ulong   hcs;
354    uchar   resp[16], cid[16], csd[16];
355    int     retry, rc, version;
356    struct elapsed_tmr tmr;
357    int check_pattern_retry = 2;
358
359    sdInfoTbl[interface].initialized = 0;
360
361    rc = 0;
362    check_pattern_retry = 2;
363
364    // Start with at least 74 clocks to powerup the card...
365    sdPowerup(10);
366
367    // Put card in SPI mode:
368
369    // This command always seems to fail on the first try after a
370    // powerup, so give it a few attempts...
371    for(retry=0; retry<3; retry++) {
372        if((rc = sdCardCmd(interface,GO_IDLE_STATE,0,resp)) != -1) {
373            break;
374        }
375    }
376
377    if(retry == 3) {
378        printf("\nSD GO_IDLE_STATE failed, card installed?\n");
379        return(-1);
380    }
381
382    // According to Physical Layer Simplified Spec (PLSS), it is mandatory
383    // for the host compliant to Version 2.00 to send CMD8 (SEND_IF_COND).
384    // If CMD8 is not recognized (illegal command), then we can assume that
385    // the card is version 1.00.
386    // The argument sent with the command is defined in section 4.3.13
387    // of the PLSS.
388    // The spec says that if the check-patter test fails, to retry...
389    do {
390        if((rc = sdCardCmd(interface,SEND_IF_COND,SEND_IF_COND_ARG,resp)) == -1) {
391            return(-1);
392        }
393
394        if(resp[0] & R1_ILLEGAL_CMD) {
395            version = VERSION_10;
396            hcs = 0;
397            break;  // Check pattern only applies to V2 and later
398        } else {
399            // The card should echo back the VHS and check pattern...
400            if(resp[3] != VHS27_36) {
401                if(sdVerbose & 2) {
402                    printf("SDCARD not 3.3v compliant!\n");
403                }
404                return(-1);
405            }
406            if(resp[4] != CHECK_PATTERN) {
407                if(--check_pattern_retry <= 0) {
408                    if(sdVerbose & 2) {
409                        printf("SDCARD check-pattern failed.\n");
410                    }
411                    return(-1);
412                }
413            }
414            version = VERSION_20;
415            hcs = HCS;
416        }
417    } while(resp[4] != CHECK_PATTERN);
418
419    // Read OCR to make sure the card will run at 3.3v...
420    if((rc = sdCardCmd(interface,READ_OCR,hcs,resp)) == -1) {
421        return(-1);
422    }
423
424    if((resp[2] & MSK_OCR_33) != MSK_OCR_33) {
425        if(sdVerbose & 2) {
426            printf("SDCARD: OCR_33 failed, card isn't 3.3v capable\n");
427        }
428        return(-1);
429    }
430
431    // Wait for card to complete initialization:
432    startElapsedTimer(&tmr,1000);
433    while(1) {
434        if((rc = sdCardCmd(interface,SD_SEND_OP_COND,HCS,resp)) == -1) {
435            return(-1);
436        }
437        if((resp[0] & R1_IDLE) == 0) {
438            break;
439        }
440        if(msecElapsed(&tmr)) {
441            printf("SDCARD: gaveup waiting for init to complete.\n");
442            return(-1);
443        }
444    }
445
446    if(version == VERSION_20) {
447        // Get CCS...
448        if((rc = sdCardCmd(interface,READ_OCR,0,resp)) == -1) {
449            return(-1);
450        }
451    } else {
452        if((rc = sdCardCmd(interface,SET_BLOCKLEN,SD_BLKSIZE,resp)) == -1) {
453            return(-1);
454        }
455    }
456
457    if(sdVerbose) {
458        printf("SD/SPI Initialized (version %s)\n",
459               version == VERSION_10 ? "1.0" : ">=2.0");
460    }
461
462    sdInfoTbl[interface].cardversion = version;
463
464    sdReadCxD(interface,cid,SEND_CID);
465    if(sdVerbose) {
466        sdShowCID(cid);
467    }
468    sdReadCxD(interface,csd,SEND_CSD);
469    if(sdVerbose) {
470        sdShowCSD(csd);
471    }
472
473    if((csd[0] & 0xc0) == 0x00) {
474        sdInfoTbl[interface].highcapacity = 0;
475    } else {
476        sdInfoTbl[interface].highcapacity = 1;
477    }
478
479    sdInfoTbl[interface].initialized = 1;
480    return(0);
481}
482
483/* Got this crc7 code off the web...
484 * The original text claimed "use-as-you-wish"...
485 */
486#define POLYNOM (0x9)        // polynomical value to XOR when 1 pops out.
487
488static unsigned char
489Encode(uchar seed, uchar input, uchar depth)
490{
491    uchar regval, count, cc;
492
493    regval = seed;
494    cc = input;
495
496    for(count = depth ; count--   ;  cc <<= 1) {
497        regval = (regval << 1) + ((cc & 0x80) ? 1 : 0);
498        if(regval & 0x80) {
499            regval ^= POLYNOM;
500        }
501    }
502    return(regval & 0x7f); // return lower 7 bits of CRC as value to use.
503}
504
505uchar
506crc7(uchar seed, uchar *buf, int len)
507{
508    int i;
509    uchar crc;
510
511    crc = seed;
512    for(i = 0; i < len; i++) {
513        crc = Encode(crc, buf[i], 8);
514    }
515
516    crc = Encode(crc,0,7);
517    crc = (crc << 1) + 1;
518    return(crc);
519}
520
521#ifdef INCLUDE_SD_DUMMY_FUNCS
522/* This code is included here just for simulating the SD
523 * interface (temporarily if a real one isn't ready.  In a real system,
524 * the INCLUDE_SD_DUMMY_FUNCS definition would be off.
525 */
526
527int
528sdInit(int interface, int verbose)
529{
530    if(interface != 0) {
531        return(-1);
532    }
533
534    return(0);
535}
536
537int
538sdRead(int interface, char *buf, int blk, int blkcnt)
539{
540    char *from;
541    int size;
542
543    if(interface != 0) {
544        return(-1);
545    }
546
547    from = (char *)(blk * SD_BLKSIZE);
548    size = blkcnt * SD_BLKSIZE;
549    memcpy(buf,from,size);
550    return(0);
551}
552
553int
554sdWrite(int interface, char *buf, int blk, int blkcnt)
555{
556    char *to;
557    int size;
558
559    if(interface != 0) {
560        return(-1);
561    }
562
563    to = (char *)(blk * SD_BLKSIZE);
564    size = blkcnt * SD_BLKSIZE;
565    memcpy(to,buf,size);
566    return(0);
567}
568
569/* sdInstalled():
570 * Return 1 if installed, 0 if not installed or -1 if
571 * the hardware can't detect installation.
572 */
573int
574sdInstalled(int interface)
575{
576    return(-1);
577}
578
579#endif
580
581#endif
Note: See TracBrowser for help on using the repository browser.