Newer
Older
/****************************************************************************
* Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/ioctl.h>
patacongo
committed
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/fs.h>
#include <nuttx/ioctl.h>
#include <nuttx/clock.h>
#include <nuttx/arch.h>
#include "mmcsd_internal.h"
#include "mmcsd_sdio.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
patacongo
committed
/* The maximum number of references on the driver (because a uint8_t is used.
* Use a larger type if more references are needed.
*/
#define MAX_CREFS 0xff
#define MMCSD_
#define MMCSD_POWERUP_DELAY ((useconds_t)250) /* 74 clock cycles @ 400KHz = 185uS */
#define MMCSD_IDLE_DELAY ((useconds_t)50000) /* Short delay to allow change to IDLE state */
#define MMCSD_DSR_DELAY ((useconds_t)100000) /* Time to wait after setting DSR */
#define MMCSD_CLK_DELAY ((useconds_t)500000) /* Delay after changing clock speeds */
patacongo
committed
/* Data delays (all in units of milliseconds).
*
* For MMC & SD V1.x, these should be based on Nac = TAAC + NSAC; The maximum
* value of TAAC is 80MS and the maximum value of NSAC is 25.5K clock cycle.
* For SD V2.x, a fixed delay of 100MS is recommend which is preety close to
* the worst case SD V1.x Nac. Here we just use 100MS delay for all data
* transfers.
*/
#define MMCSD_SCR_DATADELAY (100) /* Wait up to 100MS to get SCR */
#define MMCSD_BLOCK_DATADELAY (100) /* Wait up to 100MS to get one data block */
#define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN)
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure is contains the unique state of the MMC/SD block driver */
struct mmcsd_state_s
{
FAR struct sdio_dev_s *dev; /* The SDIO device bound to this instance */
patacongo
committed
uint8_t crefs; /* Open references on the driver */
sem_t sem; /* Assures mutually exclusive access to the slot */
patacongo
committed
uint8_t probed:1; /* true: mmcsd_probe() discovered a card */
uint8_t widebus:1; /* true: Wide 4-bit bus selected */
uint8_t mediachanged:1; /* true: Media changed since last check */
uint8_t wrbusy:1; /* true: Last transfer was a write, card may be busy */
uint8_t wrprotect:1; /* true: Card is write protected (from CSD) */
uint8_t locked:1; /* true: Media is locked (from R1) */
uint8_t dsrimp:1; /* true: card supports CMD4/DSR setting (from CSD) */
patacongo
committed
uint8_t dma:1; /* true: hardware supports DMA */
patacongo
committed
uint8_t mode:2; /* (See MMCSDMODE_* definitions) */
uint8_t type:4; /* Card type (See MMCSD_CARDTYPE_* definitions) */
uint8_t buswidth:4; /* Bus widthes supported (SD only) */
uint16_t selblocklen; /* The currently selected block length */
uint16_t rca; /* Relative Card Address (RCS) register */
/* Memory card geometry (extracted from the CSD) */
patacongo
committed
uint8_t blockshift; /* Log2 of blocksize */
uint16_t blocksize; /* Read block length (== block size) */
size_t nblocks; /* Number of blocks */
size_t capacity; /* Total capacity of volume */
/* Read-ahead and write buffering support */
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD)
struct rwbuffer_s rwbuffer;
#endif
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Misc Helpers *************************************************************/
static void mmcsd_takesem(FAR struct mmcsd_state_s *priv);
#define mmcsd_givesem(p) sem_post(&priv->sem);
/* Command/response helpers *************************************************/
patacongo
committed
static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv,
uint32_t cmd, uint32_t arg);
static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32_t cmd);
static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32_t cmd);
static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2]);
patacongo
committed
static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv,
uint32_t csd[4]);
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
patacongo
committed
static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv,
uint32_t cid[4]);
patacongo
committed
static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv,
uint32_t scr[2]);
patacongo
committed
static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32_t *r1);
static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv,
uint32_t status);
/* Transfer helpers *********************************************************/
patacongo
committed
static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv);
static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv,
patacongo
committed
sdio_eventset_t failevents, uint32_t timeout);
static int mmcsd_transferready(FAR struct mmcsd_state_s *priv);
static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv);
static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv,
patacongo
committed
uint32_t blocklen);
static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
patacongo
committed
FAR uint8_t *buffer, off_t startblock);
static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
patacongo
committed
FAR uint8_t *buffer, off_t startblock, size_t nblocks);
patacongo
committed
static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
#endif
#ifdef CONFIG_FS_WRITABLE
static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
patacongo
committed
FAR const uint8_t *buffer, off_t startblock);
static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
patacongo
committed
FAR const uint8_t *buffer, off_t startblock, size_t nblocks);
patacongo
committed
static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
/* Block driver methods *****************************************************/
static int mmcsd_open(FAR struct inode *inode);
static int mmcsd_close(FAR struct inode *inode);
static ssize_t mmcsd_read(FAR struct inode *inode, FAR unsigned char *buffer,
size_t startsector, unsigned int nsectors);
static ssize_t mmcsd_write(FAR struct inode *inode,
FAR const unsigned char *buffer, size_t startsector,
unsigned int nsectors);
#endif
static int mmcsd_geometry(FAR struct inode *inode,
static int mmcsd_ioctl(FAR struct inode *inode, int cmd,
unsigned long arg);
/* Initialization/uninitialization/reset ************************************/
static void mmcsd_mediachange(FAR void *arg);
static int mmcsd_widebus(FAR struct mmcsd_state_s *priv);
static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv);
static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv);
static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv);
static int mmcsd_probe(FAR struct mmcsd_state_s *priv);
static int mmcsd_removed(FAR struct mmcsd_state_s *priv);
static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv);
static void mmcsd_hwuninitialize(FAR struct mmcsd_state_s *priv);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct block_operations g_bops =
{
mmcsd_open, /* open */
mmcsd_close, /* close */
mmcsd_read, /* read */
#ifdef CONFIG_FS_WRITABLE
mmcsd_write, /* write */
#else
NULL, /* write */
#endif
mmcsd_geometry, /* geometry */
mmcsd_ioctl /* ioctl */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Misc Helpers
****************************************************************************/
static void mmcsd_takesem(FAR struct mmcsd_state_s *priv)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(&priv->sem) != 0)
{
/* The only case that an error should occr here is if the wait was
* awakened by a signal.
*/
ASSERT(errno == EINTR);
}
}
/****************************************************************************
* Command/Response Helpers
****************************************************************************/
/****************************************************************************
* Name: mmcsd_sendcmdpoll
*
* Description:
* Send a command and poll-wait for the response.
*
****************************************************************************/
patacongo
committed
static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, uint32_t cmd,
uint32_t arg)
{
int ret;
/* Send the command */
SDIO_SENDCMD(priv->dev, cmd, arg);
/* Then poll-wait until the response is available */
ret = SDIO_WAITRESPONSE(priv->dev, cmd);
if (ret != OK)
{
fdbg("ERROR: Wait for response to cmd: %08x failed: %d\n", cmd, ret);
/****************************************************************************
* Name: mmcsd_sendcmdpoll
*
* Description:
* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been
* provided and (2) the card supports a DSR register. If no DSR value
* the card default value (0x0404) will be used.
*
****************************************************************************/
static inline int mmcsd_sendcmd4(FAR struct mmcsd_state_s *priv)
{
int ret = OK;
#ifdef CONFIG_MMCSD_DSR
/* The dsr_imp bit from the CSD will tell us if the card supports setting
* the DSR via CMD4 or not.
*/
patacongo
committed
if (priv->dsrimp != false)
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
{
/* CMD4 = SET_DSR will set the cards DSR register. The DSR and CMD4
* support are optional. However, since this is a broadcast command
* with no response (like CMD0), we will never know if the DSR was
* set correctly or not
*/
mmcsd_sendcmdpoll(priv, MMCSD_CMD4, CONFIG_MMCSD_DSR << 16);
up_udelay(MMCSD_DSR_DELAY);
/* Send it again to have more confidence */
mmcsd_sendcmdpoll(priv, MMCSD_CMD4, CONFIG_MMCSD_DSR << 16);
up_udelay(MMCSD_DSR_DELAY);
}
#endif
return ret;
}
/****************************************************************************
* Name: mmcsd_recvR1
*
* Description:
* Receive R1 response and check for errors.
*
****************************************************************************/
patacongo
committed
static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32_t cmd)
patacongo
committed
uint32_t r1;
ret = SDIO_RECVR1(priv->dev, cmd, &r1);
if (ret == OK)
{
/* Check if R1 reports an error */
if ((r1 & MMCSD_R1_ERRORMASK) != 0)
{
/* Card locked is considered an error. Save the card locked
* indication for later use.
*/
priv->locked = ((r1 & MMCSD_R1_CARDISLOCKED) != 0);
ret = -EIO;
}
}
return ret;
}
/****************************************************************************
* Name: mmcsd_recvR6
*
* Description:
* Receive R6 response and check for errors. On success, priv->rca is set
* to the received RCA
*
****************************************************************************/
patacongo
committed
static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32_t cmd)
patacongo
committed
uint32_t r6 = 0;
int ret;
/* R6 Published RCA Response (48-bit, SD card only)
* 47 0 Start bit
* 46 0 Transmission bit (0=from card)
* 45:40 bit5 - bit0 Command index (0-63)
* 39:8 bit31 - bit0 32-bit Argument Field, consisting of:
* [31:16] New published RCA of card
* [15:0] Card status bits {23,22,19,12:0}
* 7:1 bit6 - bit0 CRC7
* 0 1 End bit
*
* Get the R1 response from the hardware
*/
ret = SDIO_RECVR6(priv->dev, cmd, &r6);
if (ret == OK)
{
/* Check if R6 reports an error */
if ((r6 & MMCSD_R6_ERRORMASK) == 0)
{
/* No, save the RCA and return success */
patacongo
committed
priv->rca = (uint16_t)(r6 >> 16);
return OK;
}
/* Otherwise, return an I/O failure */
ret = -EIO;
}
fdbg("ERROR: Failed to get RCA. R6=%08x: %d\n", r6, ret);
return ret;
}
/****************************************************************************
* Name: mmcsd_getSCR
*
* Description:
* Obtain the SD card's Configuration Register (SCR)
*
* Returned Value:
* OK on success; a negated ernno on failure.
*
****************************************************************************/
patacongo
committed
static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2])
return ret;
}
/* Send CMD55 APP_CMD with argument as card's RCA */
patacongo
committed
mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32_t)priv->rca << 16);
ret = mmcsd_recvR1(priv, SD_CMD55);
if (ret != OK)
{
fdbg("ERROR: RECVR1 for CMD55 failed: %d\n", ret);
/* Setup up to receive data with interrupt mode */
patacongo
committed
SDIO_RECVSETUP(priv->dev, (FAR uint8_t*)scr, 8);
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */
patacongo
committed
(void)SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
mmcsd_sendcmdpoll(priv, SD_ACMD51, 0);
ret = mmcsd_recvR1(priv, SD_ACMD51);
if (ret != OK)
{
fdbg("ERROR: RECVR1 for ACMD51 failed: %d\n", ret);
patacongo
committed
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_SCR_DATADELAY);
patacongo
committed
fdbg("ERROR: mmcsd_eventwait for READ DATA failed: %d\n", ret);
}
/****************************************************************************
* Name: mmcsd_decodeCSD
*
* Description:
* Decode and extract necessary information from the CSD. If debug is
* enabled, then decode and show the full contents of the CSD.
*
* Returned Value:
* OK on success; a negated ernno on failure. On success, the following
* values will be set in the driver state structure:
*
patacongo
committed
* priv->dsrimp true: card supports CMD4/DSR setting (from CSD)
* priv->wrprotect true: card is write protected (from CSD)
* priv->nblocks Number of blocks
* priv->capacity Total capacity of volume
*
****************************************************************************/
patacongo
committed
static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
struct mmcsd_csd_s decoded;
#endif
unsigned int readbllen;
patacongo
committed
bool permwriteprotect;
bool tmpwriteprotect;
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
/* Word 1: Bits 127-96:
*
* CSD_STRUCTURE 127:126 CSD structure
* SPEC_VERS 125:122 (MMC) Spec version
* TAAC 119:112 Data read access-time-1
* TIME_VALUE 6:3 Time mantissa
* TIME_UNIT 2:0 Time exponent
* NSAC 111:104 Data read access-time-2 in CLK cycle(NSAC*100)
* TRAN_SPEED 103:96 Max. data transfer rate
* TIME_VALUE 6:3 Rate exponent
* TRANSFER_RATE_UNIT 2:0 Rate mantissa
*/
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.csdstructure = csd[0] >> 30;
decoded.mmcspecvers = (csd[0] >> 26) & 0x0f;
decoded.taac.timevalue = (csd[0] >> 19) & 0x0f;
decoded.taac.timeunit = (csd[0] >> 16) & 7;
decoded.nsac = (csd[0] >> 8) & 0xff;
decoded.transpeed.timevalue = (csd[0] >> 3) & 0x0f;
decoded.transpeed.transferrateunit = csd[0] & 7;
#endif
/* Word 2: Bits 64:95
* CCC 95:84 Card command classes
* READ_BL_LEN 83:80 Max. read data block length
* READ_BL_PARTIAL 79:79 Partial blocks for read allowed
* WRITE_BLK_MISALIGN 78:78 Write block misalignment
* READ_BLK_MISALIGN 77:77 Read block misalignment
* DSR_IMP 76:76 DSR implemented
* Byte addressed SD and MMC:
* C_SIZE 73:62 Device size
* Block addressed SD:
* 75:70 (reserved)
* C_SIZE 48:69 Device size
*/
priv->dsrimp = (csd[1] >> 12) & 1;
readbllen = (csd[1] >> 16) & 0x0f;
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.ccc = (csd[1] >> 20) & 0x0fff;
decoded.readbllen = (csd[1] >> 16) & 0x0f;
decoded.readblpartial = (csd[1] >> 15) & 1;
decoded.writeblkmisalign = (csd[1] >> 14) & 1;
decoded.readblkmisalign = (csd[1] >> 13) & 1;
decoded.dsrimp = priv->dsrimp;
#endif
/* Word 3: Bits 32-63
*
* Byte addressed SD:
* C_SIZE 73:62 Device size
* VDD_R_CURR_MIN 61:59 Max. read current at Vcc min
* VDD_R_CURR_MAX 58:56 Max. read current at Vcc max
* VDD_W_CURR_MIN 55:53 Max. write current at Vcc min
* VDD_W_CURR_MAX 52:50 Max. write current at Vcc max
* C_SIZE_MULT 49:47 Device size multiplier
* SD_ER_BLK_EN 46:46 Erase single block enable (SD only)
* SD_SECTOR_SIZE 45:39 Erase sector size
* SD_WP_GRP_SIZE 38:32 Write protect group size
* Block addressed SD:
* 75:70 (reserved)
* C_SIZE 48:69 Device size
* 47:47 (reserved)
* SD_ER_BLK_EN 46:46 Erase single block enable (SD only)
* SD_SECTOR_SIZE 45:39 Erase sector size
* SD_WP_GRP_SIZE 38:32 Write protect group size
* MMC:
* C_SIZE 73:62 Device size
* VDD_R_CURR_MIN 61:59 Max. read current at Vcc min
* VDD_R_CURR_MAX 58:56 Max. read current at Vcc max
* VDD_W_CURR_MIN 55:53 Max. write current at Vcc min
* VDD_W_CURR_MAX 52:50 Max. write current at Vcc max
* C_SIZE_MULT 49:47 Device size multiplier
* MMC_SECTOR_SIZE 46:42 Erase sector size
* MMC_ER_GRP_SIZE 41:37 Erase group size (MMC)
* MMC_WP_GRP_SIZE 36:32 Write protect group size
*/
/* Block addressed SD:
*
* C_SIZE: 69:64 from Word 2 and 63:48 from Word 3
*
* 512 = (1 << 9)
* 1024 = (1 << 10)
* 512*1024 = (1 << 19)
*/
patacongo
committed
uint32_t csize = ((csd[1] & 0x3f) << 16) | (csd[2] >> 16);
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.u.sdblock.csize = csize;
decoded.u.sdblock.sderblen = (csd[2] >> 14) & 1;
decoded.u.sdblock.sdsectorsize = (csd[2] >> 7) & 0x7f;
decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f;
#endif
/* Byte addressed SD:
*
* C_SIZE: 73:64 from Word 2 and 63:62 from Word 3
*/
patacongo
committed
uint16_t csize = ((csd[1] & 0x03ff) << 2) | ((csd[2] >> 30) & 3);
uint8_t csizemult = (csd[2] >> 15) & 7;
patacongo
committed
priv->nblocks = ((uint32_t)csize + 1) * (1 << (csizemult + 2));
priv->blockshift = readbllen;
priv->blocksize = (1 << readbllen);
priv->capacity = (priv->nblocks << readbllen);
/* Some devices, such as 2Gb devices, report blocksizes larger than 512 bytes
* but still expect to be accessed with a 512 byte blocksize.
*
* NOTE: A minor optimization would be to eliminated priv->blocksize and
* priv->blockshift: Those values will be 512 and 9 in all cases anyway.
if (priv->blocksize > 512)
{
priv->nblocks <<= (priv->blockshift - 9);
priv->blocksize = 512;
priv->blockshift = 9;
}
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
decoded.u.sdbyte.csize = csize;
decoded.u.sdbyte.vddrcurrmin = (csd[2] >> 27) & 7;
decoded.u.sdbyte.vddrcurrmax = (csd[2] >> 24) & 7;
decoded.u.sdbyte.vddwcurrmin = (csd[2] >> 21) & 7;
decoded.u.sdbyte.vddwcurrmax = (csd[2] >> 18) & 7;
decoded.u.sdbyte.csizemult = csizemult;
decoded.u.sdbyte.sderblen = (csd[2] >> 14) & 1;
decoded.u.sdbyte.sdsectorsize = (csd[2] >> 7) & 0x7f;
decoded.u.sdbyte.sdwpgrpsize = csd[2] & 0x7f;
}
#ifdef CONFIG_MMCSD_MMCSUPPORT
else if (IS_MMC(priv->type))
{
decoded.u.mmc.csize = csize;
decoded.u.mmc.vddrcurrmin = (csd[2] >> 27) & 7;
decoded.u.mmc.vddrcurrmax = (csd[2] >> 24) & 7;
decoded.u.mmc.vddwcurrmin = (csd[2] >> 21) & 7;
decoded.u.mmc.vddwcurrmax = (csd[2] >> 18) & 7;
decoded.u.mmc.csizemult = csizemult;
decoded.u.mmc.er.mmc22.sectorsize = (csd[2] >> 10) & 0x1f;
decoded.u.mmc.er.mmc22.ergrpsize = (csd[2] >> 5) & 0x1f;
decoded.u.mmc.mmcwpgrpsize = csd[2] & 0x1f;
}
#endif
#endif
}
/* Word 4: Bits 0-31
* WP_GRP_EN 31:31 Write protect group enable
* MMC DFLT_ECC 30:29 Manufacturer default ECC (MMC only)
* R2W_FACTOR 28:26 Write speed factor
* WRITE_BL_LEN 25:22 Max. write data block length
* WRITE_BL_PARTIAL 21:21 Partial blocks for write allowed
* FILE_FORMAT_GROUP 15:15 File format group
* COPY 14:14 Copy flag (OTP)
* PERM_WRITE_PROTECT 13:13 Permanent write protection
* TMP_WRITE_PROTECT 12:12 Temporary write protection
* FILE_FORMAT 10:11 File format
* ECC 9:8 ECC (MMC only)
* CRC 7:1 CRC
* Not used 0:0
*/
permwriteprotect = (csd[3] >> 13) & 1;
tmpwriteprotect = (csd[3] >> 12) & 1;
priv->wrprotect = (permwriteprotect || tmpwriteprotect);
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.wpgrpen = csd[3] >> 31;
decoded.mmcdfltecc = (csd[3] >> 29) & 3;
decoded.r2wfactor = (csd[3] >> 26) & 7;
decoded.writebllen = (csd[3] >> 22) & 0x0f;
decoded.writeblpartial = (csd[3] >> 21) & 1;
decoded.fileformatgrp = (csd[3] >> 15) & 1;
decoded.copy = (csd[3] >> 14) & 1;
decoded.permwriteprotect = permwriteprotect;
decoded.tmpwriteprotect = tmpwriteprotect;
decoded.fileformat = (csd[3] >> 10) & 3;
decoded.mmcecc = (csd[3] >> 8) & 3;
decoded.crc = (csd[3] >> 1) & 0x7f;
fvdbg("CSD:\n");
fvdbg(" CSD_STRUCTURE: %d SPEC_VERS: %d (MMC)\n",
decoded.csdstructure, decoded.mmcspecvers);
fvdbg(" TAAC {TIME_UNIT: %d TIME_VALUE: %d} NSAC: %d\n",
decoded.taac.timeunit, decoded.taac.timevalue, decoded.nsac);
fvdbg(" TRAN_SPEED {TRANSFER_RATE_UNIT: %d TIME_VALUE: %d}\n",
decoded.transpeed.transferrateunit, decoded.transpeed.timevalue);
fvdbg(" CCC: %d\n", decoded.ccc);
fvdbg(" READ_BL_LEN: %d READ_BL_PARTIAL: %d\n",
decoded.readbllen, decoded.readblpartial);
fvdbg(" WRITE_BLK_MISALIGN: %d READ_BLK_MISALIGN: %d\n",
decoded.writeblkmisalign, decoded.readblkmisalign);
fvdbg(" DSR_IMP: %d\n",
decoded.dsrimp);
{
fvdbg(" SD Block Addressing:\n");
fvdbg(" C_SIZE: %d SD_ER_BLK_EN: %d\n",
decoded.u.sdblock.csize, decoded.u.sdblock.sderblen);
fvdbg(" SD_SECTOR_SIZE: %d SD_WP_GRP_SIZE: %d\n",
decoded.u.sdblock.sdsectorsize, decoded.u.sdblock.sdwpgrpsize);
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
else if (IS_SD(priv->type))
{
fvdbg(" SD Byte Addressing:\n");
fvdbg(" C_SIZE: %d C_SIZE_MULT: %d\n",
decoded.u.sdbyte.csize, decoded.u.sdbyte.csizemult);
fvdbg(" VDD_R_CURR_MIN: %d VDD_R_CURR_MAX: %d\n",
decoded.u.sdbyte.vddrcurrmin, decoded.u.sdbyte.vddrcurrmax);
fvdbg(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n",
decoded.u.sdbyte.vddwcurrmin, decoded.u.sdbyte.vddwcurrmax);
fvdbg(" SD_ER_BLK_EN: %d SD_SECTOR_SIZE: %d (SD) SD_WP_GRP_SIZE: %d\n",
decoded.u.sdbyte.sderblen, decoded.u.sdbyte.sdsectorsize, decoded.u.sdbyte.sdwpgrpsize);
}
#ifdef CONFIG_MMCSD_MMCSUPPORT
else if (IS_MMC(priv->type))
{
fvdbg(" MMC:\n");
fvdbg(" C_SIZE: %d C_SIZE_MULT: %d\n",
decoded.u.mmc.csize, decoded.u.mmc.csizemult);
fvdbg(" VDD_R_CURR_MIN: %d VDD_R_CURR_MAX: %d\n",
decoded.u.mmc.vddrcurrmin, decoded.u.mmc.vddrcurrmax);
fvdbg(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n",
decoded.u.mmc.vddwcurrmin, decoded.u.mmc.vddwcurrmax);
fvdbg(" MMC_SECTOR_SIZE: %d MMC_ER_GRP_SIZE: %d MMC_WP_GRP_SIZE: %d\n",
decoded.u.mmc.er.mmc22.sectorsize, decoded.u.mmc.er.mmc22.ergrpsize,
decoded.u.mmc.mmcwpgrpsize);
}
#endif
fvdbg(" WP_GRP_EN: %d MMC DFLT_ECC: %d (MMC) R2W_FACTOR: %d\n",
decoded.wpgrpen, decoded.mmcdfltecc, decoded.r2wfactor);
fvdbg(" WRITE_BL_LEN: %d WRITE_BL_PARTIAL: %d\n",
decoded.writebllen, decoded.writeblpartial);
fvdbg(" FILE_FORMAT_GROUP: %d COPY: %d\n",
decoded.fileformatgrp, decoded.copy);
fvdbg(" PERM_WRITE_PROTECT: %d TMP_WRITE_PROTECT: %d\n",
decoded.permwriteprotect, decoded.tmpwriteprotect);
fvdbg(" FILE_FORMAT: %d ECC: %d (MMC) CRC: %d\n",
decoded.fileformat, decoded.mmcecc, decoded.crc);
fvdbg("Capacity: %dKb, Block size: %db, nblocks: %d wrprotect: %d\n",
priv->capacity / 1024, priv->blocksize, priv->nblocks, priv->wrprotect);
}
/****************************************************************************
* Show the contents of the Card Indentification Data (CID) (for debug
* purposes only)
*
****************************************************************************/
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
patacongo
committed
static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv, uint32_t cid[4])
{
struct mmcsd_cid_s decoded;
/* Word 1: Bits 127-96:
* mid - 127-120 8-bit Manufacturer ID
* oid - 119-104 16-bit OEM/Application ID (ascii)
* pnm - 103-64 40-bit Product Name (ascii) + null terminator
* pnm[0] 103:96
*/
decoded.mid = cid[0] >> 24;
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
decoded.pnm[0] = cid[0] & 0xff;
/* Word 2: Bits 64:95
* pnm - 103-64 40-bit Product Name (ascii) + null terminator
* pnm[1] 95:88
* pnm[2] 87:80
* pnm[3] 79:72
* pnm[4] 71:64
*/
decoded.pnm[1] = cid[1] >> 24;
decoded.pnm[2] = (cid[1] >> 16) & 0xff;
decoded.pnm[3] = (cid[1] >> 8) & 0xff;
decoded.pnm[4] = cid[1] & 0xff;
decoded.pnm[5] = '\0';
/* Word 3: Bits 32-63
* prv - 63-56 8-bit Product revision
* psn - 55-24 32-bit Product serial number
*/
decoded.prv = cid[2] >> 24;
decoded.psn = cid[2] << 8;
/* Word 4: Bits 0-31
* psn - 55-24 32-bit Product serial number
* 23-20 4-bit (reserved)
* mdt - 19:8 12-bit Manufacturing date
* crc - 7:1 7-bit CRC7
*/
decoded.mdt = (cid[3] >> 8) & 0x0fff;
decoded.crc = (cid[3] >> 1) & 0x7f;
fvdbg("mid: %02x oid: %04x pnm: %s prv: %d psn: %d mdt: %02x crc: %02x\n",
decoded.mid, decoded.oid, decoded.pnm, decoded.prv,
decoded.psn, decoded.mdt, decoded.crc);
/****************************************************************************
* Name: mmcsd_decodeSCR
*
* Description:
* Show the contents of the SD Configuration Register (SCR). The only
* value retained is: priv->buswidth;
*
****************************************************************************/
patacongo
committed
static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2])
{
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
struct mmcsd_scr_s decoded;
#endif
/* Word 1, bits 63:32
* SCR_STRUCTURE 63:60 4-bit SCR structure version
* SD_VERSION 59:56 4-bit SD memory spec. version
* DATA_STATE_AFTER_ERASE 55:55 1-bit erase status
* SD_SECURITY 54:52 3-bit SD security support level
* SD_BUS_WIDTHS 51:48 4-bit bus width indicator
* Reserved 47:32 16-bit SD reserved space
*/
#ifdef CONFIG_ENDIAN_BIG /* Card transfers SCR in big-endian order */
#else
priv->buswidth = (scr[0] >> 8) & 15;
#endif
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
#ifdef CONFIG_ENDIAN_BIG /* Card SCR is big-endian order / CPU also big-endian
* 60 56 52 48 44 40 36 32
* VVVV SSSS ESSS BBBB RRRR RRRR RRRR RRRR */
decoded.scrversion = scr[0] >> 28;
decoded.sdversion = (scr[0] >> 24) & 15;
decoded.erasestate = (scr[0] >> 23) & 1;
decoded.security = (scr[0] >> 20) & 7;
#else /* Card SCR is big-endian order / CPU is little-endian
* 36 32 44 40 52 48 60 56
* RRRR RRRR RRRR RRRR ESSS BBBB VVVV SSSS */
decoded.scrversion = (scr[0] >> 4) & 15;
decoded.sdversion = scr[0] & 15;
decoded.erasestate = (scr[0] >> 15) & 1;
decoded.security = (scr[0] >> 12) & 7;
#endif
decoded.buswidth = priv->buswidth;
#endif
/* Word 1, bits 63:32
* Reserved 31:0 32-bits reserved for manufacturing usage.
*/
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.mfgdata = scr[1]; /* Might be byte reversed! */
fvdbg("SCR:\n");
fvdbg(" SCR_STRUCTURE: %d SD_VERSION: %d\n",
decoded.scrversion,decoded.sdversion);
fvdbg(" DATA_STATE_AFTER_ERASE: %d SD_SECURITY: %d SD_BUS_WIDTHS: %x\n",
decoded.erasestate, decoded.security, decoded.buswidth);
fvdbg(" Manufacturing data: %08x\n",
decoded.mfgdata);
#endif
}
/****************************************************************************
* Name: mmcsd_getR1
*
* Description:
* Get the R1 status of the card using CMD13
*
****************************************************************************/
patacongo
committed
static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32_t *r1)
patacongo
committed
uint32_t localR1;
int ret;
DEBUGASSERT(priv != NULL && r1 != NULL);
/* Send CMD13, SEND_STATUS. The addressed card responds by sending its
* R1 card status register.
*/
mmcsd_sendcmdpoll(priv, MMCSD_CMD13, (uint32_t)priv->rca << 16);
ret = SDIO_RECVR1(priv->dev, MMCSD_CMD13, &localR1);
if (ret == OK)
{
/* Check if R1 reports an error */
if ((localR1 & MMCSD_R1_ERRORMASK) != 0)
{
/* Card locked is considered an error. Save the card locked
* indication for later use.
*/
priv->locked = ((localR1 & MMCSD_R1_CARDISLOCKED) != 0);
ret = -EIO;
}
else
{
/* No errors, return R1 */
*r1 = localR1;
}
}
return ret;
}
/****************************************************************************
* Name: mmcsd_verifystate
*
****************************************************************************/
patacongo
committed
static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, uint32_t state)
patacongo
committed
uint32_t r1;
int ret;
/* Get the current R1 status from the card */
ret = mmcsd_getR1(priv, &r1);
if (ret != OK)
{
fdbg("ERROR: mmcsd_getR1 failed: %d\n", ret);
return ret;
}
/* Now check if the card is in the expected state. */
if (IS_STATE(r1, state))
{
/* Yes.. return Success */
patacongo
committed
priv->wrbusy = false;
return OK;
}
return -EINVAL;
/****************************************************************************
* Transfer Helpers
****************************************************************************/
/****************************************************************************
* Name: mmcsd_wrprotected
*
* Description:
* Return true if the the card is unlocked an not write protected. The
*
*
****************************************************************************/