From 4744d81cc0dbe238bd4d8cd88c1c71022bffa621 Mon Sep 17 00:00:00 2001 From: Stefan Mavrodiev Date: Tue, 27 Mar 2018 16:57:23 +0300 Subject: sunxi: mmc: Fix phase delays U-boot driver for sunxi-mmc uses PLL6, unlike linux kernel where PLL5 is used, with clock rates respectively 600MHz and 768MHz. Thus there are different phase degree steps - 24 for the kernel and 30 for u-boot. In the kernel driver the phase is set 90 deg for output and 120 for sample. Dividing by 30 will result values 3 and 4. Those are the values set in the u-boot driver. However, the condition defining delays is wrong. MMC core driver requests clock of 52MHz, sunxi-driver sets clock of 50MHz, but phase is set 30 deg for output and 120 deg for sample. Apparently this works for most cards. On A20-SOM204-EVB-eMMC there is eMMC card (KLMAG2GEND) which complains about it. Maybe there is other boards with similar problem? So the fix is to match delays for both u-boot and kernel. Signed-off-by: Stefan Mavrodiev Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- drivers/mmc/sunxi_mmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index df6f32850e..f4c245c5eb 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -147,19 +147,19 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) oclk_dly = 0; sclk_dly = 5; #ifdef CONFIG_MACH_SUN9I - } else if (hz <= 50000000) { + } else if (hz <= 52000000) { oclk_dly = 5; sclk_dly = 4; } else { - /* hz > 50000000 */ + /* hz > 52000000 */ oclk_dly = 2; sclk_dly = 4; #else - } else if (hz <= 50000000) { + } else if (hz <= 52000000) { oclk_dly = 3; sclk_dly = 4; } else { - /* hz > 50000000 */ + /* hz > 52000000 */ oclk_dly = 1; sclk_dly = 4; #endif -- cgit From 5ff8e54888e4d26a352453564f7f599d29696dc9 Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Wed, 21 Mar 2018 12:18:58 +0100 Subject: sunxi: improve throughput in the sunxi_mmc driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Throughput tests have shown the sunxi_mmc driver to take over 10s to read 10MB from a fast eMMC device due to excessive delays in polling loops. This commit restructures the main polling loops to use get_timer(...) to determine whether a (millisecond) timeout has expired. We choose not to use the wait_bit function, as we don't need interruptability with ctrl-c and have at least one case where two bits (one for an error condition and another one for completion) need to be read and using wait_bit would have not added to the clarity. The observed speedup in testing on a A31 is greater than 10x (e.g. a 10MB write decreases from 9.302s to 0.884s). Signed-off-by: Philipp Tomsich Signed-off-by: Maxime Ripard Tested-by: Mylène Josserand Acked-by: Jagan Teki Reviewed-by: Tom Rini --- drivers/mmc/sunxi_mmc.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index f4c245c5eb..5292f2d3cc 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -188,15 +188,16 @@ static int mmc_update_clk(struct sunxi_mmc_priv *priv) { unsigned int cmd; unsigned timeout_msecs = 2000; + unsigned long start = get_timer(0); cmd = SUNXI_MMC_CMD_START | SUNXI_MMC_CMD_UPCLK_ONLY | SUNXI_MMC_CMD_WAIT_PRE_OVER; + writel(cmd, &priv->reg->cmd); while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) { - if (!timeout_msecs--) + if (get_timer(start) > timeout_msecs) return -1; - udelay(1000); } /* clock update sets various irq status bits, clear these */ @@ -277,18 +278,21 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc, unsigned i; unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); unsigned byte_cnt = data->blocksize * data->blocks; - unsigned timeout_usecs = (byte_cnt >> 8) * 1000; - if (timeout_usecs < 2000000) - timeout_usecs = 2000000; + unsigned timeout_msecs = byte_cnt >> 8; + unsigned long start; + + if (timeout_msecs < 2000) + timeout_msecs = 2000; /* Always read / write data through the CPU */ setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); + start = get_timer(0); + for (i = 0; i < (byte_cnt >> 2); i++) { while (readl(&priv->reg->status) & status_bit) { - if (!timeout_usecs--) + if (get_timer(start) > timeout_msecs) return -1; - udelay(1); } if (reading) @@ -304,16 +308,16 @@ static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc, uint timeout_msecs, uint done_bit, const char *what) { unsigned int status; + unsigned long start = get_timer(0); do { status = readl(&priv->reg->rint); - if (!timeout_msecs-- || + if ((get_timer(start) > timeout_msecs) || (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { debug("%s timeout %x\n", what, status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); return -ETIMEDOUT; } - udelay(1000); } while (!(status & done_bit)); return 0; @@ -405,15 +409,16 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv, } if (cmd->resp_type & MMC_RSP_BUSY) { + unsigned long start = get_timer(0); timeout_msecs = 2000; + do { status = readl(&priv->reg->status); - if (!timeout_msecs--) { + if (get_timer(start) > timeout_msecs) { debug("busy timeout\n"); error = -ETIMEDOUT; goto out; } - udelay(1000); } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); } -- cgit