#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;
}
}
-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(®s->status);
if (!(st & mask))
continue;
break;
}
- if (ret)
+ if (ret){
debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+ }
return ret;
}
/*
* 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;
len = data->blocksize * data->blocks;
/* 1. data disable + fifo reset */
- writel(FTSDC010_DCR_FIFO_RST, ®s->dcr);
+ dcr = 0;
+#ifdef CONFIG_FTSDC010_SDIO
+ dcr |= FTSDC010_DCR_FIFO_RST;
+#endif
+ writel(dcr, ®s->dcr);
/* 2. clear status register */
writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
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;
setbits_le32(®s->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(®s->status) & FTSDC010_STATUS_CARD_DETECT)
- return NO_CARD_ERR;
+ return !(readl(®s->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(®s->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(®s->feature) & 0xff) << 2;
/* 1. chip reset */
}
if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) {
printf("ftsdc010: reset failed\n");
- return UNUSABLE_ERR;
+ return -EOPNOTSUPP;
}
/* 2. enter low speed mode (400k card detection) */
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(®s->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;
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(®s->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