|
|
|
@ -12,24 +12,15 @@ |
|
|
|
|
#include <part.h> |
|
|
|
|
#include <mmc.h> |
|
|
|
|
|
|
|
|
|
#include <asm/io.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; |
|
|
|
|
struct mmc_config cfg; /* mmc configuration */ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) |
|
|
|
|
{ |
|
|
|
|
struct ftsdc010_chip *chip = mmc->priv; |
|
|
|
@ -127,9 +118,8 @@ static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate) |
|
|
|
|
static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) |
|
|
|
|
{ |
|
|
|
|
int ret = -ETIMEDOUT; |
|
|
|
|
uint32_t st, ts; |
|
|
|
|
|
|
|
|
|
for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { |
|
|
|
|
uint32_t st, timeout = 10000000; |
|
|
|
|
while (timeout--) { |
|
|
|
|
st = readl(®s->status); |
|
|
|
|
if (!(st & mask)) |
|
|
|
|
continue; |
|
|
|
@ -147,10 +137,16 @@ 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) |
|
|
|
|
{ |
|
|
|
|
#endif |
|
|
|
|
int ret = -EOPNOTSUPP; |
|
|
|
|
uint32_t len = 0; |
|
|
|
|
struct ftsdc010_chip *chip = mmc->priv; |
|
|
|
@ -251,8 +247,14 @@ static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#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; |
|
|
|
|
|
|
|
|
@ -274,20 +276,43 @@ static int ftsdc010_set_ios(struct mmc *mmc) |
|
|
|
|
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 -ENOMEDIUM; |
|
|
|
|
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 */ |
|
|
|
@ -311,11 +336,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->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
@ -345,19 +429,11 @@ int ftsdc010_mmc_init(int devid) |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { |
|
|
|
|
case FTSDC010_BWR_CAPS_4BIT: |
|
|
|
|
chip->cfg.host_caps |= MMC_MODE_4BIT; |
|
|
|
|
break; |
|
|
|
|
case FTSDC010_BWR_CAPS_8BIT: |
|
|
|
|
chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
@ -373,3 +449,4 @@ int ftsdc010_mmc_init(int devid) |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|