[PATCH 5/8] BBB: Add am335x_mmc.c and am335x_mmc.h that implement "mmc" command with initialization functionality

Jarielle Catbagan jcatbagan93 at gmail.com
Tue Aug 4 18:03:25 UTC 2015


---
 ports/beagleboneblack/am335x_mmc.c | 347 +++++++++++++++++++++++++++++++++++++
 ports/beagleboneblack/am335x_mmc.h |  13 ++
 2 files changed, 360 insertions(+)
 create mode 100644 ports/beagleboneblack/am335x_mmc.c
 create mode 100644 ports/beagleboneblack/am335x_mmc.h

diff --git a/ports/beagleboneblack/am335x_mmc.c b/ports/beagleboneblack/am335x_mmc.c
new file mode 100644
index 0000000..f045fec
--- /dev/null
+++ b/ports/beagleboneblack/am335x_mmc.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2015 Jarielle Catbagan <jcatbagan93 at 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 "genlib.h"
+#include "cli.h"
+#include "stddefs.h"
+#include "am335x.h"
+#include "am335x_mmc.h"
+
+uint16_t mmcrca;
+int mmcInum;
+
+char *mmcHelp[] = {
+	"MultiMediaCard Interface",
+	"[options] {operation} [args]...",
+#if INCLUDE_VERBOSEHELP
+	"",
+	"Options:",
+	" -i ##	interface # (default is 0)",
+	" -v 	additive verbosity",
+	"",
+	"Operations:",
+	" init",
+	" read {dest} {blk} {blktot}",
+	" write {source} {blk} {blktot}",
+#endif /* INCLUDE_VERBOSEHELP */
+	0
+};
+
+int
+mmccmd(uint32_t cmd, uint32_t arg, uint32_t resp[4])
+{
+	/* Clear the SD_STAT register for proper update of status bits after CMD invocation */
+	MMC1_REG(SD_STAT) = 0xFFFFFFFF;
+
+	MMC1_REG(SD_ARG) = arg;
+	MMC1_REG(SD_CMD) = cmd;
+
+	/* CMDx complete? */
+	while (!(MMC1_REG(SD_STAT) & (SD_STAT_CC | SD_STAT_ERRI)));
+
+	resp[0] = MMC1_REG(SD_RSP10);
+	resp[1] = MMC1_REG(SD_RSP32);
+	resp[2] = MMC1_REG(SD_RSP54);
+	resp[3] = MMC1_REG(SD_RSP76);
+
+	/* CMDx error? */
+	if (MMC1_REG(SD_STAT) & SD_STAT_ERRI)
+		return(-1);
+	else
+		return(0);
+}
+
+int
+mmc(int argc, char *argv[])
+{
+	char *cmd, *buf;
+	int opt, verbose, mmcret, blknum, blkcnt;
+
+	verbose = 0;
+
+	while ((opt = getopt(argc, argv, "i:v")) != -1) {
+		switch (opt) {
+			case 'i':
+				mmcInum = atoi(optarg);
+				break;
+			case 'v':
+				verbose++;
+				break;
+			default:
+				return(CMD_PARAM_ERROR);
+		}
+	}
+
+	if (argc < optind + 1)
+		return(CMD_PARAM_ERROR);
+
+	cmd = argv[optind];
+
+	if (mmcInstalled(mmcInum) == 0) {
+		printf("MMC not installed\n");
+		return(CMD_FAILURE);
+	}
+
+	if (strcmp(cmd, "init") == 0) {
+		mmcret = mmcInit(mmcInum, verbose);
+		if(mmcret < 0) {
+			printf("mmcInit returned %d\n", mmcret);
+			return(CMD_FAILURE);
+		}
+	}
+	else if (strcmp(cmd, "read") == 0) {
+		if (argc != (optind + 4))
+			return(CMD_PARAM_ERROR);
+
+		buf = (char *)strtoul(argv[optind + 1], 0, 0);
+		blknum = strtoul(argv[optind + 2], 0, 0);
+		blkcnt = strtoul(argv[optind + 3], 0, 0);
+
+		mmcret = mmcRead(mmcInum, buf, blknum, blkcnt);
+		if (mmcret < 0) {
+			printf("mmcRead returned %d\n", mmcret);
+			return(CMD_FAILURE);
+		}
+	}
+	else if (strcmp(cmd, "write") == 0) {
+		if (argc != (optind + 4))
+			return(CMD_PARAM_ERROR);
+
+		buf = (char *)strtoul(argv[optind + 1], 0, 0);
+		blknum = strtoul(argv[optind + 2], 0, 0);
+		blkcnt = strtoul(argv[optind + 3], 0, 0);
+
+		mmcret = mmcWrite(mmcInum, buf, blknum, blkcnt);
+		if (mmcret < 0) {
+			printf("mmcWrite returned %d\n", mmcret);
+			return(CMD_FAILURE);
+		}
+	}
+	else {
+		printf("mmc op <%s> not found\n", cmd);
+		return(CMD_FAILURE);
+	}
+
+	return(CMD_SUCCESS);
+}
+
+int
+mmcInit(int interface, int verbose)
+{
+	uint32_t cmd, arg, resp[4];
+
+	/* Enable MMC1 clocks */
+	CM_PER_REG(CM_PER_MMC1_CLKCTRL) |= CM_PER_MMC1_CLKCTRL_MODULEMODE_ENABLE;
+	while (CM_PER_REG(CM_PER_MMC1_CLKCTRL) & CM_PER_MMC0_CLKCTRL_IDLEST);
+
+	/* Reset the MMC1 Controller */
+	MMC1_REG(SD_SYSCONFIG) = SD_SYSCONFIG_SOFTRESET;
+	while (!(MMC1_REG(SD_SYSSTATUS) & SD_SYSSTATUS_RESETDONE));
+
+	/* Reset the command and data lines */
+	MMC1_REG(SD_SYSCTL) |= SD_SYSCTL_SRA;
+	while (MMC1_REG(SD_SYSCTL) & SD_SYSCTL_SRA);
+
+	/* Configure the MMC1 controller capabilities to enable 3.0 V operating voltage */
+	MMC1_REG(SD_CAPA) |= SD_CAPA_VS30;
+
+	/* Configure SD_IE register to update certain status bits in SD_STAT */
+	MMC1_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;
+
+	/* Configure the operating voltage to 3.0 V */
+	MMC1_REG(SD_HCTL) &= ~(SD_HCTL_SDVS);
+	MMC1_REG(SD_HCTL) |= SD_HCTL_SDVS_VS30;
+
+	/* Turn on the bus */
+	MMC1_REG(SD_HCTL) |= SD_HCTL_SDBP;
+	while (!(MMC1_REG(SD_HCTL) & SD_HCTL_SDBP));
+
+	/* Enable the internal clock */
+	MMC1_REG(SD_SYSCTL) |= SD_SYSCTL_ICE;
+
+	/* Configure Clock Frequency Select to 100 KHz */
+	MMC1_REG(SD_SYSCTL) = (MMC1_REG(SD_SYSCTL) & ~SD_SYSCTL_CLKD) | (960 << 6);
+
+	/* Wait for clock to stabilize */
+	while (!(MMC1_REG(SD_SYSCTL) & SD_SYSCTL_ICS));
+
+	/* Configure SD_SYSCONFIG */
+	MMC1_REG(SD_SYSCONFIG) &= ~(SD_SYSCONFIG_CLOCKACTIVITY | SD_SYSCONFIG_SIDLEMODE);
+	MMC1_REG(SD_SYSCONFIG) |= SD_SYSCONFIG_SIDLEMODE_WKUP | SD_SYSCONFIG_ENAWAKEUP_ENABLE |
+		SD_SYSCONFIG_AUTOIDLE_AUTOGATE;
+
+	/* Enable the clock to the eMMC */
+	MMC1_REG(SD_SYSCTL) |= SD_SYSCTL_CEN;
+
+	/* Perform the Initialization Stream as specified in the AM335x TRM, Section 18.3.3.2
+	   "Card Detection, Identification, and Selection" */
+	MMC1_REG(SD_CON) |= SD_CON_INIT;
+	/* Clear the SD_STAT register */
+	MMC1_REG(SD_STAT) = 0xFFFFFFFF;
+	MMC1_REG(SD_ARG) = 0x00000000;
+	MMC1_REG(SD_CMD) = 0x00000000;
+	while (!(MMC1_REG(SD_STAT) & SD_STAT_CC));
+	/* Clear CC flag in SD_STAT */
+	MMC1_REG(SD_STAT) |= SD_STAT_CC;
+	MMC1_REG(SD_CON) &= ~SD_CON_INIT;
+
+	/* Clear the SD_STAT register */
+	MMC1_REG(SD_STAT) = 0xFFFFFFFF;
+
+	/* Enable open-drain mode until we enter Stand-by State as illustrated in the
+	   JEDEC JESD84-A43 Embedded MultiMediaCard Product Standard specification, Table 5 */
+	MMC1_REG(SD_CON) |= SD_CON_OD;
+
+	/* Send CMD0/GO_IDLE_STATE to reset the eMMC on MMC1 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 (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+
+	/* Send CMD1 and poll busy bit in response */
+	do {
+		arg = 0x40FF8000;
+		cmd = SD_CMD_CMD1_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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while (!(MMC1_REG(SD_RSP10) & 0x80000000));
+
+	/* Send CMD2, i.e. ALL_SEND_CID */
+	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 (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+
+	/* Set RCA of eMMC */
+	mmcrca = 0x3A3A;
+
+	/* Send CMD3 to set the relative card address (RCA) of the eMMC */
+	arg = (mmcrca << 16) & 0xFFFF0000;
+	cmd = SD_CMD_CMD3_SET_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_R1;
+	if (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+
+	/* Wait for the eMMC to enter Stand-by State */
+	do {
+		/* Send CMD13 to get the status of the MMC */
+		arg = (mmcrca << 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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
+
+	/* Disable open-drain mode */
+	MMC1_REG(SD_CON) &= ~SD_CON_OD;
+
+	/* Send CMD7 to put the eMMC into Transfer State */
+	arg = (mmcrca << 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_R1;
+	if (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+
+	/* Wait for eMMC to enter Transfer State */
+	do {
+		/* Send CMD13 to get the status of the eMMC */
+		arg = (mmcrca << 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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
+
+	/* Send CMD6 to change bus-width to 8-bits */
+	arg = (3 << 24) | (183 << 16) | (2 << 8);
+	cmd = SD_CMD_CMD6_SWITCH | 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 (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+	while (!(MMC1_REG(SD_STAT) & SD_STAT_TC));
+
+	/* Wait while CMD6 is still in effect, i.e. while eMMC is not in Transfer State */
+	do {
+		arg = (mmcrca << 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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
+
+	/* Configure the MMC1 controller to use an 8-bit data width */
+	MMC1_REG(SD_CON) |= SD_CON_DW8_8BIT;
+
+	/* Send CMD6 to change to high-speed mode */
+	arg = 0x03B90100;
+	cmd = SD_CMD_CMD6_SWITCH | 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 (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+	while (!(MMC1_REG(SD_STAT) & SD_STAT_TC));
+
+	/* Wait while CMD6 is still in effect, i.e. while eMMC is not in Transfer State */
+	do {
+		arg = (mmcrca << 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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
+
+	/* Change the clock frequency to 48 MHz and set the DTO to the maximum value setting */
+	MMC1_REG(SD_SYSCTL) &= ~SD_SYSCTL_DTO;
+	MMC1_REG(SD_SYSCTL) |= SD_SYSCTL_DTO_TCF_2_27;
+	MMC1_REG(SD_SYSCTL) = (MMC1_REG(SD_SYSCTL) & ~SD_SYSCTL_CLKD) | (2 << 6);
+
+	/* Wait for clock to stabilize */
+	while ((MMC1_REG(SD_SYSCTL) & SD_SYSCTL_ICS) != SD_SYSCTL_ICS);
+
+	/* Put the eMMC 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_DISABLE | SD_CMD_CCCE_DISABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
+	if (mmccmd(cmd, arg, resp) == -1)
+		return(-1);
+
+	/* Wait for the eMMC to enter Stand-by State */
+	do {
+		arg = (mmcrca << 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 (mmccmd(cmd, arg, resp) == -1)
+			return(-1);
+	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);
+
+	return(0);
+}
+
+int
+mmcRead(int interface, char *buf, int blknum, int blkcnt)
+{
+	return(-1);
+}
+
+int
+mmcWrite(int interface, char *buf, int blknum, int blkcnt)
+{
+	return(-1);
+}
+
+int
+mmcInstalled(int interface)
+{
+	return(1);
+}
diff --git a/ports/beagleboneblack/am335x_mmc.h b/ports/beagleboneblack/am335x_mmc.h
new file mode 100644
index 0000000..aae1b16
--- /dev/null
+++ b/ports/beagleboneblack/am335x_mmc.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 Jarielle Catbagan <jcatbagan93 at 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
+ */
+
+int mmc(int argc, char *argv[]);
+int mmcInit(int interface, int verbose);
+int mmcRead(int interface, char *buf, int blknum, int blkcnt);
+int mmcWrite(int interface, char *buf, int blknum, int blkcnt);
+int mmcInstalled(int interface);
-- 
2.5.0



More information about the umon-devel mailing list