mmc: jz_mmc: Compile-out write support if disabled
[oweals/u-boot.git] / drivers / mmc / sh_sdhi.c
index d181b6390586683cb61503fc136e8543f66951f7..e38e8abfef40a9e1aa66f421ecbfc2ab356d930a 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * drivers/mmc/sh_sdhi.c
  *
@@ -6,28 +7,31 @@
  * Copyright (C) 2011,2013-2017 Renesas Electronics Corporation
  * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
  * Copyright (C) 2008-2009 Renesas Solutions Corp.
- *
- * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
 #include <malloc.h>
 #include <mmc.h>
+#include <dm.h>
 #include <linux/errno.h>
-#include <asm/io.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
 #include <asm/arch/rmobile.h>
 #include <asm/arch/sh_sdhi.h>
+#include <clk.h>
 
 #define DRIVER_NAME "sh-sdhi"
 
 struct sh_sdhi_host {
-       unsigned long addr;
+       void __iomem *addr;
        int ch;
        int bus_shift;
        unsigned long quirks;
        unsigned char wait_int;
        unsigned char sd_error;
        unsigned char detect_waiting;
+       unsigned char app_cmd;
 };
 
 static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
@@ -50,11 +54,6 @@ static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
        return readw(host->addr + (reg << host->bus_shift));
 }
 
-static void *mmc_priv(struct mmc *mmc)
-{
-       return (void *)mmc->priv;
-}
-
 static void sh_sdhi_detect(struct sh_sdhi_host *host)
 {
        sh_sdhi_writew(host, SDHI_OPTION,
@@ -477,65 +476,64 @@ static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
 static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
                        struct mmc_data *data, unsigned short opc)
 {
-       switch (opc) {
-       case SD_CMD_APP_SEND_OP_COND:
-       case SD_CMD_APP_SEND_SCR:
-               opc |= SDHI_APP;
-               break;
-       case SD_CMD_APP_SET_BUS_WIDTH:
-                /* SD_APP_SET_BUS_WIDTH*/
+       if (host->app_cmd) {
                if (!data)
-                       opc |= SDHI_APP;
-               else /* SD_SWITCH */
-                       opc = SDHI_SD_SWITCH;
-               break;
-       case MMC_CMD_SEND_OP_COND:
-               opc = SDHI_MMC_SEND_OP_COND;
-               break;
+                       host->app_cmd = 0;
+               return opc | BIT(6);
+       }
+
+       switch (opc) {
+       case MMC_CMD_SWITCH:
+               return opc | (data ? 0x1c00 : 0x40);
        case MMC_CMD_SEND_EXT_CSD:
-               if (data)
-                       opc = SDHI_MMC_SEND_EXT_CSD;
-               break;
+               return opc | (data ? 0x1c00 : 0);
+       case MMC_CMD_SEND_OP_COND:
+               return opc | 0x0700;
+       case MMC_CMD_APP_CMD:
+               host->app_cmd = 1;
        default:
-               break;
+               return opc;
        }
-       return opc;
 }
 
 static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
                        struct mmc_data *data, unsigned short opc)
 {
-       unsigned short ret;
-
-       switch (opc) {
-       case MMC_CMD_READ_MULTIPLE_BLOCK:
-               ret = sh_sdhi_multi_read(host, data);
-               break;
-       case MMC_CMD_WRITE_MULTIPLE_BLOCK:
-               ret = sh_sdhi_multi_write(host, data);
-               break;
-       case MMC_CMD_WRITE_SINGLE_BLOCK:
-               ret = sh_sdhi_single_write(host, data);
-               break;
-       case MMC_CMD_READ_SINGLE_BLOCK:
-       case SDHI_SD_APP_SEND_SCR:
-       case SDHI_SD_SWITCH: /* SD_SWITCH */
-       case SDHI_MMC_SEND_EXT_CSD:
-               ret = sh_sdhi_single_read(host, data);
-               break;
-       default:
-               printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
-               ret = -EINVAL;
-               break;
+       if (host->app_cmd) {
+               host->app_cmd = 0;
+               switch (opc) {
+               case SD_CMD_APP_SEND_SCR:
+               case SD_CMD_APP_SD_STATUS:
+                       return sh_sdhi_single_read(host, data);
+               default:
+                       printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
+                               opc);
+                       return -EINVAL;
+               }
+       } else {
+               switch (opc) {
+               case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+                       return sh_sdhi_multi_write(host, data);
+               case MMC_CMD_READ_MULTIPLE_BLOCK:
+                       return sh_sdhi_multi_read(host, data);
+               case MMC_CMD_WRITE_SINGLE_BLOCK:
+                       return sh_sdhi_single_write(host, data);
+               case MMC_CMD_READ_SINGLE_BLOCK:
+               case MMC_CMD_SWITCH:
+               case MMC_CMD_SEND_EXT_CSD:;
+                       return sh_sdhi_single_read(host, data);
+               default:
+                       printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
+                       return -EINVAL;
+               }
        }
-       return ret;
 }
 
 static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
                        struct mmc_data *data, struct mmc_cmd *cmd)
 {
        long time;
-       unsigned short opc = cmd->cmdidx;
+       unsigned short shcmd, opc = cmd->cmdidx;
        int ret = 0;
        unsigned long timeout;
 
@@ -563,7 +561,8 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
                }
                sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
        }
