]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/mmc/ftsdc010_mci.c
mmc: fix to assign to correct clock value when clock is enabling
[people/ms/u-boot.git] / drivers / mmc / ftsdc010_mci.c
index 1fcb97c184abd6f6a02d5a413681656ea74e2f88..6ac4f83bd1cf34c38cae3aa8a1d6f19fbc567e8f 100644 (file)
@@ -4,8 +4,7 @@
  * (C) Copyright 2010 Faraday Technology
  * Dante Su <dantesu@faraday-tech.com>
  *
- * This file is released under the terms of GPL v2 and any later version.
- * See the file COPYING in the root directory of the source tree for details.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <part.h>
 #include <mmc.h>
 
-#include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/io.h>
+#include <linux/errno.h>
 #include <asm/byteorder.h>
 #include <faraday/ftsdc010.h>
+#include "ftsdc010_mci.h"
 
 #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
 #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
 
-struct ftsdc010_chip {
-       void __iomem *regs;
-       uint32_t wprot;   /* write protected (locked) */
-       uint32_t rate;    /* actual SD clock in Hz */
-       uint32_t sclk;    /* FTSDC010 source clock in Hz */
-       uint32_t fifo;    /* fifo depth in bytes */
-       uint32_t acmd;
-};
-
 static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
 {
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
-       int ret = TIMEOUT;
+       int ret = -ETIMEDOUT;
        uint32_t ts, st;
        uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
        uint32_t arg   = mmc_cmd->cmdarg;
@@ -124,20 +115,11 @@ static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
        }
 }
 
-static inline int ftsdc010_is_ro(struct mmc *mmc)
-{
-       struct ftsdc010_chip *chip = mmc->priv;
-       const uint8_t *csd = (const uint8_t *)mmc->csd;
-
-       return chip->wprot || (csd[1] & 0x30);
-}
-
 static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
 {
-       int ret = TIMEOUT;
-       uint32_t st, ts;
-
-       for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+       int ret = -ETIMEDOUT;
+       uint32_t st, timeout = 10000000;
+       while (timeout--) {
                st = readl(&regs->status);
                if (!(st & mask))
                        continue;
@@ -146,8 +128,9 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
                break;
        }
 
-       if (ret)
+       if (ret){
                debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+       }
 
        return ret;
 }
@@ -155,11 +138,17 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
 /*
  * u-boot mmc api
  */
-
+#ifdef CONFIG_DM_MMC
+static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd,
+       struct mmc_data *data)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
 static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
        struct mmc_data *data)
 {
-       int ret = UNUSABLE_ERR;
+#endif
+       int ret = -EOPNOTSUPP;
        uint32_t len = 0;
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
@@ -253,14 +242,20 @@ static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
 
        if (!ret) {
                ret = ftsdc010_wait(regs,
-                       FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+                       FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_CRC_OK);
        }
 
        return ret;
 }
 
-static void ftsdc010_set_ios(struct mmc *mmc)
+#ifdef CONFIG_DM_MMC
+static int ftsdc010_set_ios(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int ftsdc010_set_ios(struct mmc *mmc)
 {
+#endif
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
 
@@ -278,22 +273,47 @@ static void ftsdc010_set_ios(struct mmc *mmc)
                setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
                break;
        }
+
+       return 0;
 }
 
-static int ftsdc010_init(struct mmc *mmc)
+#ifdef CONFIG_DM_MMC
+static int ftsdc010_get_cd(struct udevice *dev)
 {
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int ftsdc010_get_cd(struct mmc *mmc)
+{
+#endif
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
-       uint32_t ts;
-
-       if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
-               return NO_CARD_ERR;
+       return !(readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT);
+}
 
+#ifdef CONFIG_DM_MMC
+static int ftsdc010_get_wp(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int ftsdc010_get_wp(struct mmc *mmc)
+{
+#endif
+       struct ftsdc010_chip *chip = mmc->priv;
+       struct ftsdc010_mmc __iomem *regs = chip->regs;
        if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
                printf("ftsdc010: write protected\n");
                chip->wprot = 1;
        }
 
+       return 0;
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+       struct ftsdc010_chip *chip = mmc->priv;
+       struct ftsdc010_mmc __iomem *regs = chip->regs;
+       uint32_t ts;
+
        chip->fifo = (readl(&regs->feature) & 0xff) << 2;
 
        /* 1. chip reset */
@@ -305,7 +325,7 @@ static int ftsdc010_init(struct mmc *mmc)
        }
        if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
                printf("ftsdc010: reset failed\n");
-               return UNUSABLE_ERR;
+               return -EOPNOTSUPP;
        }
 
        /* 2. enter low speed mode (400k card detection) */
