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 void sdhci_save_regs(struct sdhci_host *host) { if (!strcmp("Spread SDIO host1", host->hw_name)){ host_addr = sdhci_readl(host, SDHCI_DMA_ADDRESS); host_blk_size = sdhci_readw(host, SDHCI_BLOCK_SIZE); host_blk_cnt = sdhci_readw(host, SDHCI_BLOCK_COUNT); host_arg = sdhci_readl(host, SDHCI_ARGUMENT); host_tran_mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); host_ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); host_power = sdhci_readb(host, SDHCI_POWER_CONTROL); host_clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); } }
static void sdhci_save_regs(struct sdhci_host *host) { struct sprd_host_platdata *host_pdata = sdhci_get_platdata(host); if (!host_pdata->regs.is_valid) return; host_pdata->regs.addr = sdhci_readl(host, SDHCI_DMA_ADDRESS); host_pdata->regs.blk_size = sdhci_readw(host, SDHCI_BLOCK_SIZE); host_pdata->regs.blk_cnt = sdhci_readw(host, SDHCI_BLOCK_COUNT); host_pdata->regs.arg = sdhci_readl(host, SDHCI_ARGUMENT); host_pdata->regs.tran_mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); host_pdata->regs.ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); host_pdata->regs.power = sdhci_readb(host, SDHCI_POWER_CONTROL); host_pdata->regs.clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); }
static int arasan_sdhci_probe(struct udevice *dev) { struct arasan_sdhci_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_host *host = dev_get_priv(dev); u32 caps; int ret; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; #ifdef CONFIG_ZYNQ_HISPD_BROKEN host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; #endif host->version = sdhci_readw(host, SDHCI_HOST_VERSION); caps = sdhci_readl(host, SDHCI_CAPABILITIES); ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width, caps, CONFIG_ZYNQ_SDHCI_MAX_FREQ, CONFIG_ZYNQ_SDHCI_MIN_FREQ, host->version, host->quirks, 0); host->mmc = &plat->mmc; if (ret) return ret; host->mmc->priv = host; host->mmc->dev = dev; upriv->mmc = host->mmc; return sdhci_probe(dev); }
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 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; }
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_display_bus_width(struct sdhci_ctrlr *sdhci_ctrlr) { if (IS_ENABLED(CONFIG_SDHC_DEBUG)) { int bits; uint8_t host_ctrl; uint16_t host2; const char *rate; uint16_t timing; /* Display the bus width */ host_ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_HOST_CONTROL); host2 = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_CONTROL2); timing = host2 & SDHCI_CTRL_UHS_MASK; bits = 1; if (host_ctrl & SDHCI_CTRL_8BITBUS) bits = 8; else if (host_ctrl & SDHCI_CTRL_4BITBUS) bits = 4; rate = "SDR"; if ((timing == SDHCI_CTRL_UHS_DDR50) || (timing == SDHCI_CTRL_HS400)) rate = "DDR"; sdhc_debug("SDHCI bus width: %d bit%s %s\n", bits, (bits != 1) ? "s" : "", rate); } }
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 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); }
/* 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 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 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 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 sdhci_dumpregs_err(struct sdhci_host *host) { printf("sdhci: ============== REGISTER DUMP ==============\n"); printf("sdhci: SDHCI_DMA_ADDRESS:\t0x%08x\n", sdhci_readl(host, SDHCI_DMA_ADDRESS)); printf("sdhci: SDHCI_BLOCK_SIZE:\t0x%08x\n", sdhci_readl(host, SDHCI_BLOCK_SIZE)); printf("sdhci: SDHCI_ARGUMENT:\t\t0x%08x\n", sdhci_readl(host, SDHCI_ARGUMENT)); printf("sdhci: SDHCI_TRANSFER_MODE:\t0x%08x\n", sdhci_readl(host, SDHCI_TRANSFER_MODE)); printf("sdhci: SDHCI_COMMAND:\t\t0x%08x\n", sdhci_readw(host, SDHCI_COMMAND)); printf("sdhci: SDHCI_RESPONSE0:\t\t0x%08x\n", sdhci_readl(host, SDHCI_RESPONSE)); printf("sdhci: SDHCI_RESPONSE1:\t\t0x%08x\n", sdhci_readl(host, SDHCI_RESPONSE + 0x4)); printf("sdhci: SDHCI_RESPONSE2:\t\t0x%08x\n", sdhci_readl(host, SDHCI_RESPONSE + 0x8)); printf("sdhci: SDHCI_RESPONSE3:\t\t0x%08x\n", sdhci_readl(host, SDHCI_RESPONSE + 0xC)); printf("sdhci: SDHCI_BUFFER:\t\t0x%08x\n", sdhci_readl(host, SDHCI_BUFFER)); printf("sdhci: SDHCI_PRESENT_STATE:\t0x%08x\n", sdhci_readl(host, SDHCI_PRESENT_STATE)); printf("sdhci: SDHCI_HOST_CONTROL:\t0x%08x\n", sdhci_readl(host, SDHCI_HOST_CONTROL)); printf("sdhci: SDHCI_CLOCK_CONTROL:\t0x%08x\n", sdhci_readl(host, SDHCI_CLOCK_CONTROL)); printf("sdhci: SDHCI_INT_STATUS:\t0x%08x\n", sdhci_readl(host, SDHCI_INT_STATUS)); printf("sdhci: SDHCI_INT_ENABLE:\t0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE)); printf("sdhci: SDHCI_SIGNAL_ENABLE:\t0x%08x\n", sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); printf("sdhci: SDHCI_ACMD12_ERR:\t0x%08x\n", sdhci_readl(host, SDHCI_ACMD12_ERR)); printf("sdhci: SDHCI_CAPABILITIES:\t0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES)); printf("sdhci: SDHCI_CAPABILITIES_1:\t0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES_1)); printf("sdhci: SDHCI_MAX_CURRENT:\t0x%08x\n", sdhci_readl(host, SDHCI_MAX_CURRENT)); printf("sdhci: SDHCI_SET_ACMD12_ERROR:\t0x%08x\n", sdhci_readl(host, SDHCI_SET_ACMD12_ERROR)); printf("sdhci: SDHCI_ADMA_ERROR:\t0x%08x\n", sdhci_readl(host, SDHCI_ADMA_ERROR)); printf("sdhci: SDHCI_ADMA_ADDRESS:\t0x%08x\n", sdhci_readl(host, SDHCI_ADMA_ADDRESS)); printf("sdhci: SDHCI_SLOT_INT_STATUS:\t0x%08x\n", sdhci_readl(host, SDHCI_SLOT_INT_STATUS)); printf("sdhci: ===========================================\n"); }
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 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 arasan_sdhci_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_host *host = dev_get_priv(dev); host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 0); upriv->mmc = host->mmc; return 0; }
static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask) { ktime_t timeout = ktime_add_us(ktime_get(), 100); bool failed; u8 val = 0; while (1) { failed = ktime_after(ktime_get(), timeout); val = sdhci_readw(host, PHY_ADDR_REG); if (!(val & mask)) return 0; if (failed) return -EBUSY; } }
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); }
void sdhci_dumpregs(struct sdhci_host *host) { int i = 0; printf(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); printf(KERN_DEBUG DRIVER_NAME ":AHB CTRL 0x%08x\n", *((unsigned int*)0x20900200)); #if 1 for(i = 0; i < MAX_DUMP_NUM; i++){ printf(KERN_DEBUG DRIVER_NAME ": address 0x%08x | value 0x%08x\n", host->ioaddr + i*4, sdhci_readl(host, i*4)); } #endif printf(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", sdhci_readl(host, SDHCI_DMA_ADDRESS), sdhci_readw(host, SDHCI_HOST_VERSION)); printf(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", sdhci_readw(host, SDHCI_BLOCK_SIZE), sdhci_readw(host, SDHCI_BLOCK_COUNT)); printf(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", sdhci_readl(host, SDHCI_ARGUMENT), sdhci_readw(host, SDHCI_TRANSFER_MODE)); printf(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", sdhci_readl(host, SDHCI_PRESENT_STATE), sdhci_readb(host, SDHCI_HOST_CONTROL)); printf(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", sdhci_readb(host, SDHCI_POWER_CONTROL), sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); printf(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), sdhci_readw(host, SDHCI_CLOCK_CONTROL)); printf(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), sdhci_readl(host, SDHCI_INT_STATUS)); printf(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE), sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); printf(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", sdhci_readw(host, SDHCI_ACMD12_ERR), sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); printf(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_MAX_CURRENT)); printf(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", readl(host->ioaddr + SDHCI_ADMA_ERROR), readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); printf(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); }
static int s5p_sdhci_core_init(struct sdhci_host *host) { host->name = S5P_NAME; host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8; host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); host->set_control_reg = &s5p_sdhci_set_control_reg; host->set_clock = set_mmc_clk; if (host->bus_width == 8) host->host_caps |= MMC_MODE_8BIT; return add_sdhci(host, 52000000, 400000); }
int zynq_sdhci_init(phys_addr_t regbase) { struct sdhci_host *host = NULL; host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); if (!host) { printf("zynq_sdhci_init: sdhci_host malloc fail\n"); return 1; } host->name = "zynq_sdhci"; host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); add_sdhci(host, 52000000, 52000000 >> 9); return 0; }
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; }
int zynq_sdhci_init(u32 regbase) { struct sdhci_host *host = NULL; host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); if (!host) { printf("zynq_sdhci_init: sdhci_host malloc fail\n"); return 1; } host->name = "zynq_sdhci"; host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); host->host_caps = MMC_MODE_HC; add_sdhci(host, 52000000, 52000000 >> 9); return 0; }
static void sdhci_display_clock(struct sdhci_ctrlr *sdhci_ctrlr) { if (IS_ENABLED(CONFIG_SDHC_DEBUG)) { uint16_t clk_ctrl; uint32_t clock; uint32_t divisor; /* Display the clock */ clk_ctrl = sdhci_readw(sdhci_ctrlr, SDHCI_CLOCK_CONTROL); sdhc_debug("SDHCI bus clock: "); if (clk_ctrl & SDHCI_CLOCK_CARD_EN) { divisor = (clk_ctrl >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIV_MASK; divisor |= ((clk_ctrl >> SDHCI_DIVIDER_SHIFT) << SDHCI_DIV_MASK_LEN) & SDHCI_DIV_HI_MASK; divisor <<= 1; clock = sdhci_ctrlr->sd_mmc_ctrlr.clock_base; if (divisor) clock /= divisor; sdhc_debug("%d.%03d MHz\n", clock / 1000000, (clock / 1000) % 1000); } else
/* * This driver has only been tested with eMMC devices; SD devices may * not work. */ int bcmstb_sdhci_init(phys_addr_t regbase) { struct sdhci_host *host = NULL; host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); if (!host) { printf("%s: Failed to allocate memory\n", __func__); return 1; } memset(host, 0, sizeof(*host)); host->name = BCMSTB_SDHCI_NAME; host->ioaddr = (void *)regbase; host->quirks = 0; host->cfg.part_type = PART_TYPE_DOS; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); return add_sdhci(host, BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); }