-       opc = sh_sdhi_set_cmd(host, data, opc);
+
+       shcmd = sh_sdhi_set_cmd(host, data, opc);
 
        /*
         *  U-Boot cannot use interrupt.
@@ -594,11 +593,12 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
                       INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
                       sh_sdhi_readw(host, SDHI_INFO2_MASK));
 
-       sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
-
+       sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
        time = sh_sdhi_wait_interrupt_flag(host);
-       if (!time)
+       if (!time) {
+               host->app_cmd = 0;
                return sh_sdhi_error_manage(host);
+       }
 
        if (host->sd_error) {
                switch (cmd->cmdidx) {
@@ -616,15 +616,20 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
                }
                host->sd_error = 0;
                host->wait_int = 0;
+               host->app_cmd = 0;
                return ret;
        }
-       if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
+
+       if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
+               host->app_cmd = 0;
                return -EINVAL;
+       }
 
        if (host->wait_int) {
                sh_sdhi_get_response(host, cmd);
                host->wait_int = 0;
        }
+
        if (data)
                ret = sh_sdhi_data_trans(host, data, opc);
 
@@ -634,23 +639,17 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
        return ret;
 }
 
-static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-                       struct mmc_data *data)
+static int sh_sdhi_send_cmd_common(struct sh_sdhi_host *host,
+                                  struct mmc_cmd *cmd, struct mmc_data *data)
 {
-       struct sh_sdhi_host *host = mmc_priv(mmc);
-       int ret;
-
        host->sd_error = 0;
 
-       ret = sh_sdhi_start_cmd(host, data, cmd);
-
-       return ret;
+       return sh_sdhi_start_cmd(host, data, cmd);
 }
 
-static int sh_sdhi_set_ios(struct mmc *mmc)
+static int sh_sdhi_set_ios_common(struct sh_sdhi_host *host, struct mmc *mmc)
 {
        int ret;
-       struct sh_sdhi_host *host = mmc_priv(mmc);
 
        ret = sh_sdhi_clock_control(host, mmc->clock);
        if (ret)
@@ -674,9 +673,8 @@ static int sh_sdhi_set_ios(struct mmc *mmc)
        return 0;
 }
 
-static int sh_sdhi_initialize(struct mmc *mmc)
+static int sh_sdhi_initialize_common(struct sh_sdhi_host *host)
 {
-       struct sh_sdhi_host *host = mmc_priv(mmc);
        int ret = sh_sdhi_sync_reset(host);
 
        sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
@@ -692,6 +690,34 @@ static int sh_sdhi_initialize(struct mmc *mmc)
        return ret;
 }
 
+#ifndef CONFIG_DM_MMC
+static void *mmc_priv(struct mmc *mmc)
+{
+       return (void *)mmc->priv;
+}
+
+static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+                           struct mmc_data *data)
+{
+       struct sh_sdhi_host *host = mmc_priv(mmc);
+
+       return sh_sdhi_send_cmd_common(host, cmd, data);
+}
+
+static int sh_sdhi_set_ios(struct mmc *mmc)
+{
+       struct sh_sdhi_host *host = mmc_priv(mmc);
+
+       return sh_sdhi_set_ios_common(host, mmc);
+}
+
+static int sh_sdhi_initialize(struct mmc *mmc)
+{
+       struct sh_sdhi_host *host = mmc_priv(mmc);
+
+       return sh_sdhi_initialize_common(host);
+}
+
 static const struct mmc_ops sh_sdhi_ops = {
        .send_cmd       = sh_sdhi_send_cmd,
        .set_ios        = sh_sdhi_set_ios,
@@ -743,7 +769,7 @@ int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
        }
 
        host->ch = ch;
-       host->addr = addr;
+       host->addr = (void __iomem *)addr;
        host->quirks = quirks;
 
        if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
@@ -757,3 +783,123 @@ error:
                free(host);
        return ret;
 }
+
+#else
+
+struct sh_sdhi_plat {
+       struct mmc_config cfg;
+       struct mmc mmc;
+};
+
+int sh_sdhi_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+                       struct mmc_data *data)
+{
+       struct sh_sdhi_host *host = dev_get_priv(dev);
+
+       return sh_sdhi_send_cmd_common(host, cmd, data);
+}
+
+int sh_sdhi_dm_set_ios(struct udevice *dev)
+{
+       struct sh_sdhi_host *host = dev_get_priv(dev);
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+       return sh_sdhi_set_ios_common(host, mmc);
+}
+
+static const struct dm_mmc_ops sh_sdhi_dm_ops = {
+       .send_cmd       = sh_sdhi_dm_send_cmd,
+       .set_ios        = sh_sdhi_dm_set_ios,
+};
+
+static int sh_sdhi_dm_bind(struct udevice *dev)
+{
+       struct sh_sdhi_plat *plat = dev_get_platdata(dev);
+
+       return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int sh_sdhi_dm_probe(struct udevice *dev)
+{
+       struct sh_sdhi_plat *plat = dev_get_platdata(dev);
+       struct sh_sdhi_host *host = dev_get_priv(dev);
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct clk sh_sdhi_clk;
+       const u32 quirks = dev_get_driver_data(dev);
+       fdt_addr_t base;
+       int ret;
+
+       base = devfdt_get_addr(dev);
+       if (base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       host->addr = devm_ioremap(dev, base, SZ_2K);
+       if (!host->addr)
+               return -ENOMEM;
+
+       ret = clk_get_by_index(dev, 0, &sh_sdhi_clk);
+       if (ret) {
+               debug("failed to get clock, ret=%d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&sh_sdhi_clk);
+       if (ret) {
+               debug("failed to enable clock, ret=%d\n", ret);
+               return ret;
+       }
+
+       host->quirks = quirks;
+
+       if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
+               host->bus_shift = 2;
+       else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
+               host->bus_shift = 1;
+
+       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;
+       }
+
+       sh_sdhi_initialize_common(host);
+
+       plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+       plat->cfg.f_min = CLKDEV_INIT;
+       plat->cfg.f_max = CLKDEV_HS_DATA;
+       plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+       upriv->mmc = &plat->mmc;
+
+       return 0;
+}
+
+static const struct udevice_id sh_sdhi_sd_match[] = {
+       { .compatible = "renesas,sdhi-r8a7795", .data = SH_SDHI_QUIRK_64BIT_BUF },
+       { .compatible = "renesas,sdhi-r8a7796", .data = SH_SDHI_QUIRK_64BIT_BUF },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sh_sdhi_mmc) = {
+       .name                   = "sh-sdhi-mmc",
+       .id                     = UCLASS_MMC,
+       .of_match               = sh_sdhi_sd_match,
+       .bind                   = sh_sdhi_dm_bind,
+       .probe                  = sh_sdhi_dm_probe,
+       .priv_auto_alloc_size   = sizeof(struct sh_sdhi_host),
+       .platdata_auto_alloc_size = sizeof(struct sh_sdhi_plat),
+       .ops                    = &sh_sdhi_dm_ops,
+};
+#endif