summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorMartin LUNDHOLM <martin.xa.lundholm@stericsson.com>2010-08-23 17:31:29 +0200
committerMichael BRANDT <michael.brandt@stericsson.com>2010-08-30 19:39:16 +0200
commit3a5b27b58258ff61dfae3167bc46fed0146ddffd (patch)
treef185f10ccb07c693998340343afc4a680949aea7 /board
parent6e7432129841a6177b097c5d2388c6aa9ed257c3 (diff)
U-boot: MMC update.
MMC has been updated with several improvements. Primarily MMC performance has been improved by using assembler code for low level FIFO handling. Also some MMC functionality has been added, e.g. support for DDR and reliable write. Data and command delay times were incremented, otherwise hangups and timeouts were observed. Tested on HREF+ 1.1 V21 and HREF+ 1.1 V32 (Micron PoP). Following WP depends on this change (more reliable SD card write support): ST-Ericsson ID: WP264488 Change-Id: Ic92abffe1640aa9375b8d43a6b8522ca8296a368 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/4056 Reviewed-by: Michael BRANDT <michael.brandt@stericsson.com> Tested-by: Michael BRANDT <michael.brandt@stericsson.com>
Diffstat (limited to 'board')
-rw-r--r--board/st/u8500/Makefile4
-rw-r--r--board/st/u8500/mmc_fifo.S146
-rw-r--r--board/st/u8500/mmc_fifo.h45
-rw-r--r--board/st/u8500/mmc_host.c295
-rw-r--r--board/st/u8500/mmc_host.h9
-rw-r--r--board/st/u8500/mmc_utils.c14
6 files changed, 352 insertions, 161 deletions
diff --git a/board/st/u8500/Makefile b/board/st/u8500/Makefile
index c151f72b5..3bd3a7a37 100644
--- a/board/st/u8500/Makefile
+++ b/board/st/u8500/Makefile
@@ -22,15 +22,17 @@
include $(TOPDIR)/config.mk
-CFLAGS += -D__RELEASE -D__STN_8500
LIB = $(obj)lib$(BOARD).a
COBJS := u8500.o flash.o gpio.o u8500_i2c.o mmc_host.o mmc_utils.o clock.o prcmu.o mcde_display.o mcde_hw.o ab8500vibra.o
+SOBJS := mmc_fifo.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
SOBJS := $(addprefix $(obj),$(SOBJS))
+$(obj)mmc_host.o: CFLAGS += -O2
+
$(LIB): $(obj).depend $(OBJS) $(SOBJS)
$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
diff --git a/board/st/u8500/mmc_fifo.S b/board/st/u8500/mmc_fifo.S
new file mode 100644
index 000000000..44911a8d5
--- /dev/null
+++ b/board/st/u8500/mmc_fifo.S
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include "mmc_fifo.h"
+#include "mmc_host.h"
+
+/*
+ * Function: mmc_fifo_read()
+ *
+ * int mmc_fifo_read(u32 *fifo, u32 *buf, unsigned int count, u32 *status_reg)
+ *
+ * Info: Reads data from an MMC (ARM PL180) FIFO
+ *
+ * Parameters:
+ * fifo - pointer to the first PL180 FIFO register
+ * buf - pointer to a read buffer (32-bit aligned)
+ * count - number of bytes to be read (32-bit aligned)
+ * status_reg - pointer to the PL180 status register
+ *
+ * Returns '0' if success and PL180 status on failure.
+ *
+ */
+
+ .globl mmc_fifo_read
+mmc_fifo_read:
+ push {r4-r10,lr}
+mmc_fifo_read_loop_32_1:
+ /* If count is <32B read word-wise */
+ cmp r2,#32
+ blo mmc_fifo_read_loop_4_1
+mmc_fifo_read_loop_32_2:
+ /* Load SDI_STA to r4 */
+ ldr r4,[r3]
+ /* Exit if SDI_STA_DCRCFAIL or SDI_STA_DTIMEOUT is set */
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_read_fail
+ /* Wait until SDI_STA_RXFIFOBR is set */
+ tst r4,#SDI_STA_RXFIFOBR
+ beq mmc_fifo_read_loop_32_2
+ /* Load and store 8 words */
+ ldmia r0,{r4-r10,lr}
+ stmia r1!,{r4-r10,lr}
+ subs r2,r2,#32
+ b mmc_fifo_read_loop_32_1
+mmc_fifo_read_loop_4_1:
+ /* Read word wise */
+ cmp r2,#4
+ blo mmc_fifo_read_ok
+mmc_fifo_read_loop_4_2:
+ /* Load SDI_STA to r4 */
+ ldr r4,[r3]
+ /* Exit if SDI_STA_DCRCFAIL or SDI_STA_DTIMEOUT is set */
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_read_fail
+ /* Wait until SDI_STA_RXDAVL is set */
+ tst r4,#SDI_STA_RXDAVL
+ beq mmc_fifo_read_loop_4_2
+ /* Load and store 1 word */
+ ldmia r0,{r4}
+ stmia r1!,{r4}
+ subs r2,r2,#4
+ b mmc_fifo_read_loop_4_1
+mmc_fifo_read_ok:
+ /* Wait until SDI_STA_DBCKEND and SDI_STA_DATAEND are set */
+ ldr r4,[r3]
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_read_fail
+ and r5,r4,#(SDI_STA_DBCKEND | SDI_STA_DATAEND)
+ cmp r5,#(SDI_STA_DBCKEND | SDI_STA_DATAEND)
+ bne mmc_fifo_read_ok
+mmc_fifo_read_fail:
+ mov r0,r4
+ pop {r4-r10,pc}
+
+/*
+ * Function: mmc_fifo_write()
+ *
+ * int mmc_fifo_write(u32 *buf, u32 *fifo, unsigned int count, u32 *status_reg)
+ *
+ * Info: Writes data to an MMC (ARM PL180) FIFO
+ *
+ * Parameters:
+ * buf - pointer to a write buffer (32-bit aligned)
+ * fifo - pointer to the first PL180 FIFO register
+ * count - number of bytes to be written (32-bit aligned)
+ * status_reg - pointer to the PL180 status register
+ *
+ * Returns '0' if success and PL180 status on failure.
+ *
+ */
+
+ .globl mmc_fifo_write
+mmc_fifo_write:
+ push {r4-r10,lr}
+mmc_fifo_write_loop_32_1:
+ /* If count is <32B read word-wise */
+ cmp r2,#32
+ blo mmc_fifo_write_loop_4_1
+mmc_fifo_write_loop_32_2:
+ /* Load SDI_STA to r4 */
+ ldr r4,[r3]
+ /* Exit if SDI_STA_DCRCFAIL or SDI_STA_DTIMEOUT is set */
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_write_fail
+ /* Wait until SDI_STA_TXFIFOBW is set */
+ tst r4,#SDI_STA_TXFIFOBW
+ beq mmc_fifo_write_loop_32_2
+ /* Load and store 8 words */
+ ldmia r0!,{r4-r10,lr}
+ stmia r1,{r4-r10,lr}
+ subs r2,r2,#32
+ b mmc_fifo_write_loop_32_1
+mmc_fifo_write_loop_4_1:
+ /* Read word wise */
+ cmp r2,#4
+ blo mmc_fifo_write_ok
+mmc_fifo_write_loop_4_2:
+ /* Load SDI_STA to r4 */
+ ldr r4,[r3]
+ /* Exit if SDI_STA_DCRCFAIL or SDI_STA_DTIMEOUT is set */
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_write_fail
+ /* Wait until SDI_STA_TXFIFOBW is set */
+ tst r4,#SDI_STA_TXFIFOBW
+ beq mmc_fifo_write_loop_4_2
+ /* Load and store 1 word */
+ ldmia r0!,{r4}
+ stmia r1,{r4}
+ subs r2,r2,#4
+ b mmc_fifo_write_loop_4_1
+mmc_fifo_write_ok:
+ /* Wait until SDI_STA_DBCKEND and SDI_STA_DATAEND are set */
+ ldr r4,[r3]
+ ands r5,r4,#(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT)
+ bne mmc_fifo_write_fail
+ and r5,r4,#(SDI_STA_DBCKEND | SDI_STA_DATAEND)
+ cmp r5,#(SDI_STA_DBCKEND | SDI_STA_DATAEND)
+ bne mmc_fifo_write_ok
+mmc_fifo_write_fail:
+ mov r0,r4
+ pop {r4-r10,pc}
diff --git a/board/st/u8500/mmc_fifo.h b/board/st/u8500/mmc_fifo.h
new file mode 100644
index 000000000..e2fb0a53b
--- /dev/null
+++ b/board/st/u8500/mmc_fifo.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <common.h>
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Function: mmc_fifo_read()
+ *
+ * Info: Reads data from an MMC (ARM PL180) FIFO
+ *
+ * Parameters:
+ * fifo - pointer to the first PL180 FIFO register
+ * buf - pointer to a read buffer (32-bit aligned)
+ * count - number of bytes to be read (32-bit aligned)
+ * status_reg - pointer to the PL180 status register
+ *
+ * Returns '0' if success and PL180 status on failure.
+ *
+ */
+int mmc_fifo_read(u32 *fifo, u32 *buf, unsigned int count, u32 *status_reg);
+
+/*
+ * Function: mmc_fifo_write()
+ *
+ * Info: Writes data to an MMC (ARM PL180) FIFO
+ *
+ * Parameters:
+ * buf - pointer to a write buffer (32-bit aligned)
+ * fifo - pointer to the first PL180 FIFO register
+ * count - number of bytes to be written (32-bit aligned)
+ * status_reg - pointer to the PL180 status register
+ *
+ * Returns '0' if success and PL180 status on failure.
+ *
+ */
+int mmc_fifo_write(u32 *buf, u32 *fifo, unsigned int count, u32 *status_reg);
+
+#endif /* __ASSEMBLY__ */
diff --git a/board/st/u8500/mmc_host.c b/board/st/u8500/mmc_host.c
index 9bf319504..df46eb02c 100644
--- a/board/st/u8500/mmc_host.c
+++ b/board/st/u8500/mmc_host.c
@@ -7,13 +7,20 @@
* License terms: GNU General Public License (GPL), version 2.
*/
-/*#define DEBUG*/
+/*
+ * There are two levels of debug printouts in this file. The macro DEBUG can be
+ * set to either DBG_LVL_INFO (1) or DBG_LVL_VERBOSE (2).
+ */
+#define DBG_LVL_INFO (1)
+#define DBG_LVL_VERBOSE (2)
#include "common.h"
#include <mmc.h>
-#include "gpio.h" /* two copies of gpio.h exists - why? */
+#include "gpio.h"
#include "mmc_host.h"
#include <malloc.h>
+#include <div64.h>
+#include "mmc_fifo.h"
struct mmc_host {
struct sdi_registers *base;
@@ -21,7 +28,7 @@ struct mmc_host {
/*
* wait_for_command_end() - waiting for the command completion
- * this function will wait till the command completion has happened or
+ * this function will wait until the command completion has happened or
* any error generated by reading the status register
*/
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
@@ -39,15 +46,15 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
hoststatus = readl(&host->base->status) & statusmask;
while (!hoststatus);
- debug("SDI_ICR <= 0x%08X\n", statusmask);
+ debugX(DBG_LVL_VERBOSE, "SDI_ICR <= 0x%08X\n", statusmask);
writel(statusmask, &host->base->status_clear);
if (hoststatus & SDI_STA_CTIMEOUT) {
- debug("CMD%d time out\n", cmd->cmdidx);
+ debugX(DBG_LVL_VERBOSE, "CMD%d time out\n", cmd->cmdidx);
return TIMEOUT;
} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
(cmd->flags & MMC_RSP_CRC)) {
- debug("CMD%d CRC error\n", cmd->cmdidx);
+ debugX(DBG_LVL_VERBOSE, "CMD%d CRC error\n", cmd->cmdidx);
return MMC_CMD_CRC_FAIL;
}
@@ -56,7 +63,8 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
cmd->response[1] = readl(&host->base->response1);
cmd->response[2] = readl(&host->base->response2);
cmd->response[3] = readl(&host->base->response3);
- debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
+ debugX(DBG_LVL_VERBOSE,
+ "CMD%d response[0]:0x%08X, response[1]:0x%08X, "
"response[2]:0x%08X, response[3]:0x%08X\n",
cmd->cmdidx, cmd->response[0], cmd->response[1],
cmd->response[2], cmd->response[3]);
@@ -72,8 +80,10 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
int result;
u32 sdi_cmd = 0;
struct mmc_host *host = dev->priv;
+ u32 lap = 0;
- debug("Request to do CMD%d on %s\n", cmd->cmdidx, dev->name);
+ debugX(DBG_LVL_VERBOSE, "Request to do CMD%d on %s\n", cmd->cmdidx,
+ dev->name);
sdi_cmd = (cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN;
@@ -83,13 +93,24 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
sdi_cmd |= SDI_CMD_LONGRESP;
}
- debug("SDI_ARG <= 0x%08X\n", cmd->cmdarg);
+ debugX(DBG_LVL_VERBOSE, "SDI_ARG <= 0x%08X\n", cmd->cmdarg);
writel((u32)cmd->cmdarg, &host->base->argument);
udelay(COMMAND_REG_DELAY); /* DONT REMOVE */
- debug("SDI_CMD <= 0x%08X\n", sdi_cmd);
- writel(sdi_cmd, &host->base->command);
-
- result = wait_for_command_end(dev, cmd);
+ debugX(DBG_LVL_VERBOSE, "SDI_CMD <= 0x%08X\n", sdi_cmd);
+
+ /*
+ * It has been noticed that after a write operation some cards does
+ * not respond to a new command for a few milliseconds. So here we
+ * retry the command a couple of times if we get a timeout.
+ */
+ do {
+ writel(sdi_cmd, &host->base->command);
+ result = wait_for_command_end(dev, cmd);
+ if ((result != TIMEOUT) || (lap >= 10))
+ break;
+ udelay(1000);
+ lap++;
+ } while (1);
/* After CMD2 set RCA to a none zero value. */
if ((result == MMC_OK) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
@@ -98,7 +119,7 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
/* After CMD3 open drain is switched off and push pull is used. */
if ((result == MMC_OK) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
- debug("SDI_PWR <= 0x%08X\n", sdi_pwr);
+ debugX(DBG_LVL_VERBOSE, "SDI_PWR <= 0x%08X\n", sdi_pwr);
writel(sdi_pwr, &host->base->power);
}
@@ -121,76 +142,28 @@ static int convert_from_bytes_to_power_of_two(unsigned int x)
*/
static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
{
- u32 *tempbuff = dest;
- int i;
u64 xfercount = blkcount * blksize;
struct mmc_host *host = dev->priv;
u32 status;
- u32 status_err;
-
- debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
-
- status = readl(&host->base->status);
- status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
- while (!status_err &&
- (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32))) {
- if (status & SDI_STA_RXFIFOBR) {
- for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
- *(tempbuff + i) = readl(&host->base->fifo);
- tempbuff += SDI_FIFO_BURST_SIZE;
- xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
- }
- status = readl(&host->base->status);
- status_err = status &
- (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
- }
-
- if (status & SDI_STA_DTIMEOUT) {
- printf("Reading data timedout, xfercount:%llu,"
- "status:0x%08X\n", xfercount, status);
- return MMC_DATA_TIMEOUT;
- } else if (status & SDI_STA_DCRCFAIL) {
- printf("Reading data CRC error\n");
- return MMC_DATA_CRC_FAIL;
- }
- while ((!status_err) && (xfercount >= sizeof(u32))) {
- if (status & SDI_STA_RXDAVL) {
- *(tempbuff) = readl(&host->base->fifo);
- tempbuff++;
- xfercount -= sizeof(u32);
- }
- status = readl(&host->base->status);
- status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
- }
+ debugX(DBG_LVL_VERBOSE, "read_bytes: blkcount=%u blksize=%u\n",
+ blkcount, blksize);
- /* Wait for DBCKEND */
- status_err = status &
- (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
- while (!status_err) {
- status = readl(&host->base->status);
- status_err = status &
- (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
- }
+ status = mmc_fifo_read(&host->base->fifo, dest, xfercount,
+ &host->base->status);
- if (status & SDI_STA_DTIMEOUT) {
- printf("Reading data timedout, xfercount:%llu,"
- "status:0x%08X\n", xfercount, status);
- return MMC_DATA_TIMEOUT;
- } else if (status & SDI_STA_DCRCFAIL) {
- printf("Reading data CRC error\n");
- return MMC_DATA_CRC_FAIL;
+ if (status & (SDI_STA_DTIMEOUT | SDI_STA_DCRCFAIL)) {
+ printf("Reading data failed: status:0x%08X\n", status);
+ if (status & SDI_STA_DTIMEOUT)
+ return MMC_DATA_TIMEOUT;
+ else if (status & SDI_STA_DCRCFAIL)
+ return MMC_DATA_CRC_FAIL;
}
- debug("SDI_ICR <= 0x%08X\n", SDI_ICR_MASK);
+ debugX(DBG_LVL_VERBOSE, "SDI_ICR <= 0x%08X\n", SDI_ICR_MASK);
writel(SDI_ICR_MASK, &host->base->status_clear);
- debug("Reading loop ended\n");
-
- if (xfercount) {
- printf("Reading data error, xfercount:%llu",
- (unsigned long long) xfercount);
- return MMC_GENERAL_UNKNOWN_ERROR;
- }
+ debugX(DBG_LVL_VERBOSE, "Reading data completed status:0x%08X\n",
+ status);
return MMC_OK;
}
@@ -200,65 +173,33 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
*/
static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
{
- u32 *tempbuff = src;
- int i;
u64 xfercount = blkcount * blksize;
struct mmc_host *host = dev->priv;
u32 status;
- u32 status_err;
-
- debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
-
- status = readl(&host->base->status);
- status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
- while (!status_err && xfercount) {
- if (status & SDI_STA_TXFIFOBW) {
- if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
- for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
- writel(*(tempbuff + i),
- &host->base->fifo);
- tempbuff += SDI_FIFO_BURST_SIZE;
- xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
- } else {
- while (xfercount >= sizeof(u32)) {
- writel(*(tempbuff), &host->base->fifo);
- tempbuff++;
- xfercount -= sizeof(u32);
- }
- }
- }
- status = readl(&host->base->status);
- status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
- }
+ u32 status_busy;
- /* Wait for DBCKEND */
- status_err = status &
- (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
- while (!status_err) {
- status = readl(&host->base->status);
- status_err = status &
- (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
- }
+ debugX(DBG_LVL_VERBOSE, "write_bytes: blkcount=%u blksize=%u\n",
+ blkcount, blksize);
- if (status & SDI_STA_DTIMEOUT) {
- printf(
- "Writing data timedout, xfercount:%llu,status:0x%08X\n",
- xfercount, status);
- return MMC_DATA_TIMEOUT;
- } else if (status & SDI_STA_DCRCFAIL) {
- printf("Writing data CRC error\n");
- return MMC_DATA_CRC_FAIL;
+ status = mmc_fifo_write(src, &host->base->fifo, xfercount,
+ &host->base->status);
+
+ if (status & (SDI_STA_DTIMEOUT | SDI_STA_DCRCFAIL)) {
+ printf("Writing data failed: status=0x%08X\n", status);
+ if (status & SDI_STA_DTIMEOUT)
+ return MMC_DATA_TIMEOUT;
+ else if (status & SDI_STA_DCRCFAIL)
+ return MMC_DATA_CRC_FAIL;
}
+ /* Wait if busy */
+ status_busy = status & SDI_STA_CARDBUSY;
+ while (status_busy)
+ status_busy = readl(&host->base->status) & SDI_STA_CARDBUSY;
writel(SDI_ICR_MASK, &host->base->status_clear);
- debug("Writing data loop completed status:0x%08X\n", status);
-
- if (xfercount) {
- printf("Writing data error, xfercount:%llu",
- (unsigned long long) xfercount);
- return MMC_GENERAL_UNKNOWN_ERROR;
- }
+ debugX(DBG_LVL_VERBOSE, "Writing data completed status:0x%08X\n",
+ status);
return MMC_OK;
}
@@ -280,8 +221,13 @@ static int do_data_transfer(struct mmc *dev,
u32 data_ctrl = 0;
u32 data_len = (u32) (data->blocks * data->blocksize);
- debug("Request to do data xfer on %s\n", dev->name);
- debug("do_data_transfer(%u) start\n", data->blocks);
+ debugX(DBG_LVL_VERBOSE, "Request to do data xfer on %s\n", dev->name);
+ debugX(DBG_LVL_VERBOSE, "do_data_transfer(%u) start\n", data->blocks);
+
+#if (DEBUG >= DBG_LVL_INFO)
+ if (data->blocks > 1)
+ reset_timer();
+#endif
if (cpu_is_u8500v1() || u8500_is_earlydrop()) {
blksz = convert_from_bytes_to_power_of_two(data->blocksize);
@@ -290,20 +236,31 @@ static int do_data_transfer(struct mmc *dev,
blksz = data->blocksize;
data_ctrl |= (blksz << INDEX(SDI_DCTRL_DBLOCKSIZE_V2_MASK));
}
-
- data_ctrl |= SDI_DCTRL_DTEN;
-
- debug("SDI_DTIMER <= 0x%08X\n", SDI_DTIMER_DEFAULT);
- writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
- debug("SDI_DLEN <= 0x%08X\n", data_len);
+ data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
+ if (dev->ddr_en &&
+ ((cmd->cmdidx == MMC_CMD_READ_SINGLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_WRITE_SINGLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_SEND_EXT_CSD)))
+ data_ctrl |= SDI_DCTRL_DDR_MODE;
+
+#if (DEBUG >= DBG_LVL_VERBOSE)
+ if (data_ctrl & SDI_DCTRL_DDR_MODE)
+ printf("SDI_DCTRL_DDR_MODE\n");
+#endif
+
+ debugX(DBG_LVL_VERBOSE, "SDI_DTIMER <= 0x%08X\n", dev->data_timeout);
+ writel(dev->data_timeout, &host->base->datatimer);
+ debugX(DBG_LVL_VERBOSE, "SDI_DLEN <= 0x%08X\n", data_len);
writel(data_len, &host->base->datalength);
udelay(DATA_REG_DELAY); /* DONT REMOVE */
if (data->flags & (MMC_DATA_READ)) {
- debug("It is a read operation\n");
+ debugX(DBG_LVL_VERBOSE, "It is a read operation\n");
data_ctrl |= SDI_DCTRL_DTDIR_IN;
- debug("SDI_DCTRL <= 0x%08X\n", data_ctrl);
+ debugX(DBG_LVL_VERBOSE, "SDI_DCTRL <= 0x%08X\n", data_ctrl);
writel(data_ctrl, &host->base->datactrl);
error = do_command(dev, cmd);
@@ -315,13 +272,13 @@ static int do_data_transfer(struct mmc *dev,
(u32)data->blocks,
(u32)data->blocksize);
} else if (data->flags & (MMC_DATA_WRITE)) {
- debug("It is a write operation\n");
+ debugX(DBG_LVL_VERBOSE, "It is a write operation\n");
error = do_command(dev, cmd);
if (error)
return error;
- debug("SDI_DCTRL <= 0x%08X\n", data_ctrl);
+ debugX(DBG_LVL_VERBOSE, "SDI_DCTRL <= 0x%08X\n", data_ctrl);
writel(data_ctrl, &host->base->datactrl);
error = write_bytes(dev,
@@ -330,7 +287,24 @@ static int do_data_transfer(struct mmc *dev,
(u32)data->blocksize);
}
- debug("do_data_transfer() end\n");
+#if (DEBUG >= DBG_LVL_INFO)
+ if (data->blocks > 1) {
+ u32 transfer_time = (u32) get_timer_us();
+ u64 throughput = lldiv((u64) 1000 * 1000 * data->blocks *
+ data->blocksize, transfer_time);
+ printf("MMC %s: %u bytes in %u [us] => %llu [B/s] = "
+ "%llu [kB/s] = %llu.%02u [MB/s] = %llu [Mbits/s]\n",
+ (data->flags & (MMC_DATA_READ)) ? "read" : "write",
+ data->blocks * data->blocksize,
+ transfer_time,
+ throughput, throughput / 1024,
+ throughput / (1024 * 1024),
+ (u32)((100 * throughput) / (1024 * 1024) -
+ (throughput / (1024 * 1024)) * 100),
+ throughput * 8 / (1024 * 1024));
+ }
+#endif
+ debugX(DBG_LVL_VERBOSE, "do_data_transfer() end\n");
return error;
}
@@ -365,7 +339,7 @@ static int mmc_host_reset(struct mmc *dev)
struct mmc_host *host = dev->priv;
u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
- debug("SDI_PWR <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_PWR <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->power);
return MMC_OK;
}
@@ -376,6 +350,8 @@ static int mmc_host_reset(struct mmc *dev)
*/
static int sd_host_reset(struct mmc *dev)
{
+ (void) dev; /* Parameter not used! */
+
return MMC_OK;
}
/*
@@ -396,7 +372,8 @@ static void host_set_ios(struct mmc *dev)
u32 clkdiv = 0;
u32 tmp_clock;
- debug("setting clock and bus width in the host:");
+ debugX(DBG_LVL_VERBOSE,
+ "setting clock and bus width in the host:");
if (dev->clock >= dev->f_max) {
clkdiv = 0;
dev->clock = dev->f_max;
@@ -437,7 +414,10 @@ static void host_set_ios(struct mmc *dev)
sdi_clkcr |= buswidth;
}
- debug("SDI_CLKCR <= 0x%08X\n", sdi_clkcr);
+
+ dev->data_timeout = MMC_DATA_TIMEOUT * dev->clock;
+
+ debugX(DBG_LVL_VERBOSE, "SDI_CLKCR <= 0x%08X\n", sdi_clkcr);
writel(sdi_clkcr, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
}
@@ -466,7 +446,7 @@ static int host_poweroff(struct mmc *dev)
{
struct mmc_host *host = dev->priv;
u32 sdi_pwr = ~SDI_PWR_PWRCTRL_ON;
- debug("SDI_PWR <= 0x%08X\n", sdi_pwr);
+ debugX(DBG_LVL_VERBOSE, "SDI_PWR <= 0x%08X\n", sdi_pwr);
writel(sdi_pwr, &host->base->power);
return 0;
}
@@ -485,7 +465,7 @@ static int emmc_host_init(struct mmc *dev)
/* TODO: Investigate what is actually needed of the below. */
if (u8500_is_earlydrop()) {
- debug("configuring EMMC for ED\n");
+ debugX(DBG_LVL_VERBOSE, "configuring EMMC for ED\n");
/* Initialize the gpio alternate function for eMMC */
struct gpio_register *p_gpio_register =
(void *)IO_ADDRESS(CFG_GPIO_6_BASE);
@@ -502,7 +482,7 @@ static int emmc_host_init(struct mmc *dev)
host->base = (struct sdi_registers *)CFG_EMMC_BASE_ED;
} else {
- debug("configuring EMMC for V1\n");
+ debugX(DBG_LVL_VERBOSE, "configuring EMMC for V1\n");
/* enable the alternate function of PoP EMMC */
gpioerror = gpio_altfuncenable(GPIO_ALT_POP_EMMC, "EMMC");
if (gpioerror != GPIO_OK) {
@@ -515,15 +495,15 @@ static int emmc_host_init(struct mmc *dev)
}
sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
- debug("SDI_PWR <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_PWR <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->power);
/* setting clk freq less than 400KHz */
sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN;
- debug("SDI_CLKCR <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_CLKCR <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
- debug("SDI_MASK0 <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_MASK0 <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->mask0);
dev->clock = MCLK / (2 + SDI_CLKCR_CLKDIV_INIT);
sprintf(dev->name, "EMMC");
@@ -531,10 +511,11 @@ static int emmc_host_init(struct mmc *dev)
dev->set_ios = host_set_ios;
dev->init = mmc_host_reset;
dev->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS |
- MMC_MODE_HS_52MHz;
+ MMC_MODE_HS_52MHz /* | MMC_MODE_REL_WR | MMC_MODE_DDR */;
dev->voltages = VOLTAGE_WINDOW_MMC;
dev->f_min = dev->clock;
dev->f_max = MCLK / 2;
+ dev->ddr_en = 0;
return 0;
end:
@@ -573,23 +554,23 @@ static int mmc_host_init(struct mmc *dev)
host->base = (struct sdi_registers *)CFG_MMC_BASE;
sdi_u32 = 0xBF;
- debug("SDI_PWR <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_PWR <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->power);
/* setting clk freq just less than 400KHz */
sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN;
- debug("SDI_CLKCR <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_CLKCR <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
- debug("SDI_MASK0 <= 0x%08X\n", sdi_u32);
+ debugX(DBG_LVL_VERBOSE, "SDI_MASK0 <= 0x%08X\n", sdi_u32);
writel(sdi_u32, &host->base->mask0);
dev->clock = MCLK / (2 + SDI_CLKCR_CLKDIV_INIT);
sprintf(dev->name, "MMC");
dev->send_cmd = host_request;
dev->set_ios = host_set_ios;
dev->init = sd_host_reset;
- dev->host_caps = /*MMC_MODE_4BIT*/ 0; /* Some SD cards do not work in
- 4 bit mode! */
+ dev->host_caps = /* MMC_MODE_4BIT */ 0; /* Some SD cards do not work in
+ 4 bit mode! */
dev->voltages = VOLTAGE_WINDOW_SD;
dev->f_min = dev->clock;
dev->f_max = MCLK / 2;
@@ -610,7 +591,9 @@ int board_mmc_init(bd_t *bis)
int error;
struct mmc *dev;
- debug("mmc_host - board_mmc_init\n");
+ debugX(DBG_LVL_VERBOSE, "mmc_host - board_mmc_init\n");
+
+ (void) bis; /* Parameter not used! */
dev = alloc_mmc_struct();
if (!dev)
@@ -622,7 +605,7 @@ int board_mmc_init(bd_t *bis)
return -1;
}
mmc_register(dev);
- debug("registered emmc interface number is:%d\n",
+ debugX(DBG_LVL_VERBOSE, "registered emmc interface number is:%d\n",
dev->block_dev.dev);
dev = alloc_mmc_struct();
@@ -635,7 +618,7 @@ int board_mmc_init(bd_t *bis)
return -1;
}
mmc_register(dev);
- debug("registered mmc/sd interface number is:%d\n",
+ debugX(DBG_LVL_VERBOSE, "registered mmc/sd interface number is:%d\n",
dev->block_dev.dev);
return 0;
diff --git a/board/st/u8500/mmc_host.h b/board/st/u8500/mmc_host.h
index b33351f09..3b5e1c589 100644
--- a/board/st/u8500/mmc_host.h
+++ b/board/st/u8500/mmc_host.h
@@ -13,10 +13,11 @@
/* See SDI (SD card host interface) documentation in U8500 sw specification. */
#define COMMAND_REG_DELAY 300
-#define DATA_REG_DELAY 1000
+#define DATA_REG_DELAY 10000
#define CLK_CHANGE_DELAY 2000
#define MAX_ERROR_VALUE -65
+#ifndef __ASSEMBLY__
enum mmc_result {
/* MMC specific error defines */
MMC_CMD_CRC_FAIL = (MAX_ERROR_VALUE - 1),/* Command response received
@@ -95,6 +96,7 @@ enum mmc_result {
MMC_NO_MORE_FILTER_PENDING_EVENT = 5,
MMC_NO_PENDING_EVENT_ERROR = 7,
};
+#endif
#define MCLK (100*1000*1000)
@@ -185,7 +187,8 @@ enum mmc_result {
#define SDI_CMD_CE_ATACMD (0x00004000)
#define SDI_CMD_CBOOTMODEEN (0x00008000)
-#define SDI_DTIMER_DEFAULT (0xFFFF0000)
+/* MMC_DATA_TIMEOUT sets the data timeout in seconds */
+#define MMC_DATA_TIMEOUT (30)
/* SDI Status register bits */
@@ -261,6 +264,7 @@ enum mmc_result {
#define SDI_FIFO_BURST_SIZE (8)
+#ifndef __ASSEMBLY__
struct sdi_registers {
u32 power; /* 0x00*/
u32 clock; /* 0x04*/
@@ -293,5 +297,6 @@ struct sdi_registers {
u32 pcell_id2; /* 0xFF8*/
u32 pcell_id3; /* 0xFFC*/
};
+#endif
#endif
diff --git a/board/st/u8500/mmc_utils.c b/board/st/u8500/mmc_utils.c
index af5f0475d..b630e8adb 100644
--- a/board/st/u8500/mmc_utils.c
+++ b/board/st/u8500/mmc_utils.c
@@ -66,12 +66,12 @@ static struct partition partitions_v1[] = {
[0] = PART(0x83, 0x000A0000, 0x00004000), /* Kernel */
[1] = PART(0x83, 0x000A4000, 0x00080000), /* Root file system */
[2] = PART(0x83, 0x001FF800, 0x00000800), /* Modem parameters */
- [3] = {0},
+ [3] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
#undef PART
-int write_partition_block(void)
+int write_partition_block(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int err;
u32 offset = PIB_EMMC_ADDR;
@@ -79,6 +79,11 @@ int write_partition_block(void)
u8 emmc_existing_partition[512];
struct mmc *boot_dev = NULL;
+ (void) cmdtp; /* Parameter not used! */
+ (void) flag; /* Parameter not used! */
+ (void) argc; /* Parameter not used! */
+ (void) argv; /* Parameter not used! */
+
memset(mbr, 0, 0x1be);
if (u8500_is_earlydrop())
memcpy(mbr + 0x1be, partitions_ed, sizeof(partitions_ed));
@@ -136,6 +141,11 @@ static int mmc_read_cmd_file(cmd_tbl_t *cmdtp, int flag, int argc,
long sz;
char mmc_cmdbuffer[1024];
+ (void) cmdtp; /* Parameter not used! */
+ (void) flag; /* Parameter not used! */
+ (void) argc; /* Parameter not used! */
+ (void) argv; /* Parameter not used! */
+
sz = file_fat_read("command.txt", &mmc_cmdbuffer,
sizeof(mmc_cmdbuffer) - 1);
if (sz == -1) {