mmc: uniphier: Split out SoC specific bits from the driver
authorMarek Vasut <marek.vasut+renesas@gmail.com>
Sun, 8 Apr 2018 13:22:58 +0000 (15:22 +0200)
committerMarek Vasut <marek.vasut+renesas@gmail.com>
Wed, 11 Apr 2018 21:11:56 +0000 (23:11 +0200)
Factor out common code from the uniphier SD driver, change the prefix
of the functions from uniphier_sd_ to matsu_sd_ and create separate
renesas-sdhi.c driver. Thus far, all the code is still compiled when
CONFIG_UNIPHIER_MMC is selected and there is no functional change.
This patch is a preparation for further split of the SoC specific
parts of the Matsushita SD driver, used both on Uniphier and R-Car.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
drivers/mmc/Makefile
drivers/mmc/matsushita-common.c [new file with mode: 0644]
drivers/mmc/matsushita-common.h [new file with mode: 0644]
drivers/mmc/renesas-sdhi.c [new file with mode: 0644]
drivers/mmc/uniphier-sd.c

index 958341017c7830d7511d7fa1d467da95c0892bda..25eb669d510b9ce65606b8a290a645f57aed545b 100644 (file)
@@ -62,5 +62,5 @@ obj-$(CONFIG_MMC_SDHCI_XENON)         += xenon_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_ZYNQ)           += zynq_sdhci.o
 
 obj-$(CONFIG_MMC_SUNXI)                        += sunxi_mmc.o
