[U-Boot] [PATCH 1/1] ARM: kirkwood: mvebu_mmc: Speed up access time

Review delays and timeouts.
Get around 20 x faster access on Sheevaplug tests.
Signed-off-by: Gérald KERMA drEagle@doukki.net --- drivers/mmc/mvebu_mmc.c | 67 ++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 26 deletions(-)
diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 9f98c3f..c401a61 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -23,6 +23,11 @@ DECLARE_GLOBAL_DATA_PTR;
#define MVEBU_TARGET_DRAM 0
+#define TIMEOUT_LOOP 1000000000 /* maximum loops */ +#define TIMEOUT_WAIT 100 /* wait 100 us */ +#define TIMEOUT_START 100 /* wait 100 us */ +#define TIMEOUT_INIT 100 /* wait 100 us */ + static void mvebu_mmc_write(u32 offs, u32 val) { writel(val, CONFIG_SYS_MMC_BASE + (offs)); @@ -63,7 +68,7 @@ static int mvebu_mmc_setup_data(struct mmc_data *data) static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { - int timeout = 10; + u32 timeout = TIMEOUT_LOOP; ushort waittype = 0; ushort resptype = 0; ushort xfertype = 0; @@ -72,27 +77,34 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, debug("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
- udelay(10*1000); + udelay(TIMEOUT_INIT);
debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE));
+ /* Clear status */ + mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); + /* Checking if card is busy */ while ((mvebu_mmc_read(SDIO_HW_STATE) & CARD_BUSY)) { + timeout--; + udelay(TIMEOUT_START); if (timeout == 0) { printf("%s: card busy!\n", DRIVER_NAME); return -1; } - timeout--; - udelay(1000); }
/* Set up for a data transfer if we have one */ if (data) { int err = mvebu_mmc_setup_data(data);
- if (err) + if (err){ + debug("%s: command DATA error :%x\n", + DRIVER_NAME, err); return err; + } }
resptype = SDIO_CMD_INDEX(cmd->cmdidx); @@ -148,7 +160,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK);
/* Waiting for completion */ - timeout = 1000000; + timeout = TIMEOUT_LOOP;
while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { @@ -156,21 +168,22 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, DRIVER_NAME, cmd->cmdidx, mvebu_mmc_read(SDIO_ERR_INTR_STATUS)); if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & - (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) + (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)){ + debug("%s: command READ timed out\n", + DRIVER_NAME); return TIMEOUT; + } + debug("%s: command READ error\n", DRIVER_NAME); return COMM_ERR; }
timeout--; - udelay(1); - if (timeout <= 0) { - printf("%s: command timed out\n", DRIVER_NAME); + udelay(TIMEOUT_WAIT); + if (timeout == 0) { + debug("%s: command timed out\n", DRIVER_NAME); return TIMEOUT; } } - if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & - (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) - return TIMEOUT;
/* Handling response */ if (cmd->resp_type & MMC_RSP_136) { @@ -213,6 +226,11 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, debug("[0x%x] ", cmd->response[3]); debug("\n");
+ if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & SDIO_ERR_CMD_TIMEOUT){ + debug("%s: command STATUS timed out\n", DRIVER_NAME); + return TIMEOUT; + } + return 0; }
@@ -236,33 +254,30 @@ static void mvebu_mmc_power_up(void) /* enable interrupts status */ mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); + + udelay(10*1000); }
static void mvebu_mmc_set_clk(unsigned int clock) { - unsigned int m; - if (clock == 0) { debug("%s: clock off\n", DRIVER_NAME); mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); } else { - m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1; + u32 m = DIV_ROUND_UP(MVEBU_MMC_BASE_FAST_CLOCK, + (2 * clock)) - 1; if (m > MVEBU_MMC_BASE_DIV_MAX) m = MVEBU_MMC_BASE_DIV_MAX; - mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); + mvebu_mmc_write(SDIO_CLK_DIV, m); + debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); } - - udelay(10*1000); }
static void mvebu_mmc_set_bus(unsigned int bus) { u32 ctrl_reg = 0;
- ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); - ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; - switch (bus) { case 4: ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; @@ -277,7 +292,7 @@ static void mvebu_mmc_set_bus(unsigned int bus) ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST;
/* default to maximum timeout */ - ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); + ctrl_reg |= SDIO_HOST_CTRL_TMOUT_MAX; ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN;
ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN; @@ -293,7 +308,6 @@ static void mvebu_mmc_set_bus(unsigned int bus) "high-speed" : "");
mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); - udelay(10*1000); }
static void mvebu_mmc_set_ios(struct mmc *mmc) @@ -355,7 +369,7 @@ static void mvebu_window_setup(void)
static int mvebu_mmc_initialize(struct mmc *mmc) { - debug("%s: mvebu_mmc_initialize", DRIVER_NAME); + debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME);
/* * Setting host parameters @@ -398,7 +412,8 @@ static const struct mmc_ops mvebu_mmc_ops = { static struct mmc_config mvebu_mmc_cfg = { .name = DRIVER_NAME, .ops = &mvebu_mmc_ops, - .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX, + .f_min = DIV_ROUND_UP(MVEBU_MMC_BASE_FAST_CLOCK, + MVEBU_MMC_BASE_DIV_MAX), .f_max = MVEBU_MMC_CLOCKRATE_MAX, .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, .host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HC |
participants (1)
-
Gérald KERMA