static void sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr = 0; if (power != (unsigned short)-1) { switch (1 << power) { case MMC_VDD_165_195: pwr = SDHCI_POWER_180; break; case MMC_VDD_29_30: case MMC_VDD_30_31: pwr = SDHCI_POWER_300; break; case MMC_VDD_32_33: case MMC_VDD_33_34: pwr = SDHCI_POWER_330; break; } } if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); return; } if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); }
static int tegra_sdhci_restore(struct sdhci_host *sdhost) { unsigned long timeout; u8 mask = SDHCI_RESET_ALL; u8 pwr; sdhci_writeb(sdhost, mask, SDHCI_SOFTWARE_RESET); sdhost->clock = 0; /* Wait max 100 ms */ timeout = 100; /* hw clears the bit when it's done */ while (sdhci_readb(sdhost, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { printk(KERN_ERR "%s: Reset 0x%x never completed.\n", mmc_hostname(sdhost->mmc), (int)mask); return -EIO; } timeout--; mdelay(1); } tegra_sdhci_restore_interrupts(sdhost); pwr = SDHCI_POWER_ON; sdhci_writeb(sdhost, pwr, SDHCI_POWER_CONTROL); sdhost->pwr = 0; return 0; }
static void tegra_sdhci_enable_clock(struct tegra_sdhci_host *host, int enable) { if (enable && !host->clk_enabled) { clk_enable(host->clk); sdhci_writeb(host->sdhci, 1, SDHCI_VENDOR_CLOCK_CNTRL); host->clk_enabled = 1; } else if (!enable && host->clk_enabled) { sdhci_writeb(host->sdhci, 0, SDHCI_VENDOR_CLOCK_CNTRL); clk_disable(host->clk); host->clk_enabled = 0; } }
static void sdhci_restore_regs(struct sdhci_host *host) { if (!strcmp("Spread SDIO host1", host->hw_name)){ sdhci_writel(host, host_addr, SDHCI_DMA_ADDRESS); sdhci_writew(host, host_blk_size, SDHCI_BLOCK_SIZE); sdhci_writew(host, host_blk_cnt, SDHCI_BLOCK_COUNT); sdhci_writel(host, host_arg, SDHCI_ARGUMENT); sdhci_writew(host, host_tran_mode, SDHCI_TRANSFER_MODE); sdhci_writeb(host, host_ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, host_power, SDHCI_POWER_CONTROL); sdhci_writew(host, host_clk, SDHCI_CLOCK_CONTROL); } }
static void sdhci_restore_regs(struct sdhci_host *host) { struct sprd_host_platdata *host_pdata = sdhci_get_platdata(host); if (!host_pdata->regs.is_valid) return; sdhci_writel(host, host_pdata->regs.addr, SDHCI_DMA_ADDRESS); sdhci_writew(host, host_pdata->regs.blk_size, SDHCI_BLOCK_SIZE); sdhci_writew(host, host_pdata->regs.blk_cnt, SDHCI_BLOCK_COUNT); sdhci_writel(host, host_pdata->regs.arg, SDHCI_ARGUMENT); sdhci_writew(host, host_pdata->regs.tran_mode, SDHCI_TRANSFER_MODE); sdhci_writeb(host, host_pdata->regs.ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, host_pdata->regs.power, SDHCI_POWER_CONTROL); sdhci_writew(host, host_pdata->regs.clk, SDHCI_CLOCK_CONTROL); }
static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) { u8 reg; reg = sdhci_readb(host, SDHCI_POWER_CONTROL); reg |= 0x10; sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); /* For eMMC, minimum is 1us but give it 9us for good measure */ udelay(9); reg &= ~0x10; sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); /* For eMMC, minimum is 200us but give it 300us for good measure */ usleep_range(300, 1000); }
void sdhci_set_ios(struct mmc *mmc) { u32 ctrl; struct sdhci_host *host = (struct sdhci_host *)mmc->priv; if (mmc->clock != host->clock) sdhci_set_clock(mmc, mmc->clock); /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; if (host->version >= SDHCI_SPEC_300) ctrl |= SDHCI_CTRL_8BITBUS; } else { if (host->version >= SDHCI_SPEC_300) ctrl &= ~SDHCI_CTRL_8BITBUS; if (mmc->bus_width == 4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } if (mmc->clock > 26000000) ctrl |= SDHCI_CTRL_HISPD; else ctrl &= ~SDHCI_CTRL_HISPD; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
/** * sdhci_s3c_platform_bus_width - support 8bit buswidth * @host: The SDHCI host being queried * @width: MMC_BUS_WIDTH_ macro for the bus width being requested * * We have 8-bit width support but is not a v3 controller. * So we add platform_bus_width() and support 8bit width. */ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) { u8 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); switch (width) { case MMC_BUS_WIDTH_8: ctrl |= SDHCI_CTRL_8BITBUS; ctrl &= ~SDHCI_CTRL_4BITBUS; break; case MMC_BUS_WIDTH_4: ctrl |= SDHCI_CTRL_4BITBUS; ctrl &= ~SDHCI_CTRL_8BITBUS; break; default: ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl &= ~SDHCI_CTRL_8BITBUS; break; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); return 0; }
/** * sdhci_s3c_platform_8bit_width - support 8bit buswidth * @host: The SDHCI host being queried * @width: MMC_BUS_WIDTH_ macro for the bus width being requested * * We have 8-bit width support but is not a v3 controller. * So we add platform_8bit_width() and support 8bit width. */ static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width) { u8 ctrl; struct sdhci_s3c *ourhost = to_s3c(host); ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); switch (width) { case MMC_BUS_WIDTH_8: ctrl |= SDHCI_CTRL_8BITBUS; ctrl &= ~SDHCI_CTRL_4BITBUS; /* call cfg_gpio with 8bit data bus */ if (ourhost->pdata->cfg_gpio) ourhost->pdata->cfg_gpio(ourhost->pdev, 8); break; case MMC_BUS_WIDTH_4: ctrl |= SDHCI_CTRL_4BITBUS; ctrl &= ~SDHCI_CTRL_8BITBUS; /* call cfg_gpio with 4bit data bus */ if (ourhost->pdata->cfg_gpio) ourhost->pdata->cfg_gpio(ourhost->pdev, 4); break; default: ctrl &= ~SDHCI_CTRL_8BITBUS; ctrl &= ~SDHCI_CTRL_4BITBUS; /* call cfg_gpio with 1bit data bus */ if (ourhost->pdata->cfg_gpio) ourhost->pdata->cfg_gpio(ourhost->pdev, 1); break; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); return 0; }
static int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { printf("%s: Aligned buffer alloc failed!!!\n", __func__); return -1; } } sdhci_set_power(host, fls(mmc->cfg->voltages) - 1); if (host->quirks & SDHCI_QUIRK_NO_CD) { #if defined(CONFIG_PIC32_SDHCI) /* PIC32 SDHCI CD errata: * - set CD_TEST and clear CD_TEST_INS bit */ sdhci_writeb(host, SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL); #else unsigned int status; sdhci_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL); status = sdhci_readl(host, SDHCI_PRESENT_STATE); while ((!(status & SDHCI_CARD_PRESENT)) || (!(status & SDHCI_CARD_STATE_STABLE)) || (!(status & SDHCI_CARD_DETECT_PIN_LEVEL))) status = sdhci_readl(host, SDHCI_PRESENT_STATE); #endif } /* Enable only interrupts served by the SD controller */ sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, SDHCI_INT_ENABLE); /* Mask all sdhci interrupt sources */ sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); return 0; }
static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, unsigned int start_addr) { unsigned int stat, rdy, mask, timeout, block = 0; bool transfer_done = false; #ifdef CONFIG_MMC_SDHCI_SDMA unsigned char ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); #endif timeout = 1000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { pr_debug("%s: Error detected in status(0x%X)!\n", __func__, stat); return -EIO; } if (!transfer_done && (stat & rdy)) { if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)) continue; sdhci_writel(host, rdy, SDHCI_INT_STATUS); sdhci_transfer_pio(host, data); data->dest += data->blocksize; if (++block >= data->blocks) { /* Keep looping until the SDHCI_INT_DATA_END is * cleared, even if we finished sending all the * blocks. */ transfer_done = true; continue; } } #ifdef CONFIG_MMC_SDHCI_SDMA if (!transfer_done && (stat & SDHCI_INT_DMA_END)) { sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS); start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); } #endif if (timeout-- > 0) udelay(10); else { printf("%s: Transfer data timeout\n", __func__); return -ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); return 0; }
static int tegra_sdhci_resume(struct platform_device *pdev) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret; #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA int i, present; #endif u8 pwr; if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { int ret = 0; if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(host->sdhci->irq); } /* soft reset SD host controller and enable interrupts */ ret = tegra_sdhci_restore(host->sdhci); if (ret) { pr_err("%s: failed, error = %d\n", __func__, ret); return ret; } mmiowb(); #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA for(i=0;i<20;i++){ present = sdhci_readl(host->sdhci, SDHCI_PRESENT_STATE); if((present & SDHCI_CARD_PRESENT) == SDHCI_CARD_PRESENT) break; mdelay(5); // printk(KERN_ERR "MMC : %s : 6(Card Presnet %x) : %d \n",mmc_hostname(host->sdhci->mmc),present,i); } #endif host->sdhci->mmc->ops->set_ios(host->sdhci->mmc, &host->sdhci->mmc->ios); return 0; } tegra_sdhci_enable_clock(host, 1); pwr = SDHCI_POWER_ON; sdhci_writeb(host->sdhci, pwr, SDHCI_POWER_CONTROL); host->sdhci->pwr = 0; ret = sdhci_resume_host(host->sdhci); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); return ret; }
static void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; /* Wait max 100 ms */ timeout = 100; sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { printf("Reset 0x%x never completed.\n", (int)mask); return; } timeout--; udelay(1000); } }
static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, unsigned int start_addr) { unsigned int stat, rdy, mask, timeout, block = 0; #ifdef CONFIG_MMC_SDMA unsigned char ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); #endif timeout = 90000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { errorf("%s: Error detected in status(0x%X)!\n", __func__, stat); return -1; } if (stat & rdy) { if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)) continue; sdhci_writel(host, rdy, SDHCI_INT_STATUS); sdhci_transfer_pio(host, data); data->dest += data->blocksize; if (++block >= data->blocks) break; } #ifdef CONFIG_MMC_SDMA if (stat & SDHCI_INT_DMA_END) { sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS); start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); } #endif if (timeout-- > 0) udelay(10); else { errorf("%s: Transfer data timeout\n", __func__); return -1; } } while (!(stat & SDHCI_INT_DATA_END)); return 0; }
static int bcm_kona_sd_reset(struct sdio_dev *dev) { struct sdhci_host *host = dev->host; unsigned int val; #ifdef CONFIG_ARCH_CAPRI unsigned int tries = 10000; #endif unsigned long timeout; /* Reset host controller by setting 'Software Reset for All' */ sdhci_writeb(host, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); /* Wait for 100 ms max (100ms timeout is taken from sdhci.c) */ timeout = jiffies + msecs_to_jiffies(100); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) { if (time_is_before_jiffies(timeout)) { dev_err(dev->dev, "Error: sd host is in reset!!!\n"); return -EFAULT; } } /* reset the host using the top level reset */ val = sdhci_readl(host, KONA_SDHOST_CORECTRL); val |= KONA_SDHOST_RESET; sdhci_writel(host, val, KONA_SDHOST_CORECTRL); do { val = sdhci_readl(host, KONA_SDHOST_CORECTRL); #ifdef CONFIG_ARCH_CAPRI if (--tries <= 0) break; #endif } while (0 == (val & KONA_SDHOST_RESET)); /* bring the host out of reset */ val = sdhci_readl(host, KONA_SDHOST_CORECTRL); val &= ~KONA_SDHOST_RESET; /* Back-to-Back register write needs a delay of 1ms * at bootup (min 10uS) */ udelay(1000); sdhci_writel(host, val, KONA_SDHOST_CORECTRL); return 0; }
static int sdhci_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else static int sdhci_set_ios(struct mmc *mmc) { #endif u32 ctrl; struct sdhci_host *host = mmc->priv; if (host->ops && host->ops->set_control_reg) host->ops->set_control_reg(host); if (mmc->clock != host->clock) sdhci_set_clock(mmc, mmc->clock); /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || (host->quirks & SDHCI_QUIRK_USE_WIDE8)) ctrl |= SDHCI_CTRL_8BITBUS; } else { if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || (host->quirks & SDHCI_QUIRK_USE_WIDE8)) ctrl &= ~SDHCI_CTRL_8BITBUS; if (mmc->bus_width == 4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } if (mmc->clock > 26000000) ctrl |= SDHCI_CTRL_HISPD; else ctrl &= ~SDHCI_CTRL_HISPD; if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) ctrl &= ~SDHCI_CTRL_HISPD; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); return 0; }
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { u32 ctrl; struct sdhci_host *host = mmc_priv(mmc); if (host->ops.set_control_reg) { host->ops.set_control_reg(host); } if (ios->clock != host->clock) { sdhci_set_clock(mmc, ios->clock); } /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (ios->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; if ((host->sdhci_version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { ctrl |= SDHCI_CTRL_8BITBUS; } } else { if ((host->sdhci_version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { ctrl &= ~SDHCI_CTRL_8BITBUS; } if (ios->bus_width == 4) { ctrl |= SDHCI_CTRL_4BITBUS; } else { ctrl &= ~SDHCI_CTRL_4BITBUS; } } if (ios->clock > 26000000) { ctrl |= SDHCI_CTRL_HISPD; } else { ctrl &= ~SDHCI_CTRL_HISPD; } if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) { ctrl &= ~SDHCI_CTRL_HISPD; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = pltfm_host->priv; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; if (!(mask & SDHCI_RESET_ALL)) return; /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) { u32 misc_ctrl; misc_ctrl = sdhci_readb(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; sdhci_writeb(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); } }
static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) { u32 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if ((host->mmc->caps & MMC_CAP_8_BIT_DATA) && (bus_width == MMC_BUS_WIDTH_8)) { ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl |= SDHCI_CTRL_8BITBUS; } else { ctrl &= ~SDHCI_CTRL_8BITBUS; if (bus_width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) { u8 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS); /* * CSR atlas7 and prima2 SD host version is not 3.0 * 8bit-width enable bit of CSR SD hosts is 3, * while stardard hosts use bit 5 */ if (width == MMC_BUS_WIDTH_8) ctrl |= SDHCI_SIRF_8BITBUS; else if (width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
static int tegra_sdhci_resume(struct platform_device *pdev) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret; u8 pwr; MMC_printk("%s:+", mmc_hostname(host->sdhci->mmc)); if ((host->card_always_on && is_card_sdio(host->sdhci->mmc->card))||is_card_mmc(host->sdhci->mmc->card)) { int ret = 0; if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(host->sdhci->irq); } /* soft reset SD host controller and enable interrupts */ ret = tegra_sdhci_restore(host->sdhci); if (ret) { pr_err("%s: failed, error = %d\n", __func__, ret); return ret; } mmiowb(); host->sdhci->mmc->ops->set_ios(host->sdhci->mmc, &host->sdhci->mmc->ios); printk("tegra_sdhci_suspend: skip %s resume(always on)!\n",is_card_mmc(host->sdhci->mmc->card)?"eMMC":"SDIO"); return 0; } tegra_sdhci_enable_clock(host, 1); pwr = SDHCI_POWER_ON; sdhci_writeb(host->sdhci, pwr, SDHCI_POWER_CONTROL); host->sdhci->pwr = 0; ret = sdhci_resume_host(host->sdhci); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); MMC_printk("%s:-", mmc_hostname(host->sdhci->mmc)); return ret; }
static void tegra_sdhci_restore_interrupts(struct sdhci_host *sdhost) { u32 ierr; u32 clear = SDHCI_INT_ALL_MASK; struct tegra_sdhci_host *host = sdhci_priv(sdhost); /* enable required interrupts */ ierr = sdhci_readl(sdhost, SDHCI_INT_ENABLE); ierr &= ~clear; ierr |= host->sdhci_ints; sdhci_writel(sdhost, ierr, SDHCI_INT_ENABLE); sdhci_writel(sdhost, ierr, SDHCI_SIGNAL_ENABLE); if ((host->sdhci_ints & SDHCI_INT_CARD_INT) && (sdhost->quirks & SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP)) { u8 gap_ctrl = sdhci_readb(sdhost, SDHCI_BLOCK_GAP_CONTROL); gap_ctrl |= 0x8; sdhci_writeb(sdhost, gap_ctrl, SDHCI_BLOCK_GAP_CONTROL); } }
static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = pltfm_host->priv; u32 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (tegra_host->is_8bit && bus_width == MMC_BUS_WIDTH_8) { ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl |= SDHCI_CTRL_8BITBUS; } else { ctrl &= ~SDHCI_CTRL_8BITBUS; if (bus_width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); return 0; }
static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) { struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); struct tegra_sdhci_platform_data *plat; u32 ctrl; plat = pdev->dev.platform_data; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl |= SDHCI_CTRL_8BITBUS; } else { ctrl &= ~SDHCI_CTRL_8BITBUS; if (bus_width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); return 0; }
void sdhci_set_ios(struct mmc *mmc) { u32 ctrl; struct sdhci_host *host = (struct sdhci_host *)mmc->priv; if (host->set_control_reg) host->set_control_reg(host); if (mmc->clock != host->clock) sdhci_set_clock(mmc, mmc->clock); /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || (host->quirks & SDHCI_QUIRK_USE_WIDE8)) ctrl |= SDHCI_CTRL_8BITBUS; } else { if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ctrl &= ~SDHCI_CTRL_8BITBUS; if (mmc->bus_width == 4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } #if 0 if (mmc->clock > 26000000) ctrl |= SDHCI_CTRL_HISPD; else #endif ctrl &= ~SDHCI_CTRL_HISPD; if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) ctrl &= ~SDHCI_CTRL_HISPD; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
static void sdhci_reset(struct sdhci_host *host, u8 mask) { u32 timeout; if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) return; } /* Wait max 100 ms */ timeout = 100; sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { vmm_printf("%s: Reset 0x%x never completed.\n", __func__, mask); return; } timeout--; vmm_udelay(1000); } }
int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; unsigned int stat = 0; int ret = 0; int trans_bytes = 0, is_aligned = 1; u32 mask, flags, mode; unsigned int timeout, start_addr = 0; unsigned int retry = 10000; /* Wait max 10 ms */ timeout = 10; sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) mask &= ~SDHCI_DATA_INHIBIT; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { printf("Controller never released inhibit bit(s).\n"); return COMM_ERR; } timeout--; udelay(1000); } mask = SDHCI_INT_RESPONSE; if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->resp_type & MMC_RSP_136) flags = SDHCI_CMD_RESP_LONG; else if (cmd->resp_type & MMC_RSP_BUSY) { flags = SDHCI_CMD_RESP_SHORT_BUSY; mask |= SDHCI_INT_DATA_END; } else flags = SDHCI_CMD_RESP_SHORT; if (cmd->resp_type & MMC_RSP_CRC) flags |= SDHCI_CMD_CRC; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; if (data) flags |= SDHCI_CMD_DATA; /*Set Transfer mode regarding to data flag*/ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; trans_bytes = data->blocks * data->blocksize; if (data->blocks > 1) mode |= SDHCI_TRNS_MULTI; if (data->flags == MMC_DATA_READ) mode |= SDHCI_TRNS_READ; #ifdef CONFIG_MMC_SDMA if (data->flags == MMC_DATA_READ) start_addr = (unsigned int)data->dest; else start_addr = (unsigned int)data->src; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (start_addr & 0x7) != 0x0) { is_aligned = 0; start_addr = (unsigned int)aligned_buffer; if (data->flags != MMC_DATA_READ) memcpy(aligned_buffer, data->src, trans_bytes); } sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); mode |= SDHCI_TRNS_DMA; #endif sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize), SDHCI_BLOCK_SIZE); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); #ifdef CONFIG_MMC_SDMA flush_cache(start_addr, trans_bytes); #endif sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) break; if (--retry == 0) break; } while ((stat & mask) != mask); if (retry == 0) { if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) return 0; else { printf("Timeout for status update!\n"); return TIMEOUT; } } if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { sdhci_cmd_done(host, cmd); sdhci_writel(host, mask, SDHCI_INT_STATUS); } else ret = -1; if (!ret && data) ret = sdhci_transfer_data(host, data, start_addr); if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) udelay(1000); stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) memcpy(data->dest, aligned_buffer, trans_bytes); return 0; } sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); if (stat & SDHCI_INT_TIMEOUT) return TIMEOUT; else return COMM_ERR; }
int sdhci_send_command(struct mmc_host *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { bool present; u32 mask, flags, mode; int ret = 0, trans_bytes = 0, is_aligned = 1; u32 timeout, retry = 10000, stat = 0, start_addr = 0; struct sdhci_host *host = mmc_priv(mmc); /* If polling, assume that the card is always present. */ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { present = TRUE; } else { present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; } /* If card not present then return error */ if (!present) { return VMM_EIO; } /* Wait max 10 ms */ timeout = 10; sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) { mask &= ~SDHCI_DATA_INHIBIT; } while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { vmm_printf("%s: Controller never released " "inhibit bit(s).\n", __func__); return VMM_EIO; } timeout--; vmm_udelay(1000); } mask = SDHCI_INT_RESPONSE; if (!(cmd->resp_type & MMC_RSP_PRESENT)) { flags = SDHCI_CMD_RESP_NONE; } else if (cmd->resp_type & MMC_RSP_136) { flags = SDHCI_CMD_RESP_LONG; } else if (cmd->resp_type & MMC_RSP_BUSY) { flags = SDHCI_CMD_RESP_SHORT_BUSY; mask |= SDHCI_INT_DATA_END; } else { flags = SDHCI_CMD_RESP_SHORT; } if (cmd->resp_type & MMC_RSP_CRC) { flags |= SDHCI_CMD_CRC; } if (cmd->resp_type & MMC_RSP_OPCODE) { flags |= SDHCI_CMD_INDEX; } if (data) { flags |= SDHCI_CMD_DATA; } /* Set Transfer mode regarding to data flag */ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; trans_bytes = data->blocks * data->blocksize; if (data->blocks > 1) { mode |= SDHCI_TRNS_MULTI; } if (data->flags == MMC_DATA_READ) { mode |= SDHCI_TRNS_READ; } if (host->sdhci_caps & SDHCI_CAN_DO_SDMA) { if (data->flags == MMC_DATA_READ) { start_addr = (u32)data->dest; } else { start_addr = (u32)data->src; } if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (start_addr & 0x7) != 0x0) { is_aligned = 0; start_addr = (u32)host->aligned_buffer; if (data->flags != MMC_DATA_READ) { memcpy(host->aligned_buffer, data->src, trans_bytes); } } sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); mode |= SDHCI_TRNS_DMA; vmm_flush_cache_range(start_addr, start_addr + trans_bytes); } sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize), SDHCI_BLOCK_SIZE); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { break; } if (--retry == 0) { break; } } while ((stat & mask) != mask); if (retry == 0) { if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) return VMM_OK; else { vmm_printf("%s: Status update timeout!\n", __func__); return VMM_ETIMEDOUT; } } if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { sdhci_cmd_done(host, cmd); sdhci_writel(host, mask, SDHCI_INT_STATUS); } else { ret = VMM_EFAIL; } if (!ret && data) { ret = sdhci_transfer_data(host, data, start_addr); } if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) { vmm_udelay(1000); } stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) { memcpy(data->dest, host->aligned_buffer, trans_bytes); } return VMM_OK; } sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); if (stat & SDHCI_INT_TIMEOUT) { return VMM_ETIMEDOUT; } else { return VMM_EIO; } }
static int sdhci_send_command(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { #endif struct sdhci_host *host = mmc->priv; unsigned int stat = 0; int ret = 0; int trans_bytes = 0, is_aligned = 1; u32 mask, flags, mode; unsigned int time = 0, start_addr = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; unsigned start = get_timer(0); /* Timeout unit - ms */ static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) mask &= ~SDHCI_DATA_INHIBIT; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { printf("%s: MMC: %d busy ", __func__, mmc_dev); if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", cmd_timeout); } else { puts("timeout.\n"); return -ECOMM; } } time++; udelay(1000); } mask = SDHCI_INT_RESPONSE; if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->resp_type & MMC_RSP_136) flags = SDHCI_CMD_RESP_LONG; else if (cmd->resp_type & MMC_RSP_BUSY) { flags = SDHCI_CMD_RESP_SHORT_BUSY; if (data) mask |= SDHCI_INT_DATA_END; } else flags = SDHCI_CMD_RESP_SHORT; if (cmd->resp_type & MMC_RSP_CRC) flags |= SDHCI_CMD_CRC; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; if (data) flags |= SDHCI_CMD_DATA; /* Set Transfer mode regarding to data flag */ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; trans_bytes = data->blocks * data->blocksize; if (data->blocks > 1) mode |= SDHCI_TRNS_MULTI; if (data->flags == MMC_DATA_READ) mode |= SDHCI_TRNS_READ; #ifdef CONFIG_MMC_SDHCI_SDMA if (data->flags == MMC_DATA_READ) start_addr = (unsigned long)data->dest; else start_addr = (unsigned long)data->src; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (start_addr & 0x7) != 0x0) { is_aligned = 0; 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 */ is_aligned = 0; start_addr = (unsigned long)aligned_buffer; if (data->flags != MMC_DATA_READ) memcpy(aligned_buffer, data->src, trans_bytes); #endif sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); mode |= SDHCI_TRNS_DMA; #endif sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize), SDHCI_BLOCK_SIZE); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } else if (cmd->resp_type & MMC_RSP_BUSY) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); } sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); #ifdef CONFIG_MMC_SDHCI_SDMA trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE); flush_cache(start_addr, trans_bytes); #endif sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); start = get_timer(0); do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) break; if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) { if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) { return 0; } else { printf("%s: Timeout for status update!\n", __func__); return -ETIMEDOUT; } } } while ((stat & mask) != mask); if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { sdhci_cmd_done(host, cmd); sdhci_writel(host, mask, SDHCI_INT_STATUS); } else ret = -1; if (!ret && data) ret = sdhci_transfer_data(host, data, start_addr); if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) udelay(1000); stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) memcpy(data->dest, aligned_buffer, trans_bytes); return 0; } sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); if (stat & SDHCI_INT_TIMEOUT) return -ETIMEDOUT; else return -ECOMM; } static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout, reg; /* Wait max 20 ms */ timeout = 200; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) { if (timeout == 0) { printf("%s: Timeout to wait cmd & data inhibit\n", __func__); return -EBUSY; } timeout--; udelay(100); } reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); if (clock == 0) return 0; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { /* * Check if the Host Controller supports Programmable Clock * Mode. */ if (host->clk_mul) { for (div = 1; div <= 1024; div++) { if ((mmc->cfg->f_max * host->clk_mul / div) <= clock) break; } /* * Set Programmable Clock Mode in the Clock * Control register. */ clk = SDHCI_PROG_CLOCK_MODE; div--; } else { /* Version 3.00 divisors must be a multiple of 2. */ if (mmc->cfg->f_max <= clock) { div = 1; } else { for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { if ((mmc->cfg->f_max / div) <= clock) break; } } div >>= 1; } } else { /* Version 2.00 divisors must be a power of 2. */ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { if ((mmc->cfg->f_max / div) <= clock) break; } div >>= 1; } if (host->ops && host->ops->set_clock) host->ops->set_clock(host, div); clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; clk |= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); /* Wait max 20 ms */ timeout = 20; while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { printf("%s: Internal clock never stabilised.\n", __func__); return -EBUSY; } timeout--; udelay(1000); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); return 0; }
static int sdhci_send_command(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { #endif struct sdhci_host *host = mmc->priv; unsigned int stat = 0; int ret = 0; int trans_bytes = 0, is_aligned = 1; u32 mask, flags, mode; unsigned int time = 0, start_addr = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; ulong start = get_timer(0); /* Timeout unit - ms */ static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION || ((cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) && !data)) mask &= ~SDHCI_DATA_INHIBIT; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { printf("%s: MMC: %d busy ", __func__, mmc_dev); if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", cmd_timeout); } else { puts("timeout.\n"); return -ECOMM; } } time++; udelay(1000); } sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_INT_RESPONSE; if ((cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) && !data) mask = SDHCI_INT_DATA_AVAIL; if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->resp_type & MMC_RSP_136) flags = SDHCI_CMD_RESP_LONG; else if (cmd->resp_type & MMC_RSP_BUSY) { flags = SDHCI_CMD_RESP_SHORT_BUSY; if (data) mask |= SDHCI_INT_DATA_END; } else flags = SDHCI_CMD_RESP_SHORT; if (cmd->resp_type & MMC_RSP_CRC) flags |= SDHCI_CMD_CRC; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; if (data || cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; /* Set Transfer mode regarding to data flag */ if (data) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; trans_bytes = data->blocks * data->blocksize; if (data->blocks > 1) mode |= SDHCI_TRNS_MULTI; if (data->flags == MMC_DATA_READ) mode |= SDHCI_TRNS_READ; #ifdef CONFIG_MMC_SDHCI_SDMA if (data->flags == MMC_DATA_READ) start_addr = (unsigned long)data->dest; else start_addr = (unsigned long)data->src; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (start_addr & 0x7) != 0x0) { is_aligned = 0; 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 */ is_aligned = 0; start_addr = (unsigned long)aligned_buffer; if (data->flags != MMC_DATA_READ) memcpy(aligned_buffer, data->src, trans_bytes); #endif sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); mode |= SDHCI_TRNS_DMA; #endif sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize), SDHCI_BLOCK_SIZE); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } else if (cmd->resp_type & MMC_RSP_BUSY) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); } sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); #ifdef CONFIG_MMC_SDHCI_SDMA if (data) { trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE); flush_cache(start_addr, trans_bytes); } #endif sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); start = get_timer(0); do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) break; if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) { if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) { return 0; } else { printf("%s: Timeout for status update!\n", __func__); return -ETIMEDOUT; } } } while ((stat & mask) != mask); if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { sdhci_cmd_done(host, cmd); sdhci_writel(host, mask, SDHCI_INT_STATUS); } else ret = -1; if (!ret && data) ret = sdhci_transfer_data(host, data, start_addr); if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) udelay(1000); stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) memcpy(data->dest, aligned_buffer, trans_bytes); return 0; } sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); if (stat & SDHCI_INT_TIMEOUT) return -ETIMEDOUT; else return -ECOMM; } #if defined(CONFIG_DM_MMC) && defined(MMC_SUPPORTS_TUNING) static int sdhci_execute_tuning(struct udevice *dev, uint opcode) { int err; struct mmc *mmc = mmc_get_mmc_dev(dev); struct sdhci_host *host = mmc->priv; debug("%s\n", __func__); if (host->ops && host->ops->platform_execute_tuning) { err = host->ops->platform_execute_tuning(mmc, opcode); if (err) return err; return 0; } return 0; }