From 2591fbdba3bbae92366d0a4f20fbaf4aa0f9f65c Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:31 +0100 Subject: MVEBUMMC : Change copyright date MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 9f98c3f..063d4da 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -1,7 +1,7 @@ /* * Marvell MMC/SD/SDIO driver * - * (C) Copyright 2012 + * (C) Copyright 2012-2014 * Marvell Semiconductor * Written-by: Maen Suleiman, Gerald Kerma * -- cgit v1.1 From 28d27b79e33dea24b0fb29cf7ff6e88dfb18f030 Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:32 +0100 Subject: MVEBUMMC : Speed up access time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get about 40x faster access on SHEEVAPLUG MMC Fix some SD type compatibility Changes in v3: - fix the HW_STATE (from linux mvsdio) - review delays and timeouts Changes in v2: - increase number of loops - remove initial delay Changes in v1: - review all loops, delays and timeouts Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 063d4da..91a9be0 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -23,6 +23,8 @@ DECLARE_GLOBAL_DATA_PTR; #define MVEBU_TARGET_DRAM 0 +#define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */ + static void mvebu_mmc_write(u32 offs, u32 val) { writel(val, CONFIG_SYS_MMC_BASE + (offs)); @@ -63,7 +65,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; + ulong start; ushort waittype = 0; ushort resptype = 0; ushort xfertype = 0; @@ -72,19 +74,33 @@ 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); - debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); - /* Checking if card is busy */ - while ((mvebu_mmc_read(SDIO_HW_STATE) & CARD_BUSY)) { - if (timeout == 0) { - printf("%s: card busy!\n", DRIVER_NAME); - return -1; - } - timeout--; - udelay(1000); + /* + * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE + * register is sometimes not set before a while when some + * "unusual" data block sizes are used (such as with the SWITCH + * command), even despite the fact that the XFER_DONE interrupt + * was raised. And if another data transfer starts before + * this bit comes to good sense (which eventually happens by + * itself) then the new transfer simply fails with a timeout. + */ + if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { + ushort hw_state, count = 0; + + start = get_timer(0); + do { + hw_state = mvebu_mmc_read(SDIO_HW_STATE); + if ((get_timer(0) - start) > TIMEOUT_DELAY) { + printf("%s : FIFO_EMPTY bit missing\n", + DRIVER_NAME); + break; + } + count++; + } while (!(hw_state & CMD_FIFO_EMPTY)); + debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", + DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); } /* Set up for a data transfer if we have one */ @@ -147,8 +163,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, mvebu_mmc_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK); mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK); - /* Waiting for completion */ - timeout = 1000000; + start = get_timer(0); while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { @@ -161,13 +176,12 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, return COMM_ERR; } - timeout--; - udelay(1); - if (timeout <= 0) { - printf("%s: command timed out\n", DRIVER_NAME); + if ((get_timer(0) - start) > TIMEOUT_DELAY) { + 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; -- cgit v1.1 From fc0f25f91948eef623999ab0874d6bd4604cb889 Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:33 +0100 Subject: MVEBUMMC : FIX debug strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 91a9be0..854bcc6 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -71,8 +71,8 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ushort xfertype = 0; ushort resp_indx = 0; - debug("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", - cmd->cmdidx, cmd->resp_type, cmd->cmdarg); + debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", + DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg); debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); @@ -107,8 +107,11 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 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); @@ -171,8 +174,12 @@ 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; } @@ -265,6 +272,7 @@ static void mvebu_mmc_set_clk(unsigned int clock) 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); + debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); } udelay(10*1000); @@ -369,7 +377,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 -- cgit v1.1 From 86eeecafc24408822c1c8c329963e6f76751cae1 Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:34 +0100 Subject: MVEBUMMC : REMOVE unnecessary delays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove delays in mvebu_mmc_set_bus and mvebu_mmc_set_clk Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 854bcc6..3e08f40 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -274,8 +274,6 @@ static void mvebu_mmc_set_clk(unsigned int clock) mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); } - - udelay(10*1000); } static void mvebu_mmc_set_bus(unsigned int bus) @@ -315,7 +313,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) -- cgit v1.1 From 02b2739e8fd90f3bc6945824d87ca1647cf95aef Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:35 +0100 Subject: MVEBUMMC : CLEAN code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean mvebu_mmc_send_cmd Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 3e08f40..721ebcc 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -103,16 +103,9 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); } - /* Set up for a data transfer if we have one */ - if (data) { - int err = mvebu_mmc_setup_data(data); - - if (err) { - debug("%s: command DATA error :%x\n", - DRIVER_NAME, err); - return err; - } - } + /* Clear status */ + mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); resptype = SDIO_CMD_INDEX(cmd->cmdidx); @@ -138,6 +131,14 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (data) { + int err = mvebu_mmc_setup_data(data); + + if (err) { + debug("%s: command DATA error :%x\n", + DRIVER_NAME, err); + return err; + } + resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16; xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN; if (data->flags & MMC_DATA_READ) { @@ -157,15 +158,9 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, /* Setting Xfer mode */ mvebu_mmc_write(SDIO_XFER_MODE, xfertype); - mvebu_mmc_write(SDIO_NOR_INTR_STATUS, ~SDIO_NOR_CARD_INT); - mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); - /* Sending command */ mvebu_mmc_write(SDIO_CMD, resptype); - mvebu_mmc_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK); - mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK); - start = get_timer(0); while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { @@ -189,10 +184,6 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } } - 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) { uint response[8]; @@ -225,6 +216,11 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, cmd->response[1] = ((response[0] & 0xfc00) >> 10); cmd->response[2] = 0; cmd->response[3] = 0; + } else { + cmd->response[0] = 0; + cmd->response[1] = 0; + cmd->response[2] = 0; + cmd->response[3] = 0; } debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type); @@ -234,6 +230,10 @@ 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 | SDIO_ERR_DATA_TIMEOUT)) + return TIMEOUT; + return 0; } -- cgit v1.1 From ac0b7298441d96043a2275d3c0fdafa59ca8f103 Mon Sep 17 00:00:00 2001 From: Gerald Kerma Date: Sat, 13 Dec 2014 21:35:36 +0100 Subject: MVEBUMMC : REMOVE unnecessary delay from init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnessecary delay from mvebu_mmc_initialize Signed-off-by: Gérald Kerma Acked-by: Pantelis Antoniou --- drivers/mmc/mvebu_mmc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 721ebcc..8ca0904 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -403,8 +403,6 @@ static int mvebu_mmc_initialize(struct mmc *mmc) /* SW reset */ mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); - udelay(10*1000); - return 0; } -- cgit v1.1