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 | 227 |
14 files changed, 276 insertions, 102 deletions
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index af1380a..ab2e81e 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 0f98b96..2631174 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 ee8f261..e2379e3 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 b90f3e7..54b5363 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 f1702fe..42f0e0c 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 67b2dbe..70a9f91 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 72e8ce6..7b5fdd9 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 11ba532..fe6a5a1 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 d58c18b..4f99617 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 a72f66c..a89660f 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 afd9b30..67cfcc2 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 b9cbe34..daca0ea 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 4588568..011d4f3 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 d749ab0..e86bc68 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); - - 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; + u8 pwr = 0; + debug("%s: power = %x\n", __func__, power); + + 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); - host->reg = (struct tegra_mmc *)host->base; + /* Set the bus voltage first (if any) */ + writeb(pwr, &host->reg->pwrcon); + if (pwr == 0) + return; + + /* 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; + } +} |