@@ -317,6 +337,70 @@ static int ftsdc010_init(struct mmc *mmc)
        return 0;
 }
 
+#ifdef CONFIG_DM_MMC
+int ftsdc010_probe(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+       return ftsdc010_init(mmc);
+}
+
+const struct dm_mmc_ops dm_ftsdc010_ops = {
+       .send_cmd       = ftsdc010_request,
+       .set_ios        = ftsdc010_set_ios,
+       .get_cd         = ftsdc010_get_cd,
+       .get_wp         = ftsdc010_get_wp,
+};
+
+#else
+static const struct mmc_ops ftsdc010_ops = {
+       .send_cmd       = ftsdc010_request,
+       .set_ios        = ftsdc010_set_ios,
+       .getcd          = ftsdc010_get_cd,
+       .getwp          = ftsdc010_get_wp,
+       .init           = ftsdc010_init,
+};
+#endif
+
+void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
+                    uint caps, u32 max_clk, u32 min_clk)
+{
+       cfg->name = name;
+       cfg->f_min = min_clk;
+       cfg->f_max = max_clk;
+       cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+       cfg->host_caps = caps;
+       if (buswidth == 8) {
+               cfg->host_caps |= MMC_MODE_8BIT;
+               cfg->host_caps &= ~MMC_MODE_4BIT;
+       } else {
+               cfg->host_caps |= MMC_MODE_4BIT;
+               cfg->host_caps &= ~MMC_MODE_8BIT;
+       }
+       cfg->part_type = PART_TYPE_DOS;
+       cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+}
+
+void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg)
+{
+       switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+       case FTSDC010_BWR_CAPS_4BIT:
+               cfg->host_caps |= MMC_MODE_4BIT;
+               break;
+       case FTSDC010_BWR_CAPS_8BIT:
+               cfg->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+               break;
+       default:
+               break;
+       }
+}
+
+#ifdef CONFIG_BLK
+int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg)
+{
+       return mmc_bind(dev, mmc, cfg);
+}
+#else
+
 int ftsdc010_mmc_init(int devid)
 {
        struct mmc *mmc;
@@ -332,50 +416,37 @@ int ftsdc010_mmc_init(int devid)
        regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
 #endif
 
-       mmc = malloc(sizeof(struct mmc));
-       if (!mmc)
-               return -ENOMEM;
-       memset(mmc, 0, sizeof(struct mmc));
-
        chip = malloc(sizeof(struct ftsdc010_chip));
-       if (!chip) {
-               free(mmc);
+       if (!chip)
                return -ENOMEM;
-       }
        memset(chip, 0, sizeof(struct ftsdc010_chip));
 
        chip->regs = regs;
-       mmc->priv  = chip;
-
-       sprintf(mmc->name, "ftsdc010");
-       mmc->send_cmd  = ftsdc010_request;
-       mmc->set_ios   = ftsdc010_set_ios;
-       mmc->init      = ftsdc010_init;
-
-       mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
-       switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
-       case FTSDC010_BWR_CAPS_4BIT:
-               mmc->host_caps |= MMC_MODE_4BIT;
-               break;
-       case FTSDC010_BWR_CAPS_8BIT:
-               mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
-               break;
-       default:
-               break;
-       }
-
 #ifdef CONFIG_SYS_CLK_FREQ
        chip->sclk = CONFIG_SYS_CLK_FREQ;
 #else
        chip->sclk = clk_get_rate("SDC");
 #endif
 
-       mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->f_max     = chip->sclk / 2;
-       mmc->f_min     = chip->sclk / 0x100;
-       mmc->block_dev.part_type = PART_TYPE_DOS;
-
-       mmc_register(mmc);
+       chip->cfg.name = "ftsdc010";
+#ifndef CONFIG_DM_MMC
+       chip->cfg.ops = &ftsdc010_ops;
+#endif
+       chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+       set_bus_width(regs , &chip->cfg);
+       chip->cfg.voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+       chip->cfg.f_max     = chip->sclk / 2;
+       chip->cfg.f_min     = chip->sclk / 0x100;
+
+       chip->cfg.part_type = PART_TYPE_DOS;
+       chip->cfg.b_max     = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+       mmc = mmc_create(&chip->cfg, chip);
+       if (mmc == NULL) {
+               free(chip);
+               return -ENOMEM;
+       }
 
        return 0;
 }
+#endif