-obj-$(CONFIG_MMC_UNIPHIER)             += uniphier-sd.o
+obj-$(CONFIG_MMC_UNIPHIER)             += matsushita-common.o uniphier-sd.o renesas-sdhi.o
 obj-$(CONFIG_MMC_BCM2835)              += bcm2835_sdhost.o
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c
new file mode 100644 (file)
index 0000000..ed67710
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <mmc.h>
+#include <dm.h>
+#include <linux/compat.h>
+#include <linux/dma-direction.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <power/regulator.h>
+#include <asm/unaligned.h>
+
+#include "matsushita-common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u64 matsu_sd_readq(struct matsu_sd_priv *priv, unsigned int reg)
+{
+       if (priv->caps & MATSU_SD_CAP_64BIT)
+               return readq(priv->regbase + (reg << 1));
+       else
+               return readq(priv->regbase + reg);
+}
+
+static void matsu_sd_writeq(struct matsu_sd_priv *priv,
+                              u64 val, unsigned int reg)
+{
+       if (priv->caps & MATSU_SD_CAP_64BIT)
+               writeq(val, priv->regbase + (reg << 1));
+       else
+               writeq(val, priv->regbase + reg);
+}
+
+static u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg)
+{
+       if (priv->caps & MATSU_SD_CAP_64BIT)
+               return readl(priv->regbase + (reg << 1));
+       else
+               return readl(priv->regbase + reg);
+}
+
+static void matsu_sd_writel(struct matsu_sd_priv *priv,
+                              u32 val, unsigned int reg)
+{
+       if (priv->caps & MATSU_SD_CAP_64BIT)
+               writel(val, priv->regbase + (reg << 1));
+       else
+               writel(val, priv->regbase + reg);
+}
+
+static dma_addr_t __dma_map_single(void *ptr, size_t size,
+                                  enum dma_data_direction dir)
+{
+       unsigned long addr = (unsigned long)ptr;
+
+       if (dir == DMA_FROM_DEVICE)
+               invalidate_dcache_range(addr, addr + size);
+       else
+               flush_dcache_range(addr, addr + size);
+
+       return addr;
+}
+
+static void __dma_unmap_single(dma_addr_t addr, size_t size,
+                              enum dma_data_direction dir)
+{
+       if (dir != DMA_TO_DEVICE)
+               invalidate_dcache_range(addr, addr + size);
+}
+
+static int matsu_sd_check_error(struct udevice *dev)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       u32 info2 = matsu_sd_readl(priv, MATSU_SD_INFO2);
+
+       if (info2 & MATSU_SD_INFO2_ERR_RTO) {
+               /*
+                * TIMEOUT must be returned for unsupported command.  Do not
+                * display error log since this might be a part of sequence to
+                * distinguish between SD and MMC.
+                */
+               return -ETIMEDOUT;
+       }
+
+       if (info2 & MATSU_SD_INFO2_ERR_TO) {
+               dev_err(dev, "timeout error\n");
+               return -ETIMEDOUT;
+       }
+
+       if (info2 & (MATSU_SD_INFO2_ERR_END | MATSU_SD_INFO2_ERR_CRC |
+                    MATSU_SD_INFO2_ERR_IDX)) {
+               dev_err(dev, "communication out of sync\n");
+               return -EILSEQ;
+       }
+
+       if (info2 & (MATSU_SD_INFO2_ERR_ILA | MATSU_SD_INFO2_ERR_ILR |
+                    MATSU_SD_INFO2_ERR_ILW)) {
+               dev_err(dev, "illegal access\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int matsu_sd_wait_for_irq(struct udevice *dev, unsigned int reg,
+                                   u32 flag)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       long wait = 1000000;
+       int ret;
+
+       while (!(matsu_sd_readl(priv, reg) & flag)) {
+               if (wait-- < 0) {
+                       dev_err(dev, "timeout\n");
+                       return -ETIMEDOUT;
+               }
+
+               ret = matsu_sd_check_error(dev);
+               if (ret)
+                       return ret;
+
+               udelay(1);
+       }
+
+       return 0;
+}
+
+static int matsu_sd_pio_read_one_block(struct udevice *dev, char *pbuf,
+                                         uint blocksize)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       int i, ret;
+
+       /* wait until the buffer is filled with data */
+       ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO2,
+                                      MATSU_SD_INFO2_BRE);
+       if (ret)
+               return ret;
+
+       /*
+        * Clear the status flag _before_ read the buffer out because
+        * MATSU_SD_INFO2_BRE is edge-triggered, not level-triggered.
+        */
+       matsu_sd_writel(priv, 0, MATSU_SD_INFO2);
+
+       if (priv->caps & MATSU_SD_CAP_64BIT) {
+               u64 *buf = (u64 *)pbuf;
+               if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
+                       for (i = 0; i < blocksize / 8; i++) {
+                               *buf++ = matsu_sd_readq(priv,
+                                                          MATSU_SD_BUF);
+                       }
+               } else {
+                       for (i = 0; i < blocksize / 8; i++) {
+                               u64 data;
+                               data = matsu_sd_readq(priv,
+                                                        MATSU_SD_BUF);
+                               put_unaligned(data, buf++);
+                       }
+               }
+       } else {
+               u32 *buf = (u32 *)pbuf;
+               if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
+                       for (i = 0; i < blocksize / 4; i++) {
+                               *buf++ = matsu_sd_readl(priv,
+                                                          MATSU_SD_BUF);
+                       }
+               } else {
+                       for (i = 0; i < blocksize / 4; i++) {
+                               u32 data;
+                               data = matsu_sd_readl(priv, MATSU_SD_BUF);
+                               put_unaligned(data, buf++);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int matsu_sd_pio_write_one_block(struct udevice *dev,
+                                          const char *pbuf, uint blocksize)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       int i, ret;
+
+       /* wait until the buffer becomes empty */
+       ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO2,
+                                      MATSU_SD_INFO2_BWE);
+       if (ret)
+               return ret;
+
+       matsu_sd_writel(priv, 0, MATSU_SD_INFO2);
+
+       if (priv->caps & MATSU_SD_CAP_64BIT) {
+               const u64 *buf = (const u64 *)pbuf;
+               if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
+                       for (i = 0; i < blocksize / 8; i++) {
+                               matsu_sd_writeq(priv, *buf++,
+                                                  MATSU_SD_BUF);
+                       }
+               } else {
+                       for (i = 0; i < blocksize / 8; i++) {
+                               u64 data = get_unaligned(buf++);
+                               matsu_sd_writeq(priv, data,
+                                                  MATSU_SD_BUF);
+                       }
+               }
+       } else {
+               const u32 *buf = (const u32 *)pbuf;
+               if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
+                       for (i = 0; i < blocksize / 4; i++) {
+                               matsu_sd_writel(priv, *buf++,
+                                                  MATSU_SD_BUF);
+                       }
+               } else {
+                       for (i = 0; i < blocksize / 4; i++) {
+                               u32 data = get_unaligned(buf++);
+                               matsu_sd_writel(priv, data,
+                                                  MATSU_SD_BUF);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int matsu_sd_pio_xfer(struct udevice *dev, struct mmc_data *data)
+{
+       const char *src = data->src;
+       char *dest = data->dest;
+       int i, ret;
+
+       for (i = 0; i < data->blocks; i++) {
+               if (data->flags & MMC_DATA_READ)
+                       ret = matsu_sd_pio_read_one_block(dev, dest,
+                                                            data->blocksize);
+               else
+                       ret = matsu_sd_pio_write_one_block(dev, src,
+                                                             data->blocksize);
+               if (ret)
+                       return ret;
+
+               if (data->flags & MMC_DATA_READ)
+                       dest += data->blocksize;
+               else
+                       src += data->blocksize;
+       }
+
+       return 0;
+}
+
+static void matsu_sd_dma_start(struct matsu_sd_priv *priv,
+                                 dma_addr_t dma_addr)
+{
+       u32 tmp;
+
+       matsu_sd_writel(priv, 0, MATSU_SD_DMA_INFO1);
+       matsu_sd_writel(priv, 0, MATSU_SD_DMA_INFO2);
+
+       /* enable DMA */
+       tmp = matsu_sd_readl(priv, MATSU_SD_EXTMODE);
+       tmp |= MATSU_SD_EXTMODE_DMA_EN;
+       matsu_sd_writel(priv, tmp, MATSU_SD_EXTMODE);
+
+       matsu_sd_writel(priv, dma_addr & U32_MAX, MATSU_SD_DMA_ADDR_L);
+
+       /* suppress the warning "right shift count >= width of type" */
+       dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
+
+       matsu_sd_writel(priv, dma_addr & U32_MAX, MATSU_SD_DMA_ADDR_H);
+
+       matsu_sd_writel(priv, MATSU_SD_DMA_CTL_START, MATSU_SD_DMA_CTL);
+}
+
+static int matsu_sd_dma_wait_for_irq(struct udevice *dev, u32 flag,
+                                       unsigned int blocks)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       long wait = 1000000 + 10 * blocks;
+
+       while (!(matsu_sd_readl(priv, MATSU_SD_DMA_INFO1) & flag)) {
+               if (wait-- < 0) {
+                       dev_err(dev, "timeout during DMA\n");
+                       return -ETIMEDOUT;
+               }
+
+               udelay(10);
+       }
+
+       if (matsu_sd_readl(priv, MATSU_SD_DMA_INFO2)) {
+               dev_err(dev, "error during DMA\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int matsu_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       size_t len = data->blocks * data->blocksize;
+       void *buf;
+       enum dma_data_direction dir;
+       dma_addr_t dma_addr;
+       u32 poll_flag, tmp;
+       int ret;
+
+       tmp = matsu_sd_readl(priv, MATSU_SD_DMA_MODE);
+
+       if (data->flags & MMC_DATA_READ) {
+               buf = data->dest;
+               dir = DMA_FROM_DEVICE;
+               poll_flag = MATSU_SD_DMA_INFO1_END_RD2;
+               tmp |= MATSU_SD_DMA_MODE_DIR_RD;
+       } else {
+               buf = (void *)data->src;
+               dir = DMA_TO_DEVICE;
+               poll_flag = MATSU_SD_DMA_INFO1_END_WR;
+               tmp &= ~MATSU_SD_DMA_MODE_DIR_RD;
+       }
+
+       matsu_sd_writel(priv, tmp, MATSU_SD_DMA_MODE);
+
+       dma_addr = __dma_map_single(buf, len, dir);
+
+       matsu_sd_dma_start(priv, dma_addr);
+
+       ret = matsu_sd_dma_wait_for_irq(dev, poll_flag, data->blocks);
+
+       __dma_unmap_single(dma_addr, len, dir);
+
+       return ret;
+}
+
+/* check if the address is DMA'able */
+static bool matsu_sd_addr_is_dmaable(unsigned long addr)
+{
+       if (!IS_ALIGNED(addr, MATSU_SD_DMA_MINALIGN))
+               return false;
+
+#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \
+       defined(CONFIG_SPL_BUILD)
+       /*
+        * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways
+        * of L2, which is unreachable from the DMA engine.
+        */
+       if (addr < CONFIG_SPL_STACK)
+               return false;
+#endif
+
+       return true;
+}
+
+int matsu_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+                     struct mmc_data *data)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       int ret;
+       u32 tmp;
+
+       if (matsu_sd_readl(priv, MATSU_SD_INFO2) & MATSU_SD_INFO2_CBSY) {
+               dev_err(dev, "command busy\n");
+               return -EBUSY;
+       }
+
+       /* clear all status flags */
+       matsu_sd_writel(priv, 0, MATSU_SD_INFO1);
+       matsu_sd_writel(priv, 0, MATSU_SD_INFO2);
+
+       /* disable DMA once */
+       tmp = matsu_sd_readl(priv, MATSU_SD_EXTMODE);
+       tmp &= ~MATSU_SD_EXTMODE_DMA_EN;
+       matsu_sd_writel(priv, tmp, MATSU_SD_EXTMODE);
+
+       matsu_sd_writel(priv, cmd->cmdarg, MATSU_SD_ARG);
+
+       tmp = cmd->cmdidx;
+
+       if (data) {
+               matsu_sd_writel(priv, data->blocksize, MATSU_SD_SIZE);
+               matsu_sd_writel(priv, data->blocks, MATSU_SD_SECCNT);
+
+               /* Do not send CMD12 automatically */
+               tmp |= MATSU_SD_CMD_NOSTOP | MATSU_SD_CMD_DATA;
+
+               if (data->blocks > 1)
+                       tmp |= MATSU_SD_CMD_MULTI;
+
+               if (data->flags & MMC_DATA_READ)
+                       tmp |= MATSU_SD_CMD_RD;
+       }
+
+       /*
+        * Do not use the response type auto-detection on this hardware.
+        * CMD8, for example, has different response types on SD and eMMC,
+        * while this controller always assumes the response type for SD.
+        * Set the response type manually.
+        */
+       switch (cmd->resp_type) {
+       case MMC_RSP_NONE:
+               tmp |= MATSU_SD_CMD_RSP_NONE;
+               break;
+       case MMC_RSP_R1:
+               tmp |= MATSU_SD_CMD_RSP_R1;
+               break;
+       case MMC_RSP_R1b:
+               tmp |= MATSU_SD_CMD_RSP_R1B;
+               break;
+       case MMC_RSP_R2:
+               tmp |= MATSU_SD_CMD_RSP_R2;
+               break;
+       case MMC_RSP_R3:
+               tmp |= MATSU_SD_CMD_RSP_R3;
+               break;
+       default:
+               dev_err(dev, "unknown response type\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n",
+               cmd->cmdidx, tmp, cmd->cmdarg);
+       matsu_sd_writel(priv, tmp, MATSU_SD_CMD);
+
+       ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO1,
+                                      MATSU_SD_INFO1_RSP);
+       if (ret)
+               return ret;
+
+       if (cmd->resp_type & MMC_RSP_136) {
+               u32 rsp_127_104 = matsu_sd_readl(priv, MATSU_SD_RSP76);
+               u32 rsp_103_72 = matsu_sd_readl(priv, MATSU_SD_RSP54);
+               u32 rsp_71_40 = matsu_sd_readl(priv, MATSU_SD_RSP32);
+               u32 rsp_39_8 = matsu_sd_readl(priv, MATSU_SD_RSP10);
+
+               cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) |
+                                  ((rsp_103_72  & 0xff000000) >> 24);
+               cmd->response[1] = ((rsp_103_72  & 0x00ffffff) << 8) |
+                                  ((rsp_71_40   & 0xff000000) >> 24);
+               cmd->response[2] = ((rsp_71_40   & 0x00ffffff) << 8) |
+                                  ((rsp_39_8    & 0xff000000) >> 24);
+               cmd->response[3] = (rsp_39_8     & 0xffffff)   << 8;
+       } else {
+               /* bit 39-8 */
+               cmd->response[0] = matsu_sd_readl(priv, MATSU_SD_RSP10);
+       }
+
+       if (data) {
+               /* use DMA if the HW supports it and the buffer is aligned */
+               if (priv->caps & MATSU_SD_CAP_DMA_INTERNAL &&
+                   matsu_sd_addr_is_dmaable((long)data->src))
+                       ret = matsu_sd_dma_xfer(dev, data);
+               else
+                       ret = matsu_sd_pio_xfer(dev, data);
+
+               ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO1,
+                                              MATSU_SD_INFO1_CMP);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static int matsu_sd_set_bus_width(struct matsu_sd_priv *priv,
+                                    struct mmc *mmc)
+{
+       u32 val, tmp;
+
+       switch (mmc->bus_width) {
+       case 1:
+               val = MATSU_SD_OPTION_WIDTH_1;
+               break;
+       case 4:
+               val = MATSU_SD_OPTION_WIDTH_4;
+               break;
+       case 8:
+               val = MATSU_SD_OPTION_WIDTH_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tmp = matsu_sd_readl(priv, MATSU_SD_OPTION);
+       tmp &= ~MATSU_SD_OPTION_WIDTH_MASK;
+       tmp |= val;
+       matsu_sd_writel(priv, tmp, MATSU_SD_OPTION);
+
+       return 0;
+}
+
+static void matsu_sd_set_ddr_mode(struct matsu_sd_priv *priv,
+                                    struct mmc *mmc)
+{
+       u32 tmp;
+
+       tmp = matsu_sd_readl(priv, MATSU_SD_IF_MODE);
+       if (mmc->ddr_mode)
+               tmp |= MATSU_SD_IF_MODE_DDR;
+       else
+               tmp &= ~MATSU_SD_IF_MODE_DDR;
+       matsu_sd_writel(priv, tmp, MATSU_SD_IF_MODE);
+}
+
+static void matsu_sd_set_clk_rate(struct matsu_sd_priv *priv,
+                                    struct mmc *mmc)
+{
+       unsigned int divisor;
+       u32 val, tmp;
+
+       if (!mmc->clock)
+               return;
+
+       divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
+
+       if (divisor <= 1)
+               val = MATSU_SD_CLKCTL_DIV1;
+       else if (divisor <= 2)
+               val = MATSU_SD_CLKCTL_DIV2;
+       else if (divisor <= 4)
+               val = MATSU_SD_CLKCTL_DIV4;
+       else if (divisor <= 8)
+               val = MATSU_SD_CLKCTL_DIV8;
+       else if (divisor <= 16)
+               val = MATSU_SD_CLKCTL_DIV16;
+       else if (divisor <= 32)
+               val = MATSU_SD_CLKCTL_DIV32;
+       else if (divisor <= 64)
+               val = MATSU_SD_CLKCTL_DIV64;
+       else if (divisor <= 128)
+               val = MATSU_SD_CLKCTL_DIV128;
+       else if (divisor <= 256)
+               val = MATSU_SD_CLKCTL_DIV256;
+       else if (divisor <= 512 || !(priv->caps & MATSU_SD_CAP_DIV1024))
+               val = MATSU_SD_CLKCTL_DIV512;
+       else
+               val = MATSU_SD_CLKCTL_DIV1024;
+
+       tmp = matsu_sd_readl(priv, MATSU_SD_CLKCTL);
+       if (tmp & MATSU_SD_CLKCTL_SCLKEN &&
+           (tmp & MATSU_SD_CLKCTL_DIV_MASK) == val)
+               return;
+
+       /* stop the clock before changing its rate to avoid a glitch signal */
+       tmp &= ~MATSU_SD_CLKCTL_SCLKEN;
+       matsu_sd_writel(priv, tmp, MATSU_SD_CLKCTL);
+
+       tmp &= ~MATSU_SD_CLKCTL_DIV_MASK;
+       tmp |= val | MATSU_SD_CLKCTL_OFFEN;
+       matsu_sd_writel(priv, tmp, MATSU_SD_CLKCTL);
+
+       tmp |= MATSU_SD_CLKCTL_SCLKEN;
+       matsu_sd_writel(priv, tmp, MATSU_SD_CLKCTL);
+
+       udelay(1000);
+}
+
+int matsu_sd_set_ios(struct udevice *dev)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+       int ret;
+
+       dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n",
+               mmc->clock, mmc->ddr_mode, mmc->bus_width);
+
+       ret = matsu_sd_set_bus_width(priv, mmc);
+       if (ret)
+               return ret;
+       matsu_sd_set_ddr_mode(priv, mmc);
+       matsu_sd_set_clk_rate(priv, mmc);
+
+       return 0;
+}
+
+int matsu_sd_get_cd(struct udevice *dev)
+{
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+
+       if (priv->caps & MATSU_SD_CAP_NONREMOVABLE)
+               return 1;
+
+       return !!(matsu_sd_readl(priv, MATSU_SD_INFO1) &
+                 MATSU_SD_INFO1_CD);
+}
+
+static void matsu_sd_host_init(struct matsu_sd_priv *priv)
+{
+       u32 tmp;
+
+       /* soft reset of the host */
+       tmp = matsu_sd_readl(priv, MATSU_SD_SOFT_RST);
+       tmp &= ~MATSU_SD_SOFT_RST_RSTX;
+       matsu_sd_writel(priv, tmp, MATSU_SD_SOFT_RST);
+       tmp |= MATSU_SD_SOFT_RST_RSTX;
+       matsu_sd_writel(priv, tmp, MATSU_SD_SOFT_RST);
+
+       /* FIXME: implement eMMC hw_reset */
+
+       matsu_sd_writel(priv, MATSU_SD_STOP_SEC, MATSU_SD_STOP);
+
+       /*
+        * Connected to 32bit AXI.
+        * This register dropped backward compatibility at version 0x10.
+        * Write an appropriate value depending on the IP version.
+        */
+       matsu_sd_writel(priv, priv->version >= 0x10 ? 0x00000101 : 0x00000000,
+                          MATSU_SD_HOST_MODE);
+
+       if (priv->caps & MATSU_SD_CAP_DMA_INTERNAL) {
+               tmp = matsu_sd_readl(priv, MATSU_SD_DMA_MODE);
+               tmp |= MATSU_SD_DMA_MODE_ADDR_INC;
+               matsu_sd_writel(priv, tmp, MATSU_SD_DMA_MODE);
+       }
+}
+
+int matsu_sd_bind(struct udevice *dev)
+{
+       struct matsu_sd_plat *plat = dev_get_platdata(dev);
+
+       return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+int matsu_sd_probe(struct udevice *dev)
+{
+       struct matsu_sd_plat *plat = dev_get_platdata(dev);
+       struct matsu_sd_priv *priv = dev_get_priv(dev);
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       const u32 quirks = dev_get_driver_data(dev);
+       fdt_addr_t base;
+       struct clk clk;
+       int ret;
+#ifdef CONFIG_DM_REGULATOR
+       struct udevice *vqmmc_dev;
+#endif
+
+       base = devfdt_get_addr(dev);
+       if (base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       priv->regbase = devm_ioremap(dev, base, SZ_2K);
+       if (!priv->regbase)
+               return -ENOMEM;
+
+#ifdef CONFIG_DM_REGULATOR
+       ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev);
+       if (!ret) {
+               /* Set the regulator to 3.3V until we support 1.8V modes */
+               regulator_set_value(vqmmc_dev, 3300000);
+               regulator_set_enable(vqmmc_dev, true);
+       }
+#endif
+
+       ret = clk_get_by_index(dev, 0, &clk);
+       if (ret < 0) {
+               dev_err(dev, "failed to get host clock\n");
+               return ret;
+       }
+
+       /* set to max rate */
+       priv->mclk = clk_set_rate(&clk, ULONG_MAX);
+       if (IS_ERR_VALUE(priv->mclk)) {
+               dev_err(dev, "failed to set rate for host clock\n");
+               clk_free(&clk);
+               return priv->mclk;
+       }
+
+       ret = clk_enable(&clk);
+       clk_free(&clk);
+       if (ret) {
+               dev_err(dev, "failed to enable host clock\n");
+               return ret;
+       }
+
+       plat->cfg.name = dev->name;
+       plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+       switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
+                              1)) {
+       case 8:
+               plat->cfg.host_caps |= MMC_MODE_8BIT;
+               break;
+       case 4:
+               plat->cfg.host_caps |= MMC_MODE_4BIT;
+               break;
+       case 1:
+               break;
+       default:
+               dev_err(dev, "Invalid \"bus-width\" value\n");
+               return -EINVAL;
+       }
+
+       if (quirks) {
+               priv->caps = quirks;
+       } else {
+               priv->version = matsu_sd_readl(priv, MATSU_SD_VERSION) &
+                                                       MATSU_SD_VERSION_IP;
+               dev_dbg(dev, "version %x\n", priv->version);
+               if (priv->version >= 0x10) {
+                       priv->caps |= MATSU_SD_CAP_DMA_INTERNAL;
+                       priv->caps |= MATSU_SD_CAP_DIV1024;
+               }
+       }
+
+       if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
+                            NULL))
+               priv->caps |= MATSU_SD_CAP_NONREMOVABLE;
+
+       matsu_sd_host_init(priv);
+
+       plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+       plat->cfg.f_min = priv->mclk /
+                       (priv->caps & MATSU_SD_CAP_DIV1024 ? 1024 : 512);
+       plat->cfg.f_max = priv->mclk;
+       plat->cfg.b_max = U32_MAX; /* max value of MATSU_SD_SECCNT */
+
+       upriv->mmc = &plat->mmc;
+
+       return 0;
+}
diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h
new file mode 100644 (file)
index 0000000..e517a2d
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __MATSUSHITA_COMMON_H__
+#define __MATSUSHITA_COMMON_H__
+
+#define MATSU_SD_CMD                   0x000   /* command */
+#define   MATSU_SD_CMD_NOSTOP          BIT(14) /* No automatic CMD12 issue */
+#define   MATSU_SD_CMD_MULTI           BIT(13) /* multiple block transfer */
+#define   MATSU_SD_CMD_RD              BIT(12) /* 1: read, 0: write */
+#define   MATSU_SD_CMD_DATA            BIT(11) /* data transfer */
+#define   MATSU_SD_CMD_APP             BIT(6)  /* ACMD preceded by CMD55 */
+#define   MATSU_SD_CMD_NORMAL          (0 << 8)/* auto-detect of resp-type */
+#define   MATSU_SD_CMD_RSP_NONE                (3 << 8)/* response: none */
+#define   MATSU_SD_CMD_RSP_R1          (4 << 8)/* response: R1, R5, R6, R7 */
+#define   MATSU_SD_CMD_RSP_R1B         (5 << 8)/* response: R1b, R5b */
+#define   MATSU_SD_CMD_RSP_R2          (6 << 8)/* response: R2 */
+#define   MATSU_SD_CMD_RSP_R3          (7 << 8)/* response: R3, R4 */
+#define MATSU_SD_ARG                   0x008   /* command argument */
+#define MATSU_SD_STOP                  0x010   /* stop action control */
+#define   MATSU_SD_STOP_SEC            BIT(8)  /* use sector count */
+#define   MATSU_SD_STOP_STP            BIT(0)  /* issue CMD12 */
+#define MATSU_SD_SECCNT                        0x014   /* sector counter */
+#define MATSU_SD_RSP10                 0x018   /* response[39:8] */
+#define MATSU_SD_RSP32                 0x020   /* response[71:40] */
+#define MATSU_SD_RSP54                 0x028   /* response[103:72] */
+#define MATSU_SD_RSP76                 0x030   /* response[127:104] */
+#define MATSU_SD_INFO1                 0x038   /* IRQ status 1 */
+#define   MATSU_SD_INFO1_CD            BIT(5)  /* state of card detect */
+#define   MATSU_SD_INFO1_INSERT                BIT(4)  /* card inserted */
+#define   MATSU_SD_INFO1_REMOVE                BIT(3)  /* card removed */
+#define   MATSU_SD_INFO1_CMP           BIT(2)  /* data complete */
+#define   MATSU_SD_INFO1_RSP           BIT(0)  /* response complete */
+#define MATSU_SD_INFO2                 0x03c   /* IRQ status 2 */
+#define   MATSU_SD_INFO2_ERR_ILA       BIT(15) /* illegal access err */
+#define   MATSU_SD_INFO2_CBSY          BIT(14) /* command busy */
+#define   MATSU_SD_INFO2_BWE           BIT(9)  /* write buffer ready */
+#define   MATSU_SD_INFO2_BRE           BIT(8)  /* read buffer ready */
+#define   MATSU_SD_INFO2_DAT0          BIT(7)  /* SDDAT0 */
+#define   MATSU_SD_INFO2_ERR_RTO       BIT(6)  /* response time out */
+#define   MATSU_SD_INFO2_ERR_ILR       BIT(5)  /* illegal read err */
+#define   MATSU_SD_INFO2_ERR_ILW       BIT(4)  /* illegal write err */
+#define   MATSU_SD_INFO2_ERR_TO                BIT(3)  /* time out error */
+#define   MATSU_SD_INFO2_ERR_END       BIT(2)  /* END bit error */
+#define   MATSU_SD_INFO2_ERR_CRC       BIT(1)  /* CRC error */
+#define   MATSU_SD_INFO2_ERR_IDX       BIT(0)  /* cmd index error */
+#define MATSU_SD_INFO1_MASK            0x040
+#define MATSU_SD_INFO2_MASK            0x044
+#define MATSU_SD_CLKCTL                        0x048   /* clock divisor */
+#define   MATSU_SD_CLKCTL_DIV_MASK     0x104ff
+#define   MATSU_SD_CLKCTL_DIV1024      BIT(16) /* SDCLK = CLK / 1024 */
+#define   MATSU_SD_CLKCTL_DIV512       BIT(7)  /* SDCLK = CLK / 512 */
+#define   MATSU_SD_CLKCTL_DIV256       BIT(6)  /* SDCLK = CLK / 256 */
+#define   MATSU_SD_CLKCTL_DIV128       BIT(5)  /* SDCLK = CLK / 128 */
+#define   MATSU_SD_CLKCTL_DIV64                BIT(4)  /* SDCLK = CLK / 64 */
+#define   MATSU_SD_CLKCTL_DIV32                BIT(3)  /* SDCLK = CLK / 32 */
+#define   MATSU_SD_CLKCTL_DIV16                BIT(2)  /* SDCLK = CLK / 16 */
+#define   MATSU_SD_CLKCTL_DIV8         BIT(1)  /* SDCLK = CLK / 8 */
+#define   MATSU_SD_CLKCTL_DIV4         BIT(0)  /* SDCLK = CLK / 4 */
+#define   MATSU_SD_CLKCTL_DIV2         0       /* SDCLK = CLK / 2 */
+#define   MATSU_SD_CLKCTL_DIV1         BIT(10) /* SDCLK = CLK */
+#define   MATSU_SD_CLKCTL_OFFEN                BIT(9)  /* stop SDCLK when unused */
+#define   MATSU_SD_CLKCTL_SCLKEN       BIT(8)  /* SDCLK output enable */
+#define MATSU_SD_SIZE                  0x04c   /* block size */
+#define MATSU_SD_OPTION                        0x050
+#define   MATSU_SD_OPTION_WIDTH_MASK   (5 << 13)
+#define   MATSU_SD_OPTION_WIDTH_1      (4 << 13)
+#define   MATSU_SD_OPTION_WIDTH_4      (0 << 13)
+#define   MATSU_SD_OPTION_WIDTH_8      (1 << 13)
+#define MATSU_SD_BUF                   0x060   /* read/write buffer */
+#define MATSU_SD_EXTMODE               0x1b0
+#define   MATSU_SD_EXTMODE_DMA_EN      BIT(1)  /* transfer 1: DMA, 0: pio */
+#define MATSU_SD_SOFT_RST              0x1c0
+#define MATSU_SD_SOFT_RST_RSTX         BIT(0)  /* reset deassert */
+#define MATSU_SD_VERSION               0x1c4   /* version register */
+#define MATSU_SD_VERSION_IP            0xff    /* IP version */
+#define MATSU_SD_HOST_MODE             0x1c8
+#define MATSU_SD_IF_MODE               0x1cc
+#define   MATSU_SD_IF_MODE_DDR         BIT(0)  /* DDR mode */
+#define MATSU_SD_VOLT                  0x1e4   /* voltage switch */
+#define   MATSU_SD_VOLT_MASK           (3 << 0)
+#define   MATSU_SD_VOLT_OFF            (0 << 0)
+#define   MATSU_SD_VOLT_330            (1 << 0)/* 3.3V signal */
+#define   MATSU_SD_VOLT_180            (2 << 0)/* 1.8V signal */
+#define MATSU_SD_DMA_MODE              0x410
+#define   MATSU_SD_DMA_MODE_DIR_RD     BIT(16) /* 1: from device, 0: to dev */
+#define   MATSU_SD_DMA_MODE_ADDR_INC   BIT(0)  /* 1: address inc, 0: fixed */
+#define MATSU_SD_DMA_CTL               0x414
+#define   MATSU_SD_DMA_CTL_START       BIT(0)  /* start DMA (auto cleared) */
+#define MATSU_SD_DMA_RST               0x418
+#define   MATSU_SD_DMA_RST_RD          BIT(9)
+#define   MATSU_SD_DMA_RST_WR          BIT(8)
+#define MATSU_SD_DMA_INFO1             0x420
+#define   MATSU_SD_DMA_INFO1_END_RD2   BIT(20) /* DMA from device is complete*/
+#define   MATSU_SD_DMA_INFO1_END_RD    BIT(17) /* Don't use!  Hardware bug */
+#define   MATSU_SD_DMA_INFO1_END_WR    BIT(16) /* DMA to device is complete */
+#define MATSU_SD_DMA_INFO1_MASK                0x424
+#define MATSU_SD_DMA_INFO2             0x428
+#define   MATSU_SD_DMA_INFO2_ERR_RD    BIT(17)
+#define   MATSU_SD_DMA_INFO2_ERR_WR    BIT(16)
+#define MATSU_SD_DMA_INFO2_MASK                0x42c
+#define MATSU_SD_DMA_ADDR_L            0x440
+#define MATSU_SD_DMA_ADDR_H            0x444
+
+/* alignment required by the DMA engine of this controller */
+#define MATSU_SD_DMA_MINALIGN          0x10
+
+struct matsu_sd_plat {
+       struct mmc_config               cfg;
+       struct mmc                      mmc;
+};
+
+struct matsu_sd_priv {
+       void __iomem                    *regbase;
+       unsigned long                   mclk;
+       unsigned int                    version;
+       u32                             caps;
+#define MATSU_SD_CAP_NONREMOVABLE      BIT(0)  /* Nonremovable e.g. eMMC */
+#define MATSU_SD_CAP_DMA_INTERNAL      BIT(1)  /* have internal DMA engine */
+#define MATSU_SD_CAP_DIV1024           BIT(2)  /* divisor 1024 is available */
+#define MATSU_SD_CAP_64BIT             BIT(3)  /* Controller is 64bit */
+};
+
+int matsu_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+                     struct mmc_data *data);
+int matsu_sd_set_ios(struct udevice *dev);
+int matsu_sd_get_cd(struct udevice *dev);
+
+int matsu_sd_bind(struct udevice *dev);
+int matsu_sd_probe(struct udevice *dev);
+
+#endif /* __MATSUSHITA_COMMON_H__ */
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
new file mode 100644 (file)
index 0000000..9b388b3
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <mmc.h>
+#include <dm.h>
+#include <linux/compat.h>
+#include <linux/dma-direction.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <power/regulator.h>
+#include <asm/unaligned.h>
+
+#include "matsushita-common.h"
+
+static const struct dm_mmc_ops renesas_sdhi_ops = {
+       .send_cmd = matsu_sd_send_cmd,
+       .set_ios = matsu_sd_set_ios,
+       .get_cd = matsu_sd_get_cd,
+};
+
+static const struct udevice_id renesas_sdhi_match[] = {
+       { .compatible = "renesas,sdhi-r8a7790", .data = 0 },
+       { .compatible = "renesas,sdhi-r8a7791", .data = 0 },
+       { .compatible = "renesas,sdhi-r8a7792", .data = 0 },
+       { .compatible = "renesas,sdhi-r8a7793", .data = 0 },
+       { .compatible = "renesas,sdhi-r8a7794", .data = 0 },
+       { .compatible = "renesas,sdhi-r8a7795", .data = MATSU_SD_CAP_64BIT },
+       { .compatible = "renesas,sdhi-r8a7796", .data = MATSU_SD_CAP_64BIT },
+       { .compatible = "renesas,sdhi-r8a77965", .data = MATSU_SD_CAP_64BIT },
+       { .compatible = "renesas,sdhi-r8a77970", .data = MATSU_SD_CAP_64BIT },
+       { .compatible = "renesas,sdhi-r8a77995", .data = MATSU_SD_CAP_64BIT },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(renesas_sdhi) = {
+       .name = "renesas-sdhi",
+       .id = UCLASS_MMC,
+       .of_match = renesas_sdhi_match,
+       .bind = matsu_sd_bind,
+       .probe = matsu_sd_probe,
+       .priv_auto_alloc_size = sizeof(struct matsu_sd_priv),
+       .platdata_auto_alloc_size = sizeof(struct matsu_sd_plat),
+       .ops = &renesas_sdhi_ops,
+};
index 525b1702b965b5f821a00add47d18b4bdc09da3d..72f0d4675826d62b20753dbfae8c2543da3a54ba 100644 (file)
 #include <power/regulator.h>
 #include <asm/unaligned.h>
 
-DECLARE_GLOBAL_DATA_PTR;
-
-#define UNIPHIER_SD_CMD                        0x000   /* command */
-#define   UNIPHIER_SD_CMD_NOSTOP       BIT(14) /* No automatic CMD12 issue */
-#define   UNIPHIER_SD_CMD_MULTI                BIT(13) /* multiple block transfer */
-#define   UNIPHIER_SD_CMD_RD           BIT(12) /* 1: read, 0: write */
-#define   UNIPHIER_SD_CMD_DATA         BIT(11) /* data transfer */
-#define   UNIPHIER_SD_CMD_APP          BIT(6)  /* ACMD preceded by CMD55 */
-#define   UNIPHIER_SD_CMD_NORMAL       (0 << 8)/* auto-detect of resp-type */
-#define   UNIPHIER_SD_CMD_RSP_NONE     (3 << 8)/* response: none */
-#define   UNIPHIER_SD_CMD_RSP_R1       (4 << 8)/* response: R1, R5, R6, R7 */
-#define   UNIPHIER_SD_CMD_RSP_R1B      (5 << 8)/* response: R1b, R5b */
-#define   UNIPHIER_SD_CMD_RSP_R2       (6 << 8)/* response: R2 */
-#define   UNIPHIER_SD_CMD_RSP_R3       (7 << 8)/* response: R3, R4 */
-#define UNIPHIER_SD_ARG                        0x008   /* command argument */
-#define UNIPHIER_SD_STOP               0x010   /* stop action control */
-#define   UNIPHIER_SD_STOP_SEC         BIT(8)  /* use sector count */
-#define   UNIPHIER_SD_STOP_STP         BIT(0)  /* issue CMD12 */
-#define UNIPHIER_SD_SECCNT             0x014   /* sector counter */
-#define UNIPHIER_SD_RSP10              0x018   /* response[39:8] */
-#define UNIPHIER_SD_RSP32              0x020   /* response[71:40] */
-#define UNIPHIER_SD_RSP54              0x028   /* response[103:72] */
-#define UNIPHIER_SD_RSP76              0x030   /* response[127:104] */
-#define UNIPHIER_SD_INFO1              0x038   /* IRQ status 1 */
-#define   UNIPHIER_SD_INFO1_CD         BIT(5)  /* state of card detect */
-#define   UNIPHIER_SD_INFO1_INSERT     BIT(4)  /* card inserted */
-#define   UNIPHIER_SD_INFO1_REMOVE     BIT(3)  /* card removed */
-#define   UNIPHIER_SD_INFO1_CMP                BIT(2)  /* data complete */
-#define   UNIPHIER_SD_INFO1_RSP                BIT(0)  /* response complete */
-#define UNIPHIER_SD_INFO2              0x03c   /* IRQ status 2 */
-#define   UNIPHIER_SD_INFO2_ERR_ILA    BIT(15) /* illegal access err */
-#define   UNIPHIER_SD_INFO2_CBSY       BIT(14) /* command busy */
-#define   UNIPHIER_SD_INFO2_BWE                BIT(9)  /* write buffer ready */
-#define   UNIPHIER_SD_INFO2_BRE                BIT(8)  /* read buffer ready */
-#define   UNIPHIER_SD_INFO2_DAT0       BIT(7)  /* SDDAT0 */
-#define   UNIPHIER_SD_INFO2_ERR_RTO    BIT(6)  /* response time out */
-#define   UNIPHIER_SD_INFO2_ERR_ILR    BIT(5)  /* illegal read err */
-#define   UNIPHIER_SD_INFO2_ERR_ILW    BIT(4)  /* illegal write err */
-#define   UNIPHIER_SD_INFO2_ERR_TO     BIT(3)  /* time out error */
-#define   UNIPHIER_SD_INFO2_ERR_END    BIT(2)  /* END bit error */
-#define   UNIPHIER_SD_INFO2_ERR_CRC    BIT(1)  /* CRC error */
-#define   UNIPHIER_SD_INFO2_ERR_IDX    BIT(0)  /* cmd index error */
-#define UNIPHIER_SD_INFO1_MASK         0x040
-#define UNIPHIER_SD_INFO2_MASK         0x044
-#define UNIPHIER_SD_CLKCTL             0x048   /* clock divisor */
-#define   UNIPHIER_SD_CLKCTL_DIV_MASK  0x104ff
-#define   UNIPHIER_SD_CLKCTL_DIV1024   BIT(16) /* SDCLK = CLK / 1024 */
-#define   UNIPHIER_SD_CLKCTL_DIV512    BIT(7)  /* SDCLK = CLK / 512 */
-#define   UNIPHIER_SD_CLKCTL_DIV256    BIT(6)  /* SDCLK = CLK / 256 */
-#define   UNIPHIER_SD_CLKCTL_DIV128    BIT(5)  /* SDCLK = CLK / 128 */
-#define   UNIPHIER_SD_CLKCTL_DIV64     BIT(4)  /* SDCLK = CLK / 64 */
-#define   UNIPHIER_SD_CLKCTL_DIV32     BIT(3)  /* SDCLK = CLK / 32 */
-#define   UNIPHIER_SD_CLKCTL_DIV16     BIT(2)  /* SDCLK = CLK / 16 */
-#define   UNIPHIER_SD_CLKCTL_DIV8      BIT(1)  /* SDCLK = CLK / 8 */
-#define   UNIPHIER_SD_CLKCTL_DIV4      BIT(0)  /* SDCLK = CLK / 4 */
-#define   UNIPHIER_SD_CLKCTL_DIV2      0       /* SDCLK = CLK / 2 */
-#define   UNIPHIER_SD_CLKCTL_DIV1      BIT(10) /* SDCLK = CLK */
-#define   UNIPHIER_SD_CLKCTL_OFFEN     BIT(9)  /* stop SDCLK when unused */
-#define   UNIPHIER_SD_CLKCTL_SCLKEN    BIT(8)  /* SDCLK output enable */
-#define UNIPHIER_SD_SIZE               0x04c   /* block size */
-#define UNIPHIER_SD_OPTION             0x050
-#define   UNIPHIER_SD_OPTION_WIDTH_MASK        (5 << 13)
-#define   UNIPHIER_SD_OPTION_WIDTH_1   (4 << 13)
-#define   UNIPHIER_SD_OPTION_WIDTH_4   (0 << 13)
-#define   UNIPHIER_SD_OPTION_WIDTH_8   (1 << 13)
-#define UNIPHIER_SD_BUF                        0x060   /* read/write buffer */
-#define UNIPHIER_SD_EXTMODE            0x1b0
-#define   UNIPHIER_SD_EXTMODE_DMA_EN   BIT(1)  /* transfer 1: DMA, 0: pio */
-#define UNIPHIER_SD_SOFT_RST           0x1c0
-#define UNIPHIER_SD_SOFT_RST_RSTX      BIT(0)  /* reset deassert */
-#define UNIPHIER_SD_VERSION            0x1c4   /* version register */
-#define UNIPHIER_SD_VERSION_IP         0xff    /* IP version */
-#define UNIPHIER_SD_HOST_MODE          0x1c8
-#define UNIPHIER_SD_IF_MODE            0x1cc
-#define   UNIPHIER_SD_IF_MODE_DDR      BIT(0)  /* DDR mode */
-#define UNIPHIER_SD_VOLT               0x1e4   /* voltage switch */
-#define   UNIPHIER_SD_VOLT_MASK                (3 << 0)
-#define   UNIPHIER_SD_VOLT_OFF         (0 << 0)
-#define   UNIPHIER_SD_VOLT_330         (1 << 0)/* 3.3V signal */
-#define   UNIPHIER_SD_VOLT_180         (2 << 0)/* 1.8V signal */
-#define UNIPHIER_SD_DMA_MODE           0x410
-#define   UNIPHIER_SD_DMA_MODE_DIR_RD  BIT(16) /* 1: from device, 0: to dev */
-#define   UNIPHIER_SD_DMA_MODE_ADDR_INC        BIT(0)  /* 1: address inc, 0: fixed */
-#define UNIPHIER_SD_DMA_CTL            0x414
-#define   UNIPHIER_SD_DMA_CTL_START    BIT(0)  /* start DMA (auto cleared) */
-#define UNIPHIER_SD_DMA_RST            0x418
-#define   UNIPHIER_SD_DMA_RST_RD       BIT(9)
-#define   UNIPHIER_SD_DMA_RST_WR       BIT(8)
-#define UNIPHIER_SD_DMA_INFO1          0x420
-#define   UNIPHIER_SD_DMA_INFO1_END_RD2        BIT(20) /* DMA from device is complete*/
-#define   UNIPHIER_SD_DMA_INFO1_END_RD BIT(17) /* Don't use!  Hardware bug */
-#define   UNIPHIER_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */
-#define UNIPHIER_SD_DMA_INFO1_MASK     0x424
-#define UNIPHIER_SD_DMA_INFO2          0x428
-#define   UNIPHIER_SD_DMA_INFO2_ERR_RD BIT(17)
-#define   UNIPHIER_SD_DMA_INFO2_ERR_WR BIT(16)
-#define UNIPHIER_SD_DMA_INFO2_MASK     0x42c
-#define UNIPHIER_SD_DMA_ADDR_L         0x440
-#define UNIPHIER_SD_DMA_ADDR_H         0x444
-
-/* alignment required by the DMA engine of this controller */
-#define UNIPHIER_SD_DMA_MINALIGN       0x10
-
-struct uniphier_sd_plat {
-       struct mmc_config cfg;
-       struct mmc mmc;
-};
-
-struct uniphier_sd_priv {
-       void __iomem *regbase;
-       unsigned long mclk;
-       unsigned int version;
-       u32 caps;
-#define UNIPHIER_SD_CAP_NONREMOVABLE   BIT(0)  /* Nonremovable e.g. eMMC */
-#define UNIPHIER_SD_CAP_DMA_INTERNAL   BIT(1)  /* have internal DMA engine */
-#define UNIPHIER_SD_CAP_DIV1024                BIT(2)  /* divisor 1024 is available */
-#define UNIPHIER_SD_CAP_64BIT          BIT(3)  /* Controller is 64bit */
-};
-
-static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg)
-{
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT)
-               return readq(priv->regbase + (reg << 1));
-       else
-               return readq(priv->regbase + reg);
-}
-
-static void uniphier_sd_writeq(struct uniphier_sd_priv *priv,
-                              u64 val, unsigned int reg)
-{
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT)
-               writeq(val, priv->regbase + (reg << 1));
-       else
-               writeq(val, priv->regbase + reg);
-}
-
-static u32 uniphier_sd_readl(struct uniphier_sd_priv *priv, unsigned int reg)
-{
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT)
-               return readl(priv->regbase + (reg << 1));
-       else
-               return readl(priv->regbase + reg);
-}
-
-static void uniphier_sd_writel(struct uniphier_sd_priv *priv,
-                              u32 val, unsigned int reg)
-{
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT)
-               writel(val, priv->regbase + (reg << 1));
-       else
-               writel(val, priv->regbase + reg);
-}
-
-static dma_addr_t __dma_map_single(void *ptr, size_t size,
-                                  enum dma_data_direction dir)
-{
-       unsigned long addr = (unsigned long)ptr;
-
-       if (dir == DMA_FROM_DEVICE)
-               invalidate_dcache_range(addr, addr + size);
-       else
-               flush_dcache_range(addr, addr + size);
-
-       return addr;
-}
-
-static void __dma_unmap_single(dma_addr_t addr, size_t size,
-                              enum dma_data_direction dir)
-{
-       if (dir != DMA_TO_DEVICE)
-               invalidate_dcache_range(addr, addr + size);
-}
-
-static int uniphier_sd_check_error(struct udevice *dev)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       u32 info2 = uniphier_sd_readl(priv, UNIPHIER_SD_INFO2);
-
-       if (info2 & UNIPHIER_SD_INFO2_ERR_RTO) {
-               /*
-                * TIMEOUT must be returned for unsupported command.  Do not
-                * display error log since this might be a part of sequence to
-                * distinguish between SD and MMC.
-                */
-               return -ETIMEDOUT;
-       }
-
-       if (info2 & UNIPHIER_SD_INFO2_ERR_TO) {
-               dev_err(dev, "timeout error\n");
-               return -ETIMEDOUT;
-       }
-
-       if (info2 & (UNIPHIER_SD_INFO2_ERR_END | UNIPHIER_SD_INFO2_ERR_CRC |
-                    UNIPHIER_SD_INFO2_ERR_IDX)) {
-               dev_err(dev, "communication out of sync\n");
-               return -EILSEQ;
-       }
-
-       if (info2 & (UNIPHIER_SD_INFO2_ERR_ILA | UNIPHIER_SD_INFO2_ERR_ILR |
-                    UNIPHIER_SD_INFO2_ERR_ILW)) {
-               dev_err(dev, "illegal access\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int uniphier_sd_wait_for_irq(struct udevice *dev, unsigned int reg,
-                                   u32 flag)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       long wait = 1000000;
-       int ret;
-
-       while (!(uniphier_sd_readl(priv, reg) & flag)) {
-               if (wait-- < 0) {
-                       dev_err(dev, "timeout\n");
-                       return -ETIMEDOUT;
-               }
-
-               ret = uniphier_sd_check_error(dev);
-               if (ret)
-                       return ret;
-
-               udelay(1);
-       }
-
-       return 0;
-}
-
-static int uniphier_sd_pio_read_one_block(struct udevice *dev, char *pbuf,
-                                         uint blocksize)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       int i, ret;
-
-       /* wait until the buffer is filled with data */
-       ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO2,
-                                      UNIPHIER_SD_INFO2_BRE);
-       if (ret)
-               return ret;
-
-       /*
-        * Clear the status flag _before_ read the buffer out because
-        * UNIPHIER_SD_INFO2_BRE is edge-triggered, not level-triggered.
-        */
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT) {
-               u64 *buf = (u64 *)pbuf;
-               if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
-                       for (i = 0; i < blocksize / 8; i++) {
-                               *buf++ = uniphier_sd_readq(priv,
-                                                          UNIPHIER_SD_BUF);
-                       }
-               } else {
-                       for (i = 0; i < blocksize / 8; i++) {
-                               u64 data;
-                               data = uniphier_sd_readq(priv,
-                                                        UNIPHIER_SD_BUF);
-                               put_unaligned(data, buf++);
-                       }
-               }
-       } else {
-               u32 *buf = (u32 *)pbuf;
-               if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
-                       for (i = 0; i < blocksize / 4; i++) {
-                               *buf++ = uniphier_sd_readl(priv,
-                                                          UNIPHIER_SD_BUF);
-                       }
-               } else {
-                       for (i = 0; i < blocksize / 4; i++) {
-                               u32 data;
-                               data = uniphier_sd_readl(priv, UNIPHIER_SD_BUF);
-                               put_unaligned(data, buf++);
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int uniphier_sd_pio_write_one_block(struct udevice *dev,
-                                          const char *pbuf, uint blocksize)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       int i, ret;
-
-       /* wait until the buffer becomes empty */
-       ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO2,
-                                      UNIPHIER_SD_INFO2_BWE);
-       if (ret)
-               return ret;
-
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
-       if (priv->caps & UNIPHIER_SD_CAP_64BIT) {
-               const u64 *buf = (const u64 *)pbuf;
-               if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
-                       for (i = 0; i < blocksize / 8; i++) {
-                               uniphier_sd_writeq(priv, *buf++,
-                                                  UNIPHIER_SD_BUF);
-                       }
-               } else {
-                       for (i = 0; i < blocksize / 8; i++) {
-                               u64 data = get_unaligned(buf++);
-                               uniphier_sd_writeq(priv, data,
-                                                  UNIPHIER_SD_BUF);
-                       }
-               }
-       } else {
-               const u32 *buf = (const u32 *)pbuf;
-               if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
-                       for (i = 0; i < blocksize / 4; i++) {
-                               uniphier_sd_writel(priv, *buf++,
-                                                  UNIPHIER_SD_BUF);
-                       }
-               } else {
-                       for (i = 0; i < blocksize / 4; i++) {
-                               u32 data = get_unaligned(buf++);
-                               uniphier_sd_writel(priv, data,
-                                                  UNIPHIER_SD_BUF);
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int uniphier_sd_pio_xfer(struct udevice *dev, struct mmc_data *data)
-{
-       const char *src = data->src;
-       char *dest = data->dest;
-       int i, ret;
-
-       for (i = 0; i < data->blocks; i++) {
-               if (data->flags & MMC_DATA_READ)
-                       ret = uniphier_sd_pio_read_one_block(dev, dest,
-                                                            data->blocksize);
-               else
-                       ret = uniphier_sd_pio_write_one_block(dev, src,
-                                                             data->blocksize);
-               if (ret)
-                       return ret;
-
-               if (data->flags & MMC_DATA_READ)
-                       dest += data->blocksize;
-               else
-                       src += data->blocksize;
-       }
-
-       return 0;
-}
-
-static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
-                                 dma_addr_t dma_addr)
-{
-       u32 tmp;
-
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO1);
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO2);
-
-       /* enable DMA */
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE);
-       tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE);
-
-       uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_L);
-
-       /* suppress the warning "right shift count >= width of type" */
-       dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
-
-       uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_H);
-
-       uniphier_sd_writel(priv, UNIPHIER_SD_DMA_CTL_START, UNIPHIER_SD_DMA_CTL);
-}
-
-static int uniphier_sd_dma_wait_for_irq(struct udevice *dev, u32 flag,
-                                       unsigned int blocks)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       long wait = 1000000 + 10 * blocks;
-
-       while (!(uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO1) & flag)) {
-               if (wait-- < 0) {
-                       dev_err(dev, "timeout during DMA\n");
-                       return -ETIMEDOUT;
-               }
-
-               udelay(10);
-       }
-
-       if (uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO2)) {
-               dev_err(dev, "error during DMA\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int uniphier_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       size_t len = data->blocks * data->blocksize;
-       void *buf;
-       enum dma_data_direction dir;
-       dma_addr_t dma_addr;
-       u32 poll_flag, tmp;
-       int ret;
-
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE);
-
-       if (data->flags & MMC_DATA_READ) {
-               buf = data->dest;
-               dir = DMA_FROM_DEVICE;
-               poll_flag = UNIPHIER_SD_DMA_INFO1_END_RD2;
-               tmp |= UNIPHIER_SD_DMA_MODE_DIR_RD;
-       } else {
-               buf = (void *)data->src;
-               dir = DMA_TO_DEVICE;
-               poll_flag = UNIPHIER_SD_DMA_INFO1_END_WR;
-               tmp &= ~UNIPHIER_SD_DMA_MODE_DIR_RD;
-       }
-
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE);
-
-       dma_addr = __dma_map_single(buf, len, dir);
-
-       uniphier_sd_dma_start(priv, dma_addr);
-
-       ret = uniphier_sd_dma_wait_for_irq(dev, poll_flag, data->blocks);
-
-       __dma_unmap_single(dma_addr, len, dir);
-
-       return ret;
-}
-
-/* check if the address is DMA'able */
-static bool uniphier_sd_addr_is_dmaable(unsigned long addr)
-{
-       if (!IS_ALIGNED(addr, UNIPHIER_SD_DMA_MINALIGN))
-               return false;
-
-#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \
-       defined(CONFIG_SPL_BUILD)
-       /*
-        * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways
-        * of L2, which is unreachable from the DMA engine.
-        */
-       if (addr < CONFIG_SPL_STACK)
-               return false;
-#endif
-
-       return true;
-}
-
-static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
-                               struct mmc_data *data)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       int ret;
-       u32 tmp;
-
-       if (uniphier_sd_readl(priv, UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) {
-               dev_err(dev, "command busy\n");
-               return -EBUSY;
-       }
-
-       /* clear all status flags */
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO1);
-       uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
-       /* disable DMA once */
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE);
-       tmp &= ~UNIPHIER_SD_EXTMODE_DMA_EN;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE);
-
-       uniphier_sd_writel(priv, cmd->cmdarg, UNIPHIER_SD_ARG);
-
-       tmp = cmd->cmdidx;
-
-       if (data) {
-               uniphier_sd_writel(priv, data->blocksize, UNIPHIER_SD_SIZE);
-               uniphier_sd_writel(priv, data->blocks, UNIPHIER_SD_SECCNT);
-
-               /* Do not send CMD12 automatically */
-               tmp |= UNIPHIER_SD_CMD_NOSTOP | UNIPHIER_SD_CMD_DATA;
-
-               if (data->blocks > 1)
-                       tmp |= UNIPHIER_SD_CMD_MULTI;
-
-               if (data->flags & MMC_DATA_READ)
-                       tmp |= UNIPHIER_SD_CMD_RD;
-       }
-
-       /*
-        * Do not use the response type auto-detection on this hardware.
-        * CMD8, for example, has different response types on SD and eMMC,
-        * while this controller always assumes the response type for SD.
-        * Set the response type manually.
-        */
-       switch (cmd->resp_type) {
-       case MMC_RSP_NONE:
-               tmp |= UNIPHIER_SD_CMD_RSP_NONE;
-               break;
-       case MMC_RSP_R1:
-               tmp |= UNIPHIER_SD_CMD_RSP_R1;
-               break;
-       case MMC_RSP_R1b:
-               tmp |= UNIPHIER_SD_CMD_RSP_R1B;
-               break;
-       case MMC_RSP_R2:
-               tmp |= UNIPHIER_SD_CMD_RSP_R2;
-               break;
-       case MMC_RSP_R3:
-               tmp |= UNIPHIER_SD_CMD_RSP_R3;
-               break;
-       default:
-               dev_err(dev, "unknown response type\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n",
-               cmd->cmdidx, tmp, cmd->cmdarg);
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CMD);
-
-       ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO1,
-                                      UNIPHIER_SD_INFO1_RSP);
-       if (ret)
-               return ret;
-
-       if (cmd->resp_type & MMC_RSP_136) {
-               u32 rsp_127_104 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP76);
-               u32 rsp_103_72 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP54);
-               u32 rsp_71_40 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP32);
-               u32 rsp_39_8 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10);
-
-               cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) |
-                                  ((rsp_103_72  & 0xff000000) >> 24);
-               cmd->response[1] = ((rsp_103_72  & 0x00ffffff) << 8) |
-                                  ((rsp_71_40   & 0xff000000) >> 24);
-               cmd->response[2] = ((rsp_71_40   & 0x00ffffff) << 8) |
-                                  ((rsp_39_8    & 0xff000000) >> 24);
-               cmd->response[3] = (rsp_39_8     & 0xffffff)   << 8;
-       } else {
-               /* bit 39-8 */
-               cmd->response[0] = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10);
-       }
-
-       if (data) {
-               /* use DMA if the HW supports it and the buffer is aligned */
-               if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL &&
-                   uniphier_sd_addr_is_dmaable((long)data->src))
-                       ret = uniphier_sd_dma_xfer(dev, data);
-               else
-                       ret = uniphier_sd_pio_xfer(dev, data);
-
-               ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO1,
-                                              UNIPHIER_SD_INFO1_CMP);
-               if (ret)
-                       return ret;
-       }
-
-       return ret;
-}
-
-static int uniphier_sd_set_bus_width(struct uniphier_sd_priv *priv,
-                                    struct mmc *mmc)
-{
-       u32 val, tmp;
-
-       switch (mmc->bus_width) {
-       case 1:
-               val = UNIPHIER_SD_OPTION_WIDTH_1;
-               break;
-       case 4:
-               val = UNIPHIER_SD_OPTION_WIDTH_4;
-               break;
-       case 8:
-               val = UNIPHIER_SD_OPTION_WIDTH_8;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_OPTION);
-       tmp &= ~UNIPHIER_SD_OPTION_WIDTH_MASK;
-       tmp |= val;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_OPTION);
-
-       return 0;
-}
-
-static void uniphier_sd_set_ddr_mode(struct uniphier_sd_priv *priv,
-                                    struct mmc *mmc)
-{
-       u32 tmp;
-
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_IF_MODE);
-       if (mmc->ddr_mode)
-               tmp |= UNIPHIER_SD_IF_MODE_DDR;
-       else
-               tmp &= ~UNIPHIER_SD_IF_MODE_DDR;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_IF_MODE);
-}
-
-static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv,
-                                    struct mmc *mmc)
-{
-       unsigned int divisor;
-       u32 val, tmp;
-
-       if (!mmc->clock)
-               return;
-
-       divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
-
-       if (divisor <= 1)
-               val = UNIPHIER_SD_CLKCTL_DIV1;
-       else if (divisor <= 2)
-               val = UNIPHIER_SD_CLKCTL_DIV2;
-       else if (divisor <= 4)
-               val = UNIPHIER_SD_CLKCTL_DIV4;
-       else if (divisor <= 8)
-               val = UNIPHIER_SD_CLKCTL_DIV8;
-       else if (divisor <= 16)
-               val = UNIPHIER_SD_CLKCTL_DIV16;
-       else if (divisor <= 32)
-               val = UNIPHIER_SD_CLKCTL_DIV32;
-       else if (divisor <= 64)
-               val = UNIPHIER_SD_CLKCTL_DIV64;
-       else if (divisor <= 128)
-               val = UNIPHIER_SD_CLKCTL_DIV128;
-       else if (divisor <= 256)
-               val = UNIPHIER_SD_CLKCTL_DIV256;
-       else if (divisor <= 512 || !(priv->caps & UNIPHIER_SD_CAP_DIV1024))
-               val = UNIPHIER_SD_CLKCTL_DIV512;
-       else
-               val = UNIPHIER_SD_CLKCTL_DIV1024;
-
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL);
-       if (tmp & UNIPHIER_SD_CLKCTL_SCLKEN &&
-           (tmp & UNIPHIER_SD_CLKCTL_DIV_MASK) == val)
-               return;
-
-       /* stop the clock before changing its rate to avoid a glitch signal */
-       tmp &= ~UNIPHIER_SD_CLKCTL_SCLKEN;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
-       tmp &= ~UNIPHIER_SD_CLKCTL_DIV_MASK;
-       tmp |= val | UNIPHIER_SD_CLKCTL_OFFEN;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
-       tmp |= UNIPHIER_SD_CLKCTL_SCLKEN;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
-       udelay(1000);
-}
-
-static int uniphier_sd_set_ios(struct udevice *dev)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       struct mmc *mmc = mmc_get_mmc_dev(dev);
-       int ret;
-
-       dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n",
-               mmc->clock, mmc->ddr_mode, mmc->bus_width);
-
-       ret = uniphier_sd_set_bus_width(priv, mmc);
-       if (ret)
-               return ret;
-       uniphier_sd_set_ddr_mode(priv, mmc);
-       uniphier_sd_set_clk_rate(priv, mmc);
-
-       return 0;
-}
-
-static int uniphier_sd_get_cd(struct udevice *dev)
-{
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-
-       if (priv->caps & UNIPHIER_SD_CAP_NONREMOVABLE)
-               return 1;
-
-       return !!(uniphier_sd_readl(priv, UNIPHIER_SD_INFO1) &
-                 UNIPHIER_SD_INFO1_CD);
-}
+#include "matsushita-common.h"
 
 static const struct dm_mmc_ops uniphier_sd_ops = {
-       .send_cmd = uniphier_sd_send_cmd,
-       .set_ios = uniphier_sd_set_ios,
-       .get_cd = uniphier_sd_get_cd,
+       .send_cmd = matsu_sd_send_cmd,
+       .set_ios = matsu_sd_set_ios,
+       .get_cd = matsu_sd_get_cd,
 };
 
