#include <config.h>
#include <common.h>
+#include <malloc.h>
#include <mmc.h>
#include <part.h>
#include <i2c.h>
#include <twl4030.h>
#include <twl6030.h>
-#include <twl6035.h>
+#include <palmas.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/mmc_host_def.h>
#include <asm/arch/sys_proto.h>
+/* simplify defines to OMAP_HSMMC_USE_GPIO */
+#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
+#define OMAP_HSMMC_USE_GPIO
+#else
+#undef OMAP_HSMMC_USE_GPIO
+#endif
+
/* common definitions for all OMAPs */
#define SYSCTL_SRC (1 << 25)
#define SYSCTL_SRD (1 << 26)
struct omap_hsmmc_data {
struct hsmmc *base_addr;
+ struct mmc_config cfg;
+#ifdef OMAP_HSMMC_USE_GPIO
int cd_gpio;
+ int wp_gpio;
+#endif
};
/* If we fail after 1 second wait, something is really bad */
static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
unsigned int siz);
-static struct mmc hsmmc_dev[3];
-static struct omap_hsmmc_data hsmmc_dev_data[3];
-#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
- (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
+#ifdef OMAP_HSMMC_USE_GPIO
static int omap_mmc_setup_gpio_in(int gpio, const char *label)
{
+ int ret;
+
+#ifndef CONFIG_DM_GPIO
if (!gpio_is_valid(gpio))
return -1;
+#endif
+ ret = gpio_request(gpio, label);
+ if (ret)
+ return ret;
- if (gpio_request(gpio, label) < 0)
- return -1;
-
- if (gpio_direction_input(gpio) < 0)
- return -1;
+ ret = gpio_direction_input(gpio);
+ if (ret)
+ return ret;
return gpio;
}
-
-static int omap_mmc_getcd(struct mmc *mmc)
-{
- int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
- return gpio_get_value(cd_gpio);
-}
-#else
-static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
-{
- return -1;
-}
-
-#define omap_mmc_getcd NULL
#endif
#if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
static void omap4_vmmc_pbias_config(struct mmc *mmc)
{
u32 value = 0;
- struct omap_sys_ctrl_regs *const ctrl =
- (struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
-
- value = readl(&ctrl->control_pbiaslite);
+ value = readl((*ctrl)->control_pbiaslite);
value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
- writel(value, &ctrl->control_pbiaslite);
+ writel(value, (*ctrl)->control_pbiaslite);
/* set VMMC to 3V */
twl6030_power_mmc_init();
- value = readl(&ctrl->control_pbiaslite);
+ value = readl((*ctrl)->control_pbiaslite);
value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
- writel(value, &ctrl->control_pbiaslite);
+ writel(value, (*ctrl)->control_pbiaslite);
}
#endif
-#if defined(CONFIG_OMAP54XX) && defined(CONFIG_TWL6035_POWER)
+#if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
static void omap5_pbias_config(struct mmc *mmc)
{
u32 value = 0;
- struct omap_sys_ctrl_regs *const ctrl =
- (struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
-
- value = readl(&ctrl->control_pbias);
- value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
- value |= SDCARD_BIAS_HIZ_MODE;
- writel(value, &ctrl->control_pbias);
-
- twl6035_mmc1_poweron_ldo();
-
- value = readl(&ctrl->control_pbias);
- value &= ~SDCARD_BIAS_HIZ_MODE;
- value |= SDCARD_PBIASLITE_VMODE | SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ;
- writel(value, &ctrl->control_pbias);
-
- value = readl(&ctrl->control_pbias);
- if (value & (1 << 23)) {
- value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
- value |= SDCARD_BIAS_HIZ_MODE;
- writel(value, &ctrl->control_pbias);
- }
+
+ value = readl((*ctrl)->control_pbias);
+ value &= ~SDCARD_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+ udelay(10); /* wait 10 us */
+ value &= ~SDCARD_BIAS_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+
+ palmas_mmc1_poweron_ldo();
+
+ value = readl((*ctrl)->control_pbias);
+ value |= SDCARD_BIAS_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+ udelay(150); /* wait 150 us */
+ value |= SDCARD_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+ udelay(150); /* wait 150 us */
}
#endif
-unsigned char mmc_board_init(struct mmc *mmc)
+static unsigned char mmc_board_init(struct mmc *mmc)
{
#if defined(CONFIG_OMAP34XX)
t2_t *t2_base = (t2_t *)T2_BASE;
pbias_lite = readl(&t2_base->pbias_lite);
pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
- writel(pbias_lite, &t2_base->pbias_lite);
-#endif
-#if defined(CONFIG_TWL4030_POWER)
- twl4030_power_mmc_init();
- mdelay(100); /* ramp-up delay from Linux code */
+#ifdef CONFIG_TARGET_OMAP3_CAIRO
+ /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
+ pbias_lite &= ~PBIASLITEVMODE0;
#endif
-#if defined(CONFIG_OMAP34XX)
+ writel(pbias_lite, &t2_base->pbias_lite);
+
writel(pbias_lite | PBIASLITEPWRDNZ1 |
PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
&t2_base->pbias_lite);
&t2_base->devconf1);
/* Change from default of 52MHz to 26MHz if necessary */
- if (!(mmc->host_caps & MMC_MODE_HS_52MHz))
+ if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz))
writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
&t2_base->ctl_prog_io1);
if (mmc->block_dev.dev == 0)
omap4_vmmc_pbias_config(mmc);
#endif
-#if defined(CONFIG_OMAP54XX) && defined(CONFIG_TWL6035_POWER)
+#if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
if (mmc->block_dev.dev == 0)
omap5_pbias_config(mmc);
#endif
}
-static int mmc_init_setup(struct mmc *mmc)
+static int omap_hsmmc_init_setup(struct mmc *mmc)
{
struct hsmmc *mmc_base;
unsigned int reg_val;
mmc_reg_out(&mmc_base->sysctl, bit, bit);
+ /*
+ * CMD(DAT) lines reset procedures are slightly different
+ * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
+ * According to OMAP3 TRM:
+ * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
+ * returns to 0x0.
+ * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
+ * procedure steps must be as follows:
+ * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
+ * MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
+ * 2. Poll the SRC(SRD) bit until it is set to 0x1.
+ * 3. Wait until the SRC (SRD) bit returns to 0x0
+ * (reset procedure is completed).
+ */
+#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
+ defined(CONFIG_AM33XX)
+ if (!(readl(&mmc_base->sysctl) & bit)) {
+ start = get_timer(0);
+ while (!(readl(&mmc_base->sysctl) & bit)) {
+ if (get_timer(0) - start > MAX_RETRY_MS)
+ return;
+ }
+ }
+#endif
start = get_timer(0);
while ((readl(&mmc_base->sysctl) & bit) != 0) {
if (get_timer(0) - start > MAX_RETRY_MS) {
}
}
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct hsmmc *mmc_base;
}
writel(cmd->cmdarg, &mmc_base->arg);
+ udelay(20); /* To fix "No status update" error on eMMC */
writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
start = get_timer(0);
unsigned int count;
/*
- * Start Polled Read
+ * Start Polled Write
*/
count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
count /= 4;
return 0;
}
-static void mmc_set_ios(struct mmc *mmc)
+static void omap_hsmmc_set_ios(struct mmc *mmc)
{
struct hsmmc *mmc_base;
unsigned int dsor = 0;
writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
}
-int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio)
+#ifdef OMAP_HSMMC_USE_GPIO
+static int omap_hsmmc_getcd(struct mmc *mmc)
+{
+ struct omap_hsmmc_data *priv_data = mmc->priv;
+ int cd_gpio;
+
+ /* if no CD return as 1 */
+ cd_gpio = priv_data->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_data = mmc->priv;
+ int wp_gpio;
+
+ /* if no WP return as 0 */
+ wp_gpio = priv_data->wp_gpio;
+ if (wp_gpio < 0)
+ return 0;
+
+ /* NOTE: assumes write protect signal is active-high */
+ return gpio_get_value(wp_gpio);
+}
+#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
+};
+
+int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
+ int wp_gpio)
{
- struct mmc *mmc = &hsmmc_dev[dev_index];
- struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];
+ struct mmc *mmc;
+ struct omap_hsmmc_data *priv_data;
+ struct mmc_config *cfg;
+ uint host_caps_val;
+
+ priv_data = malloc(sizeof(*priv_data));
+ if (priv_data == NULL)
+ return -1;
- sprintf(mmc->name, "OMAP SD/MMC");
- mmc->send_cmd = mmc_send_cmd;
- mmc->set_ios = mmc_set_ios;
- mmc->init = mmc_init_setup;
- mmc->getcd = omap_mmc_getcd;
- mmc->getwp = NULL;
- mmc->priv = priv_data;
+ host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
+ MMC_MODE_HC;
switch (dev_index) {
case 0:
#ifdef OMAP_HSMMC2_BASE
case 1:
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
+#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
+ defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && \
+ 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_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
+#if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT)
+ /* Enable 8-bit interface for eMMC on DRA7XX */
+ host_caps_val |= MMC_MODE_8BIT;
+#endif
break;
#endif
default:
priv_data->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_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
- mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
- mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
- MMC_MODE_HC) & ~host_caps_mask;
+ priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
+#endif
+
+ cfg = &priv_data->cfg;
+
+ cfg->name = "OMAP SD/MMC";
+ cfg->ops = &omap_hsmmc_ops;
- mmc->f_min = 400000;
+ 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;
if (f_max != 0)
- mmc->f_max = f_max;
+ cfg->f_max = f_max;
else {
- if (mmc->host_caps & MMC_MODE_HS) {
- if (mmc->host_caps & MMC_MODE_HS_52MHz)
- mmc->f_max = 52000000;
+ if (cfg->host_caps & MMC_MODE_HS) {
+ if (cfg->host_caps & MMC_MODE_HS_52MHz)
+ cfg->f_max = 52000000;
else
- mmc->f_max = 26000000;
+ cfg->f_max = 26000000;
} else
- mmc->f_max = 20000000;
+ cfg->f_max = 20000000;
}
- mmc->b_max = 0;
+ 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))
- mmc->b_max = 1;
+ cfg->b_max = 1;
#endif
-
- mmc_register(mmc);
+ mmc = mmc_create(cfg, priv_data);
+ if (mmc == NULL)
+ return -1;
return 0;
}