Newer
Older
}
size -= (count*4);
}
if (mmc_stat & BRR_MASK)
writel(readl(&mmc_base->stat) | BRR_MASK,
&mmc_base->stat);
if (mmc_stat & TC_MASK) {
writel(readl(&mmc_base->stat) | TC_MASK,
&mmc_base->stat);
break;
}
}
return 0;
}
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base)
{
writel(readl(&mmc_base->sysctl) & ~CEN_ENABLE, &mmc_base->sysctl);
}
static void omap_hsmmc_start_clock(struct hsmmc *mmc_base)
{
writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
}
static void omap_hsmmc_set_clock(struct mmc *mmc)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
struct hsmmc *mmc_base;
unsigned int dsor = 0;
ulong start;
mmc_base = priv->base_addr;
omap_hsmmc_stop_clock(mmc_base);
/* TODO: Is setting DTO required here? */
mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK),
(ICE_STOP | DTO_15THDTO));
if (mmc->clock != 0) {
dsor = DIV_ROUND_UP(MMC_CLOCK_REFERENCE * 1000000, mmc->clock);
if (dsor > CLKD_MAX)
dsor = CLKD_MAX;
} else {
dsor = CLKD_MAX;
}
mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
start = get_timer(0);
while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
if (get_timer(0) - start > MAX_RETRY_MS) {
printf("%s: timedout waiting for ics!\n", __func__);
return;
}
}
priv->clock = mmc->clock;
omap_hsmmc_start_clock(mmc_base);
}
static void omap_hsmmc_set_bus_width(struct mmc *mmc)
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
mmc_base = priv->base_addr;
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
/* configue bus width */
switch (mmc->bus_width) {
case 8:
writel(readl(&mmc_base->con) | DTW_8_BITMODE,
&mmc_base->con);
break;
case 4:
writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
&mmc_base->con);
writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
&mmc_base->hctl);
break;
case 1:
default:
writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
&mmc_base->con);
writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
&mmc_base->hctl);
break;
}
priv->bus_width = mmc->bus_width;
}
#if !CONFIG_IS_ENABLED(DM_MMC)
static int omap_hsmmc_set_ios(struct mmc *mmc)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
#else
static int omap_hsmmc_set_ios(struct udevice *dev)
{
struct omap_hsmmc_data *priv = dev_get_priv(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = upriv->mmc;
#endif
if (priv->bus_width != mmc->bus_width)
omap_hsmmc_set_bus_width(mmc);
if (priv->clock != mmc->clock)
omap_hsmmc_set_clock(mmc);
#if CONFIG_IS_ENABLED(DM_MMC)
if (priv->mode != mmc->selected_mode)
omap_hsmmc_set_timing(mmc);
#endif
}
#ifdef OMAP_HSMMC_USE_GPIO
#if CONFIG_IS_ENABLED(DM_MMC)
static int omap_hsmmc_getcd(struct udevice *dev)
{
struct omap_hsmmc_data *priv = dev_get_priv(dev);
int value;
value = dm_gpio_get_value(&priv->cd_gpio);
/* if no CD return as 1 */
if (value < 0)
return 1;
if (priv->cd_inverted)
return !value;
return value;
}
static int omap_hsmmc_getwp(struct udevice *dev)
{
struct omap_hsmmc_data *priv = dev_get_priv(dev);
int value;
value = dm_gpio_get_value(&priv->wp_gpio);
/* if no WP return as 0 */
if (value < 0)
return 0;
return value;
}
#else
static int omap_hsmmc_getcd(struct mmc *mmc)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
int cd_gpio;
/* if no CD return as 1 */
cd_gpio = priv->cd_gpio;
if (cd_gpio < 0)
return 1;
/* NOTE: assumes card detect signal is active-low */
return !gpio_get_value(cd_gpio);
}
static int omap_hsmmc_getwp(struct mmc *mmc)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
int wp_gpio;
/* if no WP return as 0 */
wp_gpio = priv->wp_gpio;
if (wp_gpio < 0)
return 0;
/* NOTE: assumes write protect signal is active-high */
return gpio_get_value(wp_gpio);
}
#endif
#endif
#if CONFIG_IS_ENABLED(DM_MMC)
static const struct dm_mmc_ops omap_hsmmc_ops = {
.send_cmd = omap_hsmmc_send_cmd,
.set_ios = omap_hsmmc_set_ios,
#ifdef OMAP_HSMMC_USE_GPIO
.get_cd = omap_hsmmc_getcd,
.get_wp = omap_hsmmc_getwp,
#endif
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = omap_hsmmc_execute_tuning,
#endif
static const struct mmc_ops omap_hsmmc_ops = {
.send_cmd = omap_hsmmc_send_cmd,
.set_ios = omap_hsmmc_set_ios,
.init = omap_hsmmc_init_setup,
#ifdef OMAP_HSMMC_USE_GPIO
.getcd = omap_hsmmc_getcd,
.getwp = omap_hsmmc_getwp,
#endif
};
#if !CONFIG_IS_ENABLED(DM_MMC)
int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
int wp_gpio)
struct mmc *mmc;
struct omap_hsmmc_data *priv;
struct mmc_config *cfg;
uint host_caps_val;
priv = malloc(sizeof(*priv));
if (priv == NULL)
host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
switch (dev_index) {
case 0:
priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
break;
case 1:
priv->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
defined(CONFIG_DRA7XX) || defined(CONFIG_AM33XX) || \
defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \
defined(CONFIG_HSMMC2_8BIT)
/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
host_caps_val |= MMC_MODE_8BIT;
#endif
break;
#endif
#ifdef OMAP_HSMMC3_BASE
case 2:
priv->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
/* Enable 8-bit interface for eMMC on DRA7XX */
host_caps_val |= MMC_MODE_8BIT;
#endif
break;
default:
priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
return 1;
}
#ifdef OMAP_HSMMC_USE_GPIO
/* on error gpio values are set to -1, which is what we want */
priv->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
priv->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
Peter Korsgaard
committed
cfg = &priv->cfg;
cfg->name = "OMAP SD/MMC";
cfg->ops = &omap_hsmmc_ops;
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
cfg->host_caps = host_caps_val & ~host_caps_mask;
cfg->f_min = 400000;
cfg->f_max = f_max;
if (cfg->host_caps & MMC_MODE_HS) {
if (cfg->host_caps & MMC_MODE_HS_52MHz)
cfg->f_max = 52000000;
cfg->f_max = 26000000;
cfg->f_max = 20000000;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
#if defined(CONFIG_OMAP34XX)
/*
* Silicon revs 2.1 and older do not support multiblock transfers.
*/
if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
cfg->b_max = 1;
#endif
mmc = mmc_create(cfg, priv);
if (mmc == NULL)
return -1;
return 0;
}
#else
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
{
struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
struct mmc_config *cfg = &plat->cfg;
const void *fdt = gd->fdt_blob;
int ret;
plat->base_addr = map_physmem(devfdt_get_addr(dev),
sizeof(struct hsmmc *),
MAP_NOCACHE);
ret = mmc_of_parse(dev, cfg);
if (ret < 0)
return ret;
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
cfg->f_min = 400000;
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
if (fdtdec_get_bool(fdt, node, "ti,dual-volt"))
plat->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
if (fdtdec_get_bool(fdt, node, "no-1-8-v"))
plat->controller_flags |= OMAP_HSMMC_NO_1_8_V;
plat->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
return 0;
}
#ifdef CONFIG_BLK
static int omap_hsmmc_bind(struct udevice *dev)
{
struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
return mmc_bind(dev, &plat->mmc, &plat->cfg);
}
#endif
static int omap_hsmmc_probe(struct udevice *dev)
{
struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct omap_hsmmc_data *priv = dev_get_priv(dev);
struct mmc_config *cfg = &plat->cfg;
struct mmc *mmc;
cfg->name = "OMAP SD/MMC";
priv->base_addr = plat->base_addr;
#ifdef OMAP_HSMMC_USE_GPIO
priv->cd_inverted = plat->cd_inverted;
#endif
#ifdef CONFIG_BLK
mmc = &plat->mmc;
#else
mmc = mmc_create(cfg, priv);
if (mmc == NULL)
return -1;
#if defined(OMAP_HSMMC_USE_GPIO) && CONFIG_IS_ENABLED(OF_CONTROL)
gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
#endif
mmc->dev = dev;
upriv->mmc = mmc;
return omap_hsmmc_init_setup(mmc);
}
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
static const struct udevice_id omap_hsmmc_ids[] = {
{ .compatible = "ti,omap3-hsmmc" },
{ .compatible = "ti,omap4-hsmmc" },
{ .compatible = "ti,am33xx-hsmmc" },
{ }
};
U_BOOT_DRIVER(omap_hsmmc) = {
.name = "omap_hsmmc",
.id = UCLASS_MMC,
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
.of_match = omap_hsmmc_ids,
.ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct omap_hsmmc_plat),
#endif
#ifdef CONFIG_BLK
.bind = omap_hsmmc_bind,
#endif
.probe = omap_hsmmc_probe,
.priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
.flags = DM_FLAG_PRE_RELOC,
};
#endif