/*
* Copyright (c) 2015 Jarielle Catbagan <jcatbagan93@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "stddefs.h"
#include "am335x.h"
#include "sd.h"
uint16_t sdrca;
int
sdcmd(uint32_t cmd, uint32_t arg, uint32_t resp[4])
{
/* Clear the SD_STAT register for proper update of status bits after CMD invocation */
MMCHS0_REG(SD_STAT) = 0xFFFFFFFF;
MMCHS0_REG(SD_ARG) = arg;
MMCHS0_REG(SD_CMD) = cmd;
/* CMDx complete? */
while (!(MMCHS0_REG(SD_STAT) & (SD_STAT_CC | SD_STAT_ERRI)));
resp[0] = MMCHS0_REG(SD_RSP10);
resp[1] = MMCHS0_REG(SD_RSP32);
resp[2] = MMCHS0_REG(SD_RSP54);
resp[3] = MMCHS0_REG(SD_RSP76);
/* CMDx error? */
if (MMCHS0_REG(SD_STAT) & SD_STAT_ERRI)
return(-1);
else
return(0);
}
int
sdCardCmd(int interface, int cmd, unsigned long arg, unsigned char *resp)
{
return(-1);
}
int
sdInit(int interface, int verbosity)
{
uint32_t cmd, arg, resp[4];
/* Reset the MMC/SD controller */
MMCHS0_REG(SD_SYSCONFIG) = SD_SYSCONFIG_SOFTRESET;
while (!(MMCHS0_REG(SD_SYSSTATUS) & SD_SYSSTATUS_RESETDONE));
/* Reset the command and data lines */
MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_SRA;
while (MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_SRA);
/* Configure the MMC/SD controller capabilities to enable 3.0 V operating voltage */
MMCHS0_REG(SD_CAPA) = SD_CAPA_VS30;
/* Configure SD_IE register to update certain status bits in SD_STAT */
MMCHS0_REG(SD_IE) = SD_IE_BADA_ENABLE | SD_IE_CERR_ENABLE | SD_IE_ACE_ENABLE |
SD_IE_DEB_ENABLE | SD_IE_DCRC_ENABLE | SD_IE_DTO_ENABLE | SD_IE_CIE_ENABLE |
SD_IE_CEB_ENABLE | SD_IE_CCRC_ENABLE | SD_IE_CIRQ_ENABLE | SD_IE_CREM_ENABLE |
SD_IE_CINS_ENABLE | SD_IE_BRR_ENABLE | SD_IE_BWR_ENABLE |
SD_IE_TC_ENABLE | SD_IE_CC_ENABLE;
/* Disable open-drain mode (only used for MMC cards) and 8-bit data width */
MMCHS0_REG(SD_CON) &= ~(SD_CON_OD | SD_CON_DW8);
/* Configure the operating voltage to 3.0 V */
MMCHS0_REG(SD_HCTL) &= ~(SD_HCTL_SDVS);
MMCHS0_REG(SD_HCTL) |= SD_HCTL_SDVS_VS30;
/* Set the data width to 4-bits */
MMCHS0_REG(SD_HCTL) |= SD_HCTL_DTW;
/* Turn on the bus */
MMCHS0_REG(SD_HCTL) |= SD_HCTL_SDBP;
while (!(MMCHS0_REG(SD_HCTL) & SD_HCTL_SDBP));
/* Enable the internal clock */
MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_ICE;
/* Configure Clock Frequency Select to 100 KHz */
MMCHS0_REG(SD_SYSCTL) = (MMCHS0_REG(SD_SYSCTL) & ~(SD_SYSCTL_CLKD)) | (960 << 6);
/* Wait for clock to stabilize */
while (!(MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_ICS));
/* Configure SD_SYSCONFIG */
MMCHS0_REG(SD_SYSCONFIG) &= ~(SD_SYSCONFIG_CLOCKACTIVITY | SD_SYSCONFIG_SIDLEMODE);
MMCHS0_REG(SD_SYSCONFIG) |= SD_SYSCONFIG_SIDLEMODE_WKUP | SD_SYSCONFIG_ENAWAKEUP_ENABLE |
SD_SYSCONFIG_AUTOIDLE_AUTOGATE;
/* Enable the clock to the SD card */
MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_CEN_ENABLE;
/* Perform the Initialization Stream as specified in the AM335x TRM, Section 18.3.3.2
"Card Detection, Identicication, and Selection" */
MMCHS0_REG(SD_CON) |= SD_CON_INIT;
/* Clear the SD_STAT register */
MMCHS0_REG(SD_STAT) = 0xFFFFFFFF;
MMCHS0_REG(SD_ARG) = 0x00000000;
MMCHS0_REG(SD_CMD) = 0x00000000;
while (!(MMCHS0_REG(SD_STAT) & SD_STAT_CC));
/* Clear CC flag in SD_STAT */
MMCHS0_REG(SD_STAT) |= SD_STAT_CC;
MMCHS0_REG(SD_CON) &= ~SD_CON_INIT;
/* Change the clock frequency to 6 MHz and set the DTO to the maximum value setting */
MMCHS0_REG(SD_SYSCTL) &= ~SD_SYSCTL_DTO;
MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_DTO_TCF_2_27;
MMCHS0_REG(SD_SYSCTL) = (MMCHS0_REG(SD_SYSCTL) & ~SD_SYSCTL_CLKD) | (16 << 6);
/* Wait for clock to stabilize */
while ((MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_ICS) != SD_SYSCTL_ICS);
/* Send CMD0/GO_IDLE_STATE to reset the SD card connected to MMC0 interface */
arg = 0x00000000;
cmd = SD_CMD_CMD0_GO_IDLE_STATE | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_DISABLE | SD_CMD_CCCE_DISABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Send CMD8/SEND_IF_COND to verify that the SD card satisfies MMC/SD controller
requirements */
arg = 0x00000188;
cmd = SD_CMD_CMD8_SEND_IF_COND | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R7;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Determine what type of SD card is connected, i.e. standard capacity, high capacity, etc.
* We perform a CMD55/ACMD41 loop until the "Card power up status bit" is set in the OCR
* register from the SD card to determine when we have a valid response */
do {
arg = 0x00000000;
cmd = SD_CMD_CMD55_APP_CMD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
arg = 0x40060000;
cmd = SD_CMD_ACMD41_SD_SEND_OP_COND | SD_CMD_CMD_TYPE_NORMAL |
SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_DISABLE | SD_CMD_CCCE_DISABLE |
SD_CMD_RSP_TYPE_R3;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while (!(resp[0] & SD_RSP10_R3_CARD_POWER_UP_STATUS));
/* Check SD_RSP10 to determine whether the card connected is high capacity or not */
if (resp[0] & SD_RSP10_R3_CARD_CAPACITY_STATUS)
sdInfoTbl[interface].highcapacity = 1;
else
sdInfoTbl[interface].highcapacity = 0;
/* Send CMD2 to get SD's CID and to put the card into Identification State */
arg = 0x00000000;
cmd = SD_CMD_CMD2_ALL_SEND_CID | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_DISABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R2;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Send CMD3, i.e. request new relative address (RCA) and to put the card into
Stand-by State */
arg = 0x00000000;
cmd = SD_CMD_CMD3_SEND_RELATIVE_ADDR | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R6;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Save the RCA published from the SD card, this will be used in future CMDx commands */
sdrca = (MMCHS0_REG(SD_RSP10) >> 16) & 0xFFFF;
/* Wait for the SD card to enter Stand-by State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
/* Put the card with the RCA obtained previously into Transfer State via CMD7 */
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1B;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for the SD card to enter Transfer State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
/* Set the bus-width to 4-bits */
/* Send CMD55 to get ready to configure the bus-width via ACMD6 */
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD55_APP_CMD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Send ACMD6, SET_BUS_WIDTH to set the bus-width to 4-bits */
arg = 0x00000002;
cmd = SD_CMD_ACMD6_SET_BUS_WIDTH | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Put the SD card into Stand-by State */
arg = 0x00000000;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for the SD card to enter Stand-by State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
/* This point is reached when SD controller initialization and SD card
communication is successful */
return(0);
}
int
sdRead(int interface, char *buf, int blknum, int blkcount)
{
uint32_t cmd, arg, resp[4];
uint32_t *wordptr = (uint32_t *) buf;
int byteindex;
/* Get the SD card's status via CMD13 */
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Ensure that the card is in Transfer State before proceeding */
if ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER) {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL |
SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
SD_CMD_RSP_TYPE_R1B;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for the SD card to enter Transfer State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL |
SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
}
/* Set the block length and the number of blocks to read */
MMCHS0_REG(SD_BLK) = SD_BLKSIZE | (blkcount << 16);
/* Send CMD18, i.e. read multiple blocks */
arg = blknum;
cmd = SD_CMD_CMD18_READ_MULTIPLE_BLOCK | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1 | SD_CMD_MSBS_MULTIPLE |
SD_CMD_DDIR_READ | SD_CMD_ACEN_CMD12_ENABLE | SD_CMD_BCE_ENABLE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Check the data buffer to see if there is data to be read */
do {
while (!(MMCHS0_REG(SD_STAT) & SD_STAT_BRR));
/* Clear the BRR status bit in SD_STAT */
MMCHS0_REG(SD_STAT) |= SD_STAT_BRR;
for (byteindex = 0; byteindex < (SD_BLKSIZE / 4); byteindex++) {
*wordptr = (MMCHS0_REG(SD_DATA));
wordptr++;
}
} while (!(MMCHS0_REG(SD_STAT) & SD_STAT_TC));
/* Put the SD card into Stand-by State */
arg = 0;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for the SD card to enter Stand-by State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
return(0);
}
int
sdWrite(int interface, char *buf, int blknum, int blkcount)
{
uint32_t cmd, arg, resp[4];
uint32_t *wordptr = (uint32_t *) buf;
int byteindex;
/* Get the SD card's status by sending CMD13 */
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Ensure that the card is in the Transfer State before proceeding */
if ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER) {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL |
SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
SD_CMD_RSP_TYPE_R1B;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for SD card to enter Transfer State */
do {
arg = (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL |
SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
}
/* Set the block length in bytes and the number of blocks to write to the SD card */
MMCHS0_REG(SD_BLK) = SD_BLKSIZE | ( blkcount << 16);
/* Send CMD25, that is write the number of blocks specified in 'blkcount' from 'buf' to the
* location that is 512 byte aligned in the SD card specified by the block number 'blknum'
*/
arg = blknum;
cmd = SD_CMD_CMD25_WRITE_MULTIPLE_BLOCK | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1 | SD_CMD_MSBS_MULTIPLE |
SD_CMD_DDIR_WRITE | SD_CMD_ACEN_CMD12_ENABLE | SD_CMD_BCE_ENABLE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Write the data */
do {
/* Wait until data is ready to be written */
while (!(MMCHS0_REG(SD_STAT) & (SD_STAT_BWR | SD_STAT_TC)));
if (MMCHS0_REG(SD_STAT) & SD_STAT_TC)
break;
/* Clear the BWR status bit in SD_STAT */
MMCHS0_REG(SD_STAT) |= SD_STAT_BWR;
for (byteindex = 0; byteindex < (SD_BLKSIZE / 4); byteindex++)
MMCHS0_REG(SD_DATA) = *wordptr++;
} while (!(MMCHS0_REG(SD_STAT) & SD_STAT_TC));
/* Put the SD card into Stand-by State */
arg = 0x00000000;
cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
/* Wait for SD card to enter Stand-by State */
do {
arg= (sdrca << 16) & 0xFFFF0000;
cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
if (sdcmd(cmd, arg, resp) == -1)
return(-1);
} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
return(0);
}
int
sdInstalled(int interface)
{
if ((MMCHS0_REG(SD_CON) & SD_CON_CDP) == SD_CON_CDP_ACTIVE_HIGH)
if (MMCHS0_REG(SD_PSTATE) & SD_PSTATE_CINS)
return(1);
else
return(0);
else
if (MMCHS0_REG(SD_PSTATE) & SD_PSTATE_CINS)
return(0);
else
return(1);
}
int
sdPowerup(int tot)
{
return(-1);
}
int
sdReadCxD(int interface, unsigned char *buf, int cmd)
{
return(-1);
}