diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mmc/renesas-sdhi.c | 77 |
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index bb38787eca..8f0df568b9 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -358,6 +358,7 @@ config RENESAS_SDHI depends on ARCH_RMOBILE depends on BLK && DM_MMC depends on OF_CONTROL + select BOUNCE_BUFFER help This selects support for the Matsushita SD/MMC Host Controller on Renesas R-Car SoCs. diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index c3b13136f8..231a78178c 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <bouncebuf.h> #include <clk.h> #include <fdtdec.h> #include <malloc.h> @@ -689,12 +690,88 @@ static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, } #endif +#define RENESAS_SDHI_DMA_ALIGNMENT 128 + +static int renesas_sdhi_addr_aligned(struct bounce_buffer *state) +{ + uintptr_t ubuf = (uintptr_t)state->user_buffer; + + /* Check if start is aligned */ + if (!IS_ALIGNED(ubuf, RENESAS_SDHI_DMA_ALIGNMENT)) { + debug("Unaligned buffer address %p\n", state->user_buffer); + return 0; + } + + /* Check if length is aligned */ + if (state->len != state->len_aligned) { + debug("Unaligned buffer length %zu\n", state->len); + return 0; + } + +#ifdef CONFIG_PHYS_64BIT + /* Check if below 32bit boundary */ + if ((ubuf >> 32) || (ubuf + state->len_aligned) >> 32) { + debug("Buffer above 32bit boundary %p-%p\n", + state->user_buffer, + state->user_buffer + state->len_aligned); + return 0; + } +#endif + + /* Aligned */ + return 1; +} + static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { + struct bounce_buffer bbstate; + unsigned int bbflags; + bool bbok = false; + size_t len; + void *buf; int ret; + if (data) { + if (data->flags & MMC_DATA_READ) { + buf = data->dest; + bbflags = GEN_BB_WRITE; + } else { + buf = (void *)data->src; + bbflags = GEN_BB_READ; + } + len = data->blocks * data->blocksize; + + ret = bounce_buffer_start_extalign(&bbstate, buf, len, bbflags, + RENESAS_SDHI_DMA_ALIGNMENT, + renesas_sdhi_addr_aligned); + /* + * If the amount of data to transfer is too large, we can get + * -ENOMEM when starting the bounce buffer. If that happens, + * fall back to PIO as it was before, otherwise use the BB. + */ + if (!ret) { + bbok = true; + if (data->flags & MMC_DATA_READ) + data->dest = bbstate.bounce_buffer; + else + data->src = bbstate.bounce_buffer; + } + } + ret = tmio_sd_send_cmd(dev, cmd, data); + + if (data && bbok) { + buf = bbstate.user_buffer; + + bounce_buffer_stop(&bbstate); + + if (data->flags & MMC_DATA_READ) + data->dest = buf; + else + data->src = buf; + } + if (ret) return ret; |