static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) { u16 clk; unsigned long timeout; clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk &= ~(SDHCI_CLOCK_CARD_EN); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); /* Issue DLL Reset */ zynqmp_dll_reset(deviceid); /* Wait max 20 ms */ timeout = 100; while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { dev_err(mmc_dev(host->mmc), ": Internal clock never stabilised.\n"); return; } timeout--; udelay(1000); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); }
static int sdhci_set_clock(struct mmc_host *mmc, u32 clock) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; u32 div, clk, timeout; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); if (clock == 0) { return VMM_OK; } if ((host->sdhci_version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { /* Version 3.00 divisors must be a multiple of 2. */ if (mmc->f_max <= clock) div = 1; else { for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { if (udiv32(mmc->f_max, div) <= clock) { break; } } } } else { /* Version 2.00 divisors must be a power of 2. */ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { if (udiv32(mmc->f_max, div) <= clock) { break; } } } div >>= 1; if (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) { vmm_printf("%s: Internal clock never stabilised.\n", __func__); return VMM_EFAIL; } timeout--; vmm_udelay(1000); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); return VMM_OK; }
/* sdhci_cmu_set_clock - callback on clock change.*/ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned long timeout; u16 clk = 0; /* don't bother if the clock is going off */ if (clock == 0) return; sdhci_s3c_set_clock(host, clock); clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); host->clock = clock; 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) { printk(KERN_ERR "%s: Internal clock never " "stabilised.\n", mmc_hostname(host->mmc)); return; } timeout--; mdelay(1); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); }
static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret = 0; printk(KERN_INFO "%s (%s) ++ \n", __func__, mmc_hostname(host->sdhci->mmc)); if (time_before(jiffies, host->card_detection_time + msecs_to_jiffies(SD_TIME_GAP_FOR_SUSPEND))) { printk(KERN_INFO "%s: Prevent from going to suspend mode too soon \n", __func__); return -1; } if (host->irq_cd != -1) disable_irq(host->irq_cd); if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { int div = 0; u16 clk; unsigned int clock = 100000; if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(host->sdhci->irq); } /* save interrupt status before suspending */ host->sdhci_ints = sdhci_readl(host->sdhci, SDHCI_INT_ENABLE); /* reduce host controller clk and card clk to 100 KHz */ tegra_sdhci_set_clock(host->sdhci, clock); sdhci_writew(host->sdhci, 0, SDHCI_CLOCK_CONTROL); if (host->sdhci->max_clk > clock) { div = 1 << (fls(host->sdhci->max_clk / clock) - 2); if (div > 128) div = 128; } clk = div << SDHCI_DIVIDER_SHIFT; clk |= SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; sdhci_writew(host->sdhci, clk, SDHCI_CLOCK_CONTROL); return ret; } /* * Set disable_delay to zero * to disable mmc_schedule_delay_work * before suspend */ mmc_set_disable_delay(host->sdhci->mmc, 0); ret = sdhci_suspend_host(host->sdhci, state); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); tegra_sdhci_enable_clock(host, 0); printk(KERN_INFO "%s (%s) -- \n", __func__, mmc_hostname(host->sdhci->mmc)); return ret; }
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; unsigned int div, clk, timeout; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); if (clock == 0) return 0; if(host->clock == clock) return 0; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { /* Version 3.00 divisors must be a multiple of 2. */ if (mmc->f_max <= clock) div = 1; else { for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { if ((mmc->f_max / div) <= clock) break; } } } else { /* Version 2.00 divisors must be a power of 2. */ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { if ((mmc->f_max / div) <= clock) break; } } div >>= 1; div = div -1; if (host->set_clock) host->set_clock(host->index, 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); host->clock = clock; /* Wait max 20 ms */ timeout = 20; while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { errorf("%s: Internal clock never stabilised.\n", __func__); return -1; } timeout--; udelay(1000); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); return 0; }
static void xenon_mmc_phy_set(struct sdhci_host *host) { struct xenon_sdhci_priv *priv = host->mmc->priv; u32 var; /* Setup pad, set bit[30], bit[28] and bits[26:24] */ var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL); var |= AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN; sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL); /* Set CMD and DQ Pull Up */ var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL1); /* * If timing belongs to high speed, set bit[17] of * EMMC_PHY_TIMING_ADJUST register */ if ((priv->timing == MMC_TIMING_MMC_HS400) || (priv->timing == MMC_TIMING_MMC_HS200) || (priv->timing == MMC_TIMING_UHS_SDR50) || (priv->timing == MMC_TIMING_UHS_SDR104) || (priv->timing == MMC_TIMING_UHS_DDR50) || (priv->timing == MMC_TIMING_UHS_SDR25) || (priv->timing == MMC_TIMING_MMC_DDR52)) { var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); var |= OUTPUT_QSN_PHASE_SELECT; sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); } /* * When setting EMMC_PHY_FUNC_CONTROL register, * SD clock should be disabled */ var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); var &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); if (host->mmc->ddr_mode) { var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; } else { var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE); } sdhci_writel(host, var, EMMC_PHY_FUNC_CONTROL); /* Enable bus clock */ var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); var |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); xenon_mmc_phy_init(host); }
static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data) { int ret; sdhci_writew(host, 0, PHY_DAT_REG); sdhci_writew(host, offset, PHY_ADDR_REG); ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); /* Masking valid data bits */ *data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK; return ret; }
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_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 pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { u16 ctrl_2; /* * Set V18_EN -- UHS modes do not work without this. * does not change signaling voltage */ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", __func__, uhs, ctrl_2); }
static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host) { u16 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); ctrl &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL); }
static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) { if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL); sdhci_reset(host, mask); }
static void tegra_sdhci_reset(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; u32 misc_ctrl; sdhci_reset(host, mask); if (!(mask & SDHCI_RESET_ALL)) return; misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; /* Don't advertise UHS modes which aren't supported yet */ if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50) misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50; if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50) misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104) misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); }
static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); u16 ctrl_2; /* * Set V18_EN -- UHS modes do not work without this. * does not change signaling voltage */ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } /* * Update SDIO3 Configuration register according to erratum * FE-2946959 */ if (pxa->sdio3_conf_reg) { u8 reg_val = readb(pxa->sdio3_conf_reg); if (uhs == MMC_TIMING_UHS_SDR50 || uhs == MMC_TIMING_UHS_DDR50) { reg_val &= ~SDIO3_CONF_CLK_INV; reg_val |= SDIO3_CONF_SD_FB_CLK; } else if (uhs == MMC_TIMING_MMC_HS) { reg_val &= ~SDIO3_CONF_CLK_INV; reg_val &= ~SDIO3_CONF_SD_FB_CLK; } else { reg_val |= SDIO3_CONF_CLK_INV; reg_val &= ~SDIO3_CONF_SD_FB_CLK; } writeb(reg_val, pxa->sdio3_conf_reg); } sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", __func__, uhs, ctrl_2); }
static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret = 0; 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 div = 0; u16 clk; unsigned int clock = 100000; if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(host->sdhci->irq); } /* save interrupt status before suspending */ host->sdhci_ints = sdhci_readl(host->sdhci, SDHCI_INT_ENABLE); /* reduce host controller clk and card clk to 100 KHz */ tegra_sdhci_set_clock(host->sdhci, clock); sdhci_writew(host->sdhci, 0, SDHCI_CLOCK_CONTROL); if (host->sdhci->max_clk > clock) { div = 1 << (fls(host->sdhci->max_clk / clock) - 2); if (div > 128) div = 128; } clk = div << SDHCI_DIVIDER_SHIFT; clk |= SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; sdhci_writew(host->sdhci, clk, SDHCI_CLOCK_CONTROL); printk("tegra_sdhci_suspend: skip %s suspend(always on)!\n",is_card_mmc(host->sdhci->mmc->card)?"eMMC":"SDIO"); return ret; } ret = sdhci_suspend_host(host->sdhci, state); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); tegra_sdhci_enable_clock(host, 0); MMC_printk("%s:-", mmc_hostname(host->sdhci->mmc)); return ret; }
static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; unsigned long timeout; host->mmc->actual_clock = 0; /* * There is no requirement to disable the internal clock before * changing the SD clock configuration. Moreover, disabling the * internal clock, changing the configuration and re-enabling the * internal clock causes some bugs. It can prevent to get the internal * clock stable flag ready and an unexpected switch to the base clock * when using presets. */ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk &= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); if (clock == 0) return; clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 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) { pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc)); return; } timeout--; mdelay(1); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); }
static void pxav3_clk_gate_auto(struct sdhci_host *host, unsigned int ctrl) { u16 tmp; tmp = sdhci_readw(host, SD_FIFO_PARAM); tmp &= ~PAD_CLK_GATE_MASK; sdhci_writew(host, tmp, SD_FIFO_PARAM); /* * FIXME: according to spec, bit SDHCI_CTRL_ASYNC_INT * should be used to deliver async interrupt requested by sdio device * rather than auto clock gate. But current host controller use this * bit to enable/disable auto clock gate. */ tmp = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (ctrl) tmp |= SDHCI_CTRL_ASYNC_INT; else tmp &= ~SDHCI_CTRL_ASYNC_INT; sdhci_writew(host, tmp, SDHCI_HOST_CONTROL2); }
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; u32 reg; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) ; reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); reg &= ~SDHCI_CLOCK_CARD_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 / 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) {
static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct mmc_host *mmc = host->mmc; u16 ctrl_2; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50; break; case MMC_TIMING_MMC_HS200: case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104; break; case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: ctrl_2 |= SDHCI_CTRL_UHS_DDR50; break; } /* * When clock frequency is less than 100MHz, the feedback clock must be * provided and DLL must not be used so that tuning can be skipped. To * provide feedback clock, the mode selection can be any value less * than 3'b011 in bits [2:0] of HOST CONTROL2 register. */ if (host->clock <= 100000000 && (uhs == MMC_TIMING_MMC_HS400 || uhs == MMC_TIMING_MMC_HS200 || uhs == MMC_TIMING_UHS_SDR104)) ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); }
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock) { bool en = false; if (clock == 0) { sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); } else if (clock != host->clock) { sdhci_sprd_sd_clk_off(host); _sdhci_sprd_set_clock(host, clock); if (clock <= 400000) en = true; sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV | SDHCI_SPRD_BIT_POSRD_DLY_INV, en); } else { _sdhci_sprd_set_clock(host, clock); } }
static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; u32 reg, vendor_ptr; vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); /* Disable software managed rx tuning */ reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr)); reg &= ~SDHC_SW_TUNE_EN; sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr)); if (clock <= 52000000) { sdhci_set_clock(host, clock); } else { /* Assert reset to MMCM */ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); reg |= SDHC_CCLK_MMCM_RST; sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); /* Configure MMCM */ if (clock == 100000000) { sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG); sdhci_writel(host, CLKFBOUT_100_MHZ, SDHC_MMCM_CLKFBOUT); } else { sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG); sdhci_writel(host, CLKFBOUT_200_MHZ, SDHC_MMCM_CLKFBOUT); } /* De-assert reset to MMCM */ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); reg &= ~SDHC_CCLK_MMCM_RST; sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); /* Enable clock */ clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } }
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { u16 ctrl_2; if (timing == host->timing) return; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (timing) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_MMC_HS: case MMC_TIMING_SD_HS: case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50; break; case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104; break; case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: ctrl_2 |= SDHCI_CTRL_UHS_DDR50; break; case MMC_TIMING_MMC_HS200: ctrl_2 |= SDHCI_SPRD_CTRL_HS200; break; case MMC_TIMING_MMC_HS400: ctrl_2 |= SDHCI_SPRD_CTRL_HS400; break; default: break; } sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); }
static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable) { bool status; u32 reg; reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); status = !!(reg & SDHCI_CLOCK_CARD_EN); if (status == enable) return status; if (enable) reg |= SDHCI_CLOCK_CARD_EN; else reg &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); return status; }
static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { u16 ctrl_2; /* */ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", __func__, uhs, ctrl_2); return 0; }
static void sdhci_pltfm_shutdown(struct platform_device *pdev) { u16 clk; int ret; struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_get_sync(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) dev_err(dev->dev, "enable clock during shutdown failed\n"); } /* Certain cards don't like abrupt clock * shutdown, and they go insane if we do so. * When PM runtime autosuspend is enabled, * it takes time for the clock to be cut, * but during this time, the system reboot * can abruptly cut it off. Avoid that by * disabling the clock to the card. */ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_put_sync_suspend(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 0); if (ret) dev_err(dev->dev, "disable clock during shutdown failed\n"); } }
/** * __sdhci_msm_set_clock - sdhci_msm clock control. * * Description: * MSM controller does not use internal divider and * instead directly control the GCC clock as per * HW recommendation. **/ void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; /* * Keep actual_clock as zero - * - since there is no divider used so no need of having actual_clock. * - MSM controller uses SDCLK for data timeout calculation. If * actual_clock is zero, host->clock is taken for calculation. */ host->mmc->actual_clock = 0; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); if (clock == 0) return; /* * MSM controller do not use clock divider. * Thus read SDHCI_CLOCK_CONTROL and only enable * clock with no divider value programmed. */ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); sdhci_enable_clk(host, clk); }
static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) { struct mmc_cmd cmd; struct mmc_data data; u32 ctrl; struct sdhci_host *host; struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev); u8 tuning_loop_counter = 40; u8 deviceid; debug("%s\n", __func__); host = priv->host; deviceid = priv->deviceid; ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2); mdelay(1); arasan_zynqmp_dll_reset(host, deviceid); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); do { cmd.cmdidx = opcode; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 0; data.blocksize = 64; data.blocks = 1; data.flags = MMC_DATA_READ; if (tuning_loop_counter-- == 0) break; if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 && mmc->bus_width == 8) data.blocksize = 128; 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, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); mmc_send_cmd(mmc, &cmd, NULL); ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK) udelay(1); } while (ctrl & SDHCI_CTRL_EXEC_TUNING); if (tuning_loop_counter < 0) { ctrl &= ~SDHCI_CTRL_TUNED_CLK; sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2); } if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { debug("%s:Tuning failed\n", __func__); return -1; } else { udelay(1); arasan_zynqmp_dll_reset(host, deviceid); } /* 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; }
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; }
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; /* 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); } sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); if (clock == 0) return 0; if (host->ops && host->ops->set_delay) host->ops->set_delay(host); 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 ((host->max_clk / 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 (host->max_clk <= clock) { div = 1; } else { for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { if ((host->max_clk / 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) {
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; }