diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/bfin_sdh.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/davinci_mmc.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/fsl_esdhc.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/ftsdc010_esdhc.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/gen_atmel_mci.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/mmc_spi.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/mxcmmc.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/mxsmmc.c | 21 | ||||
| -rw-r--r-- | drivers/mmc/omap_hsmmc.c | 103 | ||||
| -rw-r--r-- | drivers/mmc/sdhci.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/sh_mmcif.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/tegra_mmc.c | 225 | 
14 files changed, 275 insertions, 101 deletions
| diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index af1380a45..ab2e81e5d 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -377,6 +377,7 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host)  	dev->set_ios = host_set_ios;  	dev->init = mmc_host_reset;  	dev->getcd = NULL; +	dev->getwp = NULL;  	dev->host_caps = host->caps;  	dev->voltages = host->voltages;  	dev->f_min = host->clock_min; diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c index 0f98b961f..26311741f 100644 --- a/drivers/mmc/bfin_sdh.c +++ b/drivers/mmc/bfin_sdh.c @@ -287,6 +287,7 @@ int bfin_mmc_init(bd_t *bis)  	mmc->set_ios = bfin_sdh_set_ios;  	mmc->init = bfin_sdh_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->host_caps = MMC_MODE_4BIT;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c index ee8f2614d..e2379e326 100644 --- a/drivers/mmc/davinci_mmc.c +++ b/drivers/mmc/davinci_mmc.c @@ -388,6 +388,7 @@ int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)  	mmc->set_ios = dmmc_set_ios;  	mmc->init = dmmc_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->f_min = 200000;  	mmc->f_max = 25000000; diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index b90f3e776..54b536316 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -552,6 +552,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)  	mmc->set_ios = esdhc_set_ios;  	mmc->init = esdhc_init;  	mmc->getcd = esdhc_getcd; +	mmc->getwp = NULL;  	voltage_caps = 0;  	caps = regs->hostcapblt; diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c index f1702fe33..42f0e0ce5 100644 --- a/drivers/mmc/ftsdc010_esdhc.c +++ b/drivers/mmc/ftsdc010_esdhc.c @@ -666,6 +666,7 @@ int ftsdc010_mmc_init(int dev_index)  	mmc->set_ios = ftsdc010_set_ios;  	mmc->init = ftsdc010_core_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index 67b2dbe8d..70a9f91c8 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -349,6 +349,7 @@ int atmel_mci_init(void *regs)  	mmc->set_ios = mci_set_ios;  	mmc->init = mci_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	/* need to be able to pass these in on a board by board basis */  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 72e8ce6da..7b5fdd9f6 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -40,6 +40,23 @@  static struct list_head mmc_devices;  static int cur_dev_num = -1; +int __weak board_mmc_getwp(struct mmc *mmc) +{ +	return -1; +} + +int mmc_getwp(struct mmc *mmc) +{ +	int wp; + +	wp = board_mmc_getwp(mmc); + +	if ((wp < 0) && mmc->getwp) +		wp = mmc->getwp(mmc); + +	return wp; +} +  int __board_mmc_getcd(struct mmc *mmc) {  	return -1;  } diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 11ba532b0..fe6a5a166 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -273,6 +273,7 @@ struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)  	mmc->set_ios = mmc_spi_set_ios;  	mmc->init = mmc_spi_init_p;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->host_caps = MMC_MODE_SPI;  	mmc->voltages = MMC_SPI_VOLTAGE; diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c index d58c18bc2..4f99617b9 100644 --- a/drivers/mmc/mxcmmc.c +++ b/drivers/mmc/mxcmmc.c @@ -499,6 +499,7 @@ static int mxcmci_initialize(bd_t *bis)  	mmc->set_ios = mxcmci_set_ios;  	mmc->init = mxcmci_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->host_caps = MMC_MODE_4BIT;  	host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE; diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index a72f66cc7..a89660f13 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -53,12 +53,6 @@ struct mxsmmc_priv {  	struct mxs_dma_desc	*desc;  }; -#if defined(CONFIG_MX23) -static const unsigned int mxsmmc_id_offset = 1; -#elif defined(CONFIG_MX28) -static const unsigned int mxsmmc_id_offset = 0; -#endif -  #define	MXSMMC_MAX_TIMEOUT	10000  #define MXSMMC_SMALL_TRANSFER	512 @@ -137,7 +131,7 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)  	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |  				(data_count << MXS_DMA_DESC_BYTES_OFFSET); -	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id + mxsmmc_id_offset; +	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;  	mxs_dma_desc_append(dmach, priv->desc);  	if (mxs_dma_go(dmach)) {  		bounce_buffer_stop(&bbstate); @@ -390,15 +384,9 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))  	struct mmc *mmc = NULL;  	struct mxsmmc_priv *priv = NULL;  	int ret; -#if defined(CONFIG_MX23) -	const unsigned int mxsmmc_max_id = 2; -	const unsigned int mxsmmc_clk_id = 0; -#elif defined(CONFIG_MX28) -	const unsigned int mxsmmc_max_id = 4; -	const unsigned int mxsmmc_clk_id = id; -#endif +	const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id); -	if (id >= mxsmmc_max_id) +	if (!mxs_ssp_bus_id_valid(id))  		return -ENODEV;  	mmc = malloc(sizeof(struct mmc)); @@ -418,7 +406,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))  		return -ENOMEM;  	} -	ret = mxs_dma_init_channel(id + mxsmmc_id_offset); +	ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);  	if (ret)  		return ret; @@ -432,6 +420,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))  	mmc->set_ios = mxsmmc_set_ios;  	mmc->init = mxsmmc_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	mmc->priv = priv;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index afd9b30b5..67cfcc24d 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -30,6 +30,7 @@  #include <twl4030.h>  #include <twl6030.h>  #include <twl6035.h> +#include <asm/gpio.h>  #include <asm/io.h>  #include <asm/arch/mmc_host_def.h>  #include <asm/arch/sys_proto.h> @@ -38,30 +39,71 @@  #define SYSCTL_SRC	(1 << 25)  #define SYSCTL_SRD	(1 << 26) +struct omap_hsmmc_data { +	struct hsmmc *base_addr; +	int cd_gpio; +	int wp_gpio; +}; +  /* If we fail after 1 second wait, something is really bad */  #define MAX_RETRY_MS	1000  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[2]; +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)) +static int omap_mmc_setup_gpio_in(int gpio, const char *label) +{ +	if (!gpio_is_valid(gpio)) +		return -1; + +	if (gpio_request(gpio, label) < 0) +		return -1; + +	if (gpio_direction_input(gpio) < 0) +		return -1; + +	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); +} + +static int omap_mmc_getwp(struct mmc *mmc) +{ +	int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio; +	return gpio_get_value(wp_gpio); +} +#else +static inline int omap_mmc_setup_gpio_in(int gpio, const char *label) +{ +	return -1; +} + +#define omap_mmc_getcd NULL +#define omap_mmc_getwp 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 @@ -69,26 +111,24 @@ static void omap4_vmmc_pbias_config(struct mmc *mmc)  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 = readl((*ctrl)->control_pbias);  	value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);  	value |= SDCARD_BIAS_HIZ_MODE; -	writel(value, &ctrl->control_pbias); +	writel(value, (*ctrl)->control_pbias);  	twl6035_mmc1_poweron_ldo(); -	value = readl(&ctrl->control_pbias); +	value = readl((*ctrl)->control_pbias);  	value &= ~SDCARD_BIAS_HIZ_MODE;  	value |= SDCARD_PBIASLITE_VMODE | SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ; -	writel(value, &ctrl->control_pbias); +	writel(value, (*ctrl)->control_pbias); -	value = readl(&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); +		writel(value, (*ctrl)->control_pbias);  	}  }  #endif @@ -177,11 +217,12 @@ void mmc_init_stream(struct hsmmc *mmc_base)  static int mmc_init_setup(struct mmc *mmc)  { -	struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv; +	struct hsmmc *mmc_base;  	unsigned int reg_val;  	unsigned int dsor;  	ulong start; +	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;  	mmc_board_init(mmc);  	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET, @@ -262,10 +303,11 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)  static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  			struct mmc_data *data)  { -	struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv; +	struct hsmmc *mmc_base;  	unsigned int flags, mmc_stat;  	ulong start; +	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;  	start = get_timer(0);  	while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {  		if (get_timer(0) - start > MAX_RETRY_MS) { @@ -489,10 +531,11 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,  static void mmc_set_ios(struct mmc *mmc)  { -	struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv; +	struct hsmmc *mmc_base;  	unsigned int dsor = 0;  	ulong start; +	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;  	/* configue bus width */  	switch (mmc->bus_width) {  	case 8: @@ -540,36 +583,40 @@ static void mmc_set_ios(struct mmc *mmc)  	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 omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, +		int wp_gpio)  { -	struct mmc *mmc; - -	mmc = &hsmmc_dev[dev_index]; +	struct mmc *mmc = &hsmmc_dev[dev_index]; +	struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];  	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 = NULL; +	mmc->getcd = omap_mmc_getcd; +	mmc->getwp = omap_mmc_getwp; +	mmc->priv = priv_data;  	switch (dev_index) {  	case 0: -		mmc->priv = (struct hsmmc *)OMAP_HSMMC1_BASE; +		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;  		break;  #ifdef OMAP_HSMMC2_BASE  	case 1: -		mmc->priv = (struct hsmmc *)OMAP_HSMMC2_BASE; +		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;  		break;  #endif  #ifdef OMAP_HSMMC3_BASE  	case 2: -		mmc->priv = (struct hsmmc *)OMAP_HSMMC3_BASE; +		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;  		break;  #endif  	default: -		mmc->priv = (struct hsmmc *)OMAP_HSMMC1_BASE; +		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;  		return 1;  	} +	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd"); +	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");  	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; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index b9cbe34f1..daca0ea4f 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -438,6 +438,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)  	mmc->set_ios = sdhci_set_ios;  	mmc->init = sdhci_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	caps = sdhci_readl(host, SDHCI_CAPABILITIES);  #ifdef CONFIG_MMC_SDMA diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c index 4588568a6..011d4f3e6 100644 --- a/drivers/mmc/sh_mmcif.c +++ b/drivers/mmc/sh_mmcif.c @@ -599,6 +599,7 @@ int mmcif_mmc_init(void)  	mmc->set_ios = sh_mmcif_set_ios;  	mmc->init = sh_mmcif_init;  	mmc->getcd = NULL; +	mmc->getwp = NULL;  	host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;  	host->clk = CONFIG_SH_MMCIF_CLK;  	mmc->priv = host; diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index d749ab095..e86bc680f 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -2,7 +2,7 @@   * (C) Copyright 2009 SAMSUNG Electronics   * Minkyu Kang <mk7.kang@samsung.com>   * Jaehoon Chung <jh80.chung@samsung.com> - * Portions Copyright 2011-2012 NVIDIA Corporation + * Portions Copyright 2011-2013 NVIDIA Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -28,43 +28,45 @@  #include <asm/arch-tegra/tegra_mmc.h>  #include <mmc.h> -/* support 4 mmc hosts */ -struct mmc mmc_dev[4]; -struct mmc_host mmc_host[4]; +DECLARE_GLOBAL_DATA_PTR; +struct mmc mmc_dev[MAX_HOSTS]; +struct mmc_host mmc_host[MAX_HOSTS]; -/** - * Get the host address and peripheral ID for a device. Devices are numbered - * from 0 to 3. - * - * @param host		Structure to fill in (base, reg, mmc_id) - * @param dev_index	Device index (0-3) - */ -static void tegra_get_setup(struct mmc_host *host, int dev_index) +#ifndef CONFIG_OF_CONTROL +#error "Please enable device tree support to use this driver" +#endif + +static void mmc_set_power(struct mmc_host *host, unsigned short power)  { -	debug("tegra_get_setup: dev_index = %d\n", dev_index); +	u8 pwr = 0; +	debug("%s: power = %x\n", __func__, power); -	switch (dev_index) { -	case 1: -		host->base = TEGRA_SDMMC3_BASE; -		host->mmc_id = PERIPH_ID_SDMMC3; -		break; -	case 2: -		host->base = TEGRA_SDMMC2_BASE; -		host->mmc_id = PERIPH_ID_SDMMC2; -		break; -	case 3: -		host->base = TEGRA_SDMMC1_BASE; -		host->mmc_id = PERIPH_ID_SDMMC1; -		break; -	case 0: -	default: -		host->base = TEGRA_SDMMC4_BASE; -		host->mmc_id = PERIPH_ID_SDMMC4; -		break; +	if (power != (unsigned short)-1) { +		switch (1 << power) { +		case MMC_VDD_165_195: +			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; +			break; +		case MMC_VDD_29_30: +		case MMC_VDD_30_31: +			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0; +			break; +		case MMC_VDD_32_33: +		case MMC_VDD_33_34: +			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; +			break; +		}  	} +	debug("%s: pwr = %X\n", __func__, pwr); + +	/* Set the bus voltage first (if any) */ +	writeb(pwr, &host->reg->pwrcon); +	if (pwr == 0) +		return; -	host->reg = (struct tegra_mmc *)host->base; +	/* Now enable bus power */ +	pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; +	writeb(pwr, &host->reg->pwrcon);  }  static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data, @@ -363,8 +365,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)  	debug(" mmc_change_clock called\n");  	/* -	 * Change Tegra SDMMCx clock divisor here. Source is 216MHz, -	 * PLLP_OUT0 +	 * Change Tegra SDMMCx clock divisor here. Source is PLLP_OUT0  	 */  	if (clock == 0)  		goto out; @@ -439,7 +440,7 @@ static void mmc_set_ios(struct mmc *mmc)  	debug("mmc_set_ios: hostctl = %08X\n", ctrl);  } -static void mmc_reset(struct mmc_host *host) +static void mmc_reset(struct mmc_host *host, struct mmc *mmc)  {  	unsigned int timeout;  	debug(" mmc_reset called\n"); @@ -465,6 +466,14 @@ static void mmc_reset(struct mmc_host *host)  		timeout--;  		udelay(1000);  	} + +	/* Set SD bus voltage & enable bus power */ +	mmc_set_power(host, fls(mmc->voltages) - 1); +	debug("%s: power control = %02X, host control = %02X\n", __func__, +		readb(&host->reg->pwrcon), readb(&host->reg->hostctl)); + +	/* Make sure SDIO pads are set up */ +	pad_init_mmc(host);  }  static int mmc_core_init(struct mmc *mmc) @@ -473,7 +482,7 @@ static int mmc_core_init(struct mmc *mmc)  	unsigned int mask;  	debug(" mmc_core_init called\n"); -	mmc_reset(host); +	mmc_reset(host, mmc);  	host->version = readw(&host->reg->hcver);  	debug("host version = %x\n", host->version); @@ -518,41 +527,43 @@ int tegra_mmc_getcd(struct mmc *mmc)  	debug("tegra_mmc_getcd called\n"); -	if (host->cd_gpio >= 0) -		return !gpio_get_value(host->cd_gpio); +	if (fdt_gpio_isvalid(&host->cd_gpio)) +		return fdtdec_get_gpio(&host->cd_gpio);  	return 1;  } -int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) +static int do_mmc_init(int dev_index)  {  	struct mmc_host *host;  	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */  	struct mmc *mmc; -	debug(" tegra_mmc_init: index %d, bus width %d " -		"pwr_gpio %d cd_gpio %d\n", -		dev_index, bus_width, pwr_gpio, cd_gpio); - +	/* DT should have been read & host config filled in */  	host = &mmc_host[dev_index]; +	if (!host->enabled) +		return -1; -	host->clock = 0; -	host->pwr_gpio = pwr_gpio; -	host->cd_gpio = cd_gpio; -	tegra_get_setup(host, dev_index); +	debug(" do_mmc_init: index %d, bus width %d " +		"pwr_gpio %d cd_gpio %d\n", +		dev_index, host->width, +		host->pwr_gpio.gpio, host->cd_gpio.gpio); +	host->clock = 0;  	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); -	if (host->pwr_gpio >= 0) { +	if (fdt_gpio_isvalid(&host->pwr_gpio)) {  		sprintf(gpusage, "SD/MMC%d PWR", dev_index); -		gpio_request(host->pwr_gpio, gpusage); -		gpio_direction_output(host->pwr_gpio, 1); +		gpio_request(host->pwr_gpio.gpio, gpusage); +		gpio_direction_output(host->pwr_gpio.gpio, 1); +		debug(" Power GPIO name = %s\n", host->pwr_gpio.name);  	} -	if (host->cd_gpio >= 0) { +	if (fdt_gpio_isvalid(&host->cd_gpio)) {  		sprintf(gpusage, "SD/MMC%d CD", dev_index); -		gpio_request(host->cd_gpio, gpusage); -		gpio_direction_input(host->cd_gpio); +		gpio_request(host->cd_gpio.gpio, gpusage); +		gpio_direction_input(host->cd_gpio.gpio); +		debug(" CD GPIO name = %s\n", host->cd_gpio.name);  	}  	mmc = &mmc_dev[dev_index]; @@ -563,12 +574,13 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	mmc->set_ios = mmc_set_ios;  	mmc->init = mmc_core_init;  	mmc->getcd = tegra_mmc_getcd; +	mmc->getwp = NULL;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;  	mmc->host_caps = 0; -	if (bus_width == 8) +	if (host->width == 8)  		mmc->host_caps |= MMC_MODE_8BIT; -	if (bus_width >= 4) +	if (host->width >= 4)  		mmc->host_caps |= MMC_MODE_4BIT;  	mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; @@ -577,8 +589,6 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	 *  low-speed SDIO card frequency (actually 400KHz)  	 * max freq is highest HS eMMC clock as per the SD/MMC spec  	 *  (actually 52MHz) -	 * Both of these are the closest equivalents w/216MHz source -	 *  clock and Tegra SDMMC divisors.  	 */  	mmc->f_min = 375000;  	mmc->f_max = 48000000; @@ -587,3 +597,104 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	return 0;  } + +/** + * Get the host address and peripheral ID for a node. + * + * @param blob		fdt blob + * @param node		Device index (0-3) + * @param host		Structure to fill in (reg, width, mmc_id) + */ +static int mmc_get_config(const void *blob, int node, struct mmc_host *host) +{ +	debug("%s: node = %d\n", __func__, node); + +	host->enabled = fdtdec_get_is_enabled(blob, node); + +	host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg"); +	if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) { +		debug("%s: no sdmmc base reg info found\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} + +	host->mmc_id = clock_decode_periph_id(blob, node); +	if (host->mmc_id == PERIPH_ID_NONE) { +		debug("%s: could not decode periph id\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} + +	/* +	 * NOTE: mmc->bus_width is determined by mmc.c dynamically. +	 * TBD: Override it with this value? +	 */ +	host->width = fdtdec_get_int(blob, node, "bus-width", 0); +	if (!host->width) +		debug("%s: no sdmmc width found\n", __func__); + +	/* These GPIOs are optional */ +	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio); +	fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio); +	fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio); + +	debug("%s: found controller at %p, width = %d, periph_id = %d\n", +		__func__, host->reg, host->width, host->mmc_id); +	return 0; +} + +/* + * Process a list of nodes, adding them to our list of SDMMC ports. + * + * @param blob          fdt blob + * @param node_list     list of nodes to process (any <=0 are ignored) + * @param count         number of nodes to process + * @return 0 if ok, -1 on error + */ +static int process_nodes(const void *blob, int node_list[], int count) +{ +	struct mmc_host *host; +	int i, node; + +	debug("%s: count = %d\n", __func__, count); + +	/* build mmc_host[] for each controller */ +	for (i = 0; i < count; i++) { +		node = node_list[i]; +		if (node <= 0) +			continue; + +		host = &mmc_host[i]; +		host->id = i; + +		if (mmc_get_config(blob, node, host)) { +			printf("%s: failed to decode dev %d\n",	__func__, i); +			return -1; +		} +		do_mmc_init(i); +	} +	return 0; +} + +void tegra_mmc_init(void) +{ +	int node_list[MAX_HOSTS], count; +	const void *blob = gd->fdt_blob; +	debug("%s entry\n", __func__); + +	/* See if any Tegra30 MMC controllers are present */ +	count = fdtdec_find_aliases_for_id(blob, "sdhci", +		COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS); +	debug("%s: count of T30 sdhci nodes is %d\n", __func__, count); +	if (process_nodes(blob, node_list, count)) { +		printf("%s: Error processing T30 mmc node(s)!\n", __func__); +		return; +	} + +	/* Now look for any Tegra20 MMC controllers */ +	count = fdtdec_find_aliases_for_id(blob, "sdhci", +		COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS); +	debug("%s: count of T20 sdhci nodes is %d\n", __func__, count); +	if (process_nodes(blob, node_list, count)) { +		printf("%s: Error processing T20 mmc node(s)!\n", __func__); +		return; +	} +} |