-static void uniphier_sd_host_init(struct uniphier_sd_priv *priv)
-{
-       u32 tmp;
-
-       /* soft reset of the host */
-       tmp = uniphier_sd_readl(priv, UNIPHIER_SD_SOFT_RST);
-       tmp &= ~UNIPHIER_SD_SOFT_RST_RSTX;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST);
-       tmp |= UNIPHIER_SD_SOFT_RST_RSTX;
-       uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST);
-
-       /* FIXME: implement eMMC hw_reset */
-
-       uniphier_sd_writel(priv, UNIPHIER_SD_STOP_SEC, UNIPHIER_SD_STOP);
-
-       /*
-        * Connected to 32bit AXI.
-        * This register dropped backward compatibility at version 0x10.
-        * Write an appropriate value depending on the IP version.
-        */
-       uniphier_sd_writel(priv, priv->version >= 0x10 ? 0x00000101 : 0x00000000,
-                          UNIPHIER_SD_HOST_MODE);
-
-       if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) {
-               tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE);
-               tmp |= UNIPHIER_SD_DMA_MODE_ADDR_INC;
-               uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE);
-       }
-}
-
-static int uniphier_sd_bind(struct udevice *dev)
-{
-       struct uniphier_sd_plat *plat = dev_get_platdata(dev);
-
-       return mmc_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static int uniphier_sd_probe(struct udevice *dev)
-{
-       struct uniphier_sd_plat *plat = dev_get_platdata(dev);
-       struct uniphier_sd_priv *priv = dev_get_priv(dev);
-       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
-       const u32 quirks = dev_get_driver_data(dev);
-       fdt_addr_t base;
-       struct clk clk;
-       int ret;
-#ifdef CONFIG_DM_REGULATOR
-       struct udevice *vqmmc_dev;
-#endif
-
-       base = devfdt_get_addr(dev);
-       if (base == FDT_ADDR_T_NONE)
-               return -EINVAL;
-
-       priv->regbase = devm_ioremap(dev, base, SZ_2K);
-       if (!priv->regbase)
-               return -ENOMEM;
-
-#ifdef CONFIG_DM_REGULATOR
-       ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev);
-       if (!ret) {
-               /* Set the regulator to 3.3V until we support 1.8V modes */
-               regulator_set_value(vqmmc_dev, 3300000);
-               regulator_set_enable(vqmmc_dev, true);
-       }
-#endif
-
-       ret = clk_get_by_index(dev, 0, &clk);
-       if (ret < 0) {
-               dev_err(dev, "failed to get host clock\n");
-               return ret;
-       }
-
-       /* set to max rate */
-       priv->mclk = clk_set_rate(&clk, ULONG_MAX);
-       if (IS_ERR_VALUE(priv->mclk)) {
-               dev_err(dev, "failed to set rate for host clock\n");
-               clk_free(&clk);
-               return priv->mclk;
-       }
-
-       ret = clk_enable(&clk);
-       clk_free(&clk);
-       if (ret) {
-               dev_err(dev, "failed to enable host clock\n");
-               return ret;
-       }
-
-       plat->cfg.name = dev->name;
-       plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
-
-       switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
-                              1)) {
-       case 8:
-               plat->cfg.host_caps |= MMC_MODE_8BIT;
-               break;
-       case 4:
-               plat->cfg.host_caps |= MMC_MODE_4BIT;
-               break;
-       case 1:
-               break;
-       default:
-               dev_err(dev, "Invalid \"bus-width\" value\n");
-               return -EINVAL;
-       }
-
-       if (quirks) {
-               priv->caps = quirks;
-       } else {
-               priv->version = uniphier_sd_readl(priv, UNIPHIER_SD_VERSION) &
-                                                       UNIPHIER_SD_VERSION_IP;
-               dev_dbg(dev, "version %x\n", priv->version);
-               if (priv->version >= 0x10) {
-                       priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL;
-                       priv->caps |= UNIPHIER_SD_CAP_DIV1024;
-               }
-       }
-
-       if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
-                            NULL))
-               priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE;
-
-       uniphier_sd_host_init(priv);
-
-       plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
-       plat->cfg.f_min = priv->mclk /
-                       (priv->caps & UNIPHIER_SD_CAP_DIV1024 ? 1024 : 512);
-       plat->cfg.f_max = priv->mclk;
-       plat->cfg.b_max = U32_MAX; /* max value of UNIPHIER_SD_SECCNT */
-
-       upriv->mmc = &plat->mmc;
-
-       return 0;
-}
-
 static const struct udevice_id uniphier_sd_match[] = {
-       { .compatible = "renesas,sdhi-r8a7790", .data = 0 },
-       { .compatible = "renesas,sdhi-r8a7791", .data = 0 },
-       { .compatible = "renesas,sdhi-r8a7792", .data = 0 },
-       { .compatible = "renesas,sdhi-r8a7793", .data = 0 },
-       { .compatible = "renesas,sdhi-r8a7794", .data = 0 },
-       { .compatible = "renesas,sdhi-r8a7795", .data = UNIPHIER_SD_CAP_64BIT },
-       { .compatible = "renesas,sdhi-r8a7796", .data = UNIPHIER_SD_CAP_64BIT },
-       { .compatible = "renesas,sdhi-r8a77965", .data = UNIPHIER_SD_CAP_64BIT },
-       { .compatible = "renesas,sdhi-r8a77970", .data = UNIPHIER_SD_CAP_64BIT },
-       { .compatible = "renesas,sdhi-r8a77995", .data = UNIPHIER_SD_CAP_64BIT },
        { .compatible = "socionext,uniphier-sdhc", .data = 0 },
        { /* sentinel */ }
 };
@@ -865,9 +34,9 @@ U_BOOT_DRIVER(uniphier_mmc) = {
        .name = "uniphier-mmc",
        .id = UCLASS_MMC,
        .of_match = uniphier_sd_match,
-       .bind = uniphier_sd_bind,
-       .probe = uniphier_sd_probe,
-       .priv_auto_alloc_size = sizeof(struct uniphier_sd_priv),
-       .platdata_auto_alloc_size = sizeof(struct uniphier_sd_plat),
+       .bind = matsu_sd_bind,
+       .probe = matsu_sd_probe,
+       .priv_auto_alloc_size = sizeof(struct matsu_sd_priv),
+       .platdata_auto_alloc_size = sizeof(struct matsu_sd_plat),
        .ops = &uniphier_sd_ops,
 };