X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fmmc%2Fsdhci.c;h=372dc0a820174c2708131e2b52905e82bf0574f6;hb=04da42770b0cc3bea8841972bfc9568299ece826;hp=e2bb90abbdf3c5b05af34a23526f75da985df62d;hpb=44237e272f1eac3b026709e76333a07b2d3a3523;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index e2bb90a..372dc0a 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -8,16 +8,14 @@ */ #include +#include +#include #include #include #include #include - -#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) -void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; -#else -void *aligned_buffer; -#endif +#include +#include static void sdhci_reset(struct sdhci_host *host, u8 mask) { @@ -68,8 +66,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) } #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) -static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len, - bool end) +static void sdhci_adma_desc(struct sdhci_host *host, dma_addr_t dma_addr, + u16 len, bool end) { struct sdhci_adma_desc *desc; u8 attr; @@ -85,9 +83,9 @@ static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len, desc->attr = attr; desc->len = len; desc->reserved = 0; - desc->addr_lo = (dma_addr_t)buf; + desc->addr_lo = lower_32_bits(dma_addr); #ifdef CONFIG_DMA_ADDR_T_64BIT - desc->addr_hi = (u64)buf >> 32; + desc->addr_hi = upper_32_bits(dma_addr); #endif } @@ -97,22 +95,17 @@ static void sdhci_prepare_adma_table(struct sdhci_host *host, uint trans_bytes = data->blocksize * data->blocks; uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); int i = desc_count; - char *buf; + dma_addr_t dma_addr = host->start_addr; host->desc_slot = 0; - if (data->flags & MMC_DATA_READ) - buf = data->dest; - else - buf = (char *)data->src; - while (--i) { - sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false); - buf += ADMA_MAX_LEN; + sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false); + dma_addr += ADMA_MAX_LEN; trans_bytes -= ADMA_MAX_LEN; } - sdhci_adma_desc(host, buf, trans_bytes, true); + sdhci_adma_desc(host, dma_addr, trans_bytes, true); flush_cache((dma_addr_t)host->adma_desc_table, ROUND(desc_count * sizeof(struct sdhci_adma_desc), @@ -128,11 +121,12 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, int *is_aligned, int trans_bytes) { unsigned char ctrl; + void *buf; if (data->flags == MMC_DATA_READ) - host->start_addr = (dma_addr_t)data->dest; + buf = data->dest; else - host->start_addr = (dma_addr_t)data->src; + buf = (void *)data->src; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; @@ -142,37 +136,30 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - if (host->flags & USE_SDMA) { - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && - (host->start_addr & 0x7) != 0x0) { - *is_aligned = 0; - host->start_addr = (unsigned long)aligned_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); - } - -#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) - /* - * Always use this bounce-buffer when - * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined - */ + if (host->flags & USE_SDMA && + (host->force_align_buffer || + (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR && + ((unsigned long)buf & 0x7) != 0x0))) { *is_aligned = 0; - host->start_addr = (unsigned long)aligned_buffer; if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); -#endif - sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); + memcpy(host->align_buffer, buf, trans_bytes); + buf = host->align_buffer; + } + host->start_addr = dma_map_single(buf, trans_bytes, + mmc_get_dma_dir(data)); + + if (host->flags & USE_SDMA) { + sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); } else if (host->flags & (USE_ADMA | USE_ADMA64)) { sdhci_prepare_adma_table(host, data); - sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS); + sdhci_writel(host, lower_32_bits(host->adma_addr), + SDHCI_ADMA_ADDRESS); if (host->flags & USE_ADMA64) - sdhci_writel(host, (u64)host->adma_addr >> 32, + sdhci_writel(host, upper_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS_HI); } - - flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN)); } #else static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, @@ -228,6 +215,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data) return -ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); + + dma_unmap_single(host->start_addr, data->blocks * data->blocksize, + mmc_get_dma_dir(data)); + return 0; } @@ -378,7 +369,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) - memcpy(data->dest, aligned_buffer, trans_bytes); + memcpy(data->dest, host->align_buffer, trans_bytes); return 0; } @@ -408,7 +399,7 @@ static int sdhci_execute_tuning(struct udevice *dev, uint opcode) return 0; } #endif -static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) +int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; @@ -532,6 +523,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } +void sdhci_set_uhs_timing(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + u32 reg; + + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; + + switch (mmc->selected_mode) { + case UHS_SDR50: + case MMC_HS_52: + reg |= SDHCI_CTRL_UHS_SDR50; + break; + case UHS_DDR50: + case MMC_DDR_52: + reg |= SDHCI_CTRL_UHS_DDR50; + break; + case UHS_SDR104: + case MMC_HS_200: + reg |= SDHCI_CTRL_UHS_SDR104; + break; + default: + reg |= SDHCI_CTRL_UHS_SDR12; + } + + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); +} + #ifdef CONFIG_DM_MMC static int sdhci_set_ios(struct udevice *dev) { @@ -582,7 +601,7 @@ static int sdhci_set_ios(struct mmc *mmc) /* If available, call the driver specific "post" set_ios() function */ if (host->ops && host->ops->set_ios_post) - host->ops->set_ios_post(host); + return host->ops->set_ios_post(host); return 0; } @@ -590,17 +609,32 @@ static int sdhci_set_ios(struct mmc *mmc) static int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; +#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_GPIO) + struct udevice *dev = mmc->dev; + + gpio_request_by_name(dev, "cd-gpios", 0, + &host->cd_gpio, GPIOD_IS_IN); +#endif sdhci_reset(host, SDHCI_RESET_ALL); - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { - aligned_buffer = memalign(8, 512*1024); - if (!aligned_buffer) { +#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) + host->align_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; + /* + * Always use this bounce-buffer when CONFIG_FIXED_SDHCI_ALIGNED_BUFFER + * is defined. + */ + host->force_align_buffer = true; +#else + if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) { + host->align_buffer = memalign(8, 512 * 1024); + if (!host->align_buffer) { printf("%s: Aligned buffer alloc failed!!!\n", __func__); return -ENOMEM; } } +#endif sdhci_set_power(host, fls(mmc->cfg->voltages) - 1); @@ -624,9 +658,55 @@ int sdhci_probe(struct udevice *dev) return sdhci_init(mmc); } +static int sdhci_deferred_probe(struct udevice *dev) +{ + int err; + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + + if (host->ops && host->ops->deferred_probe) { + err = host->ops->deferred_probe(host); + if (err) + return err; + } + return 0; +} + +static int sdhci_get_cd(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + int value; + + /* If nonremovable, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE) + return 1; + /* If polling, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL) + return 1; + +#if CONFIG_IS_ENABLED(DM_GPIO) + value = dm_gpio_get_value(&host->cd_gpio); + if (value >= 0) { + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; + } +#endif + value = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT); + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; +} + const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, + .get_cd = sdhci_get_cd, + .deferred_probe = sdhci_deferred_probe, #ifdef MMC_SUPPORTS_TUNING .execute_tuning = sdhci_execute_tuning, #endif @@ -643,8 +723,20 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 f_max, u32 f_min) { u32 caps, caps_1 = 0; - +#if CONFIG_IS_ENABLED(DM_MMC) + u64 dt_caps, dt_caps_mask; + + dt_caps_mask = dev_read_u64_default(host->mmc->dev, + "sdhci-caps-mask", 0); + dt_caps = dev_read_u64_default(host->mmc->dev, + "sdhci-caps", 0); + caps = ~(u32)dt_caps_mask & + sdhci_readl(host, SDHCI_CAPABILITIES); + caps |= (u32)dt_caps; +#else caps = sdhci_readl(host, SDHCI_CAPABILITIES); +#endif + debug("%s, caps: 0x%x\n", __func__, caps); #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -661,8 +753,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, __func__); return -EINVAL; } - host->adma_desc_table = (struct sdhci_adma_desc *) - memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); + host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); host->adma_addr = (dma_addr_t)host->adma_desc_table; #ifdef CONFIG_DMA_ADDR_T_64BIT @@ -684,7 +775,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { +#if CONFIG_IS_ENABLED(DM_MMC) + caps_1 = ~(u32)(dt_caps_mask >> 32) & + sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps_1 |= (u32)(dt_caps >> 32); +#else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); +#endif + debug("%s, caps_1: 0x%x\n", __func__, caps_1); host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } @@ -741,11 +839,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - - if (!(cfg->voltages & MMC_VDD_165_195) || - (host->quirks & SDHCI_QUIRK_NO_1_8_V)) + if (!(cfg->voltages & MMC_VDD_165_195)) caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);