int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = NULL; /* memalign(8, 512*1024); */ /* FIXME: */ if (!aligned_buffer) { PRINT_ERR("Aligned buffer alloc failed!!!"); return -1; } } sdhci_set_power(host, fls(mmc->voltages) - 1); if (host->quirks & SDHCI_QUIRK_NO_CD) { unsigned int status; sdhci_writel(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); } /* Eable all state */ sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE); return 0; }
static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) { struct f_sdhost_priv *priv = sdhci_priv(host); u32 ctrl = 0; usleep_range(2500, 3000); ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2); ctrl |= F_SDH30_CRES_O_DN; sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); ctrl |= F_SDH30_MSEL_O_1_8; sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); ctrl &= ~F_SDH30_CRES_O_DN; sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); usleep_range(2500, 3000); if (priv->vendor_hs200) { dev_info(priv->dev, "%s: setting hs200\n", __func__); ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL); ctrl |= priv->vendor_hs200; sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL); } ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING); ctrl |= F_SDH30_CMD_CHK_DIS; sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING); }
static int bcm_kona_sd_init(struct sdio_dev *dev) { struct sdhci_host *host = dev->host; unsigned int val; /* enable the interrupt from the IP core */ val = sdhci_readl(host, KONA_SDHOST_COREIMR); val |= KONA_SDHOST_IP; sdhci_writel(host, val, KONA_SDHOST_COREIMR); /* * Enable DAT3 logic for card detection and enable the AHB clock to the * host */ val = sdhci_readl(host, KONA_SDHOST_CORECTRL); val |= /*KONA_SDHOST_CD_PINCTRL | */ KONA_SDHOST_EN; /* 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; }
int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { printf("Aligned buffer alloc failed!!!"); return -1; } } sdhci_set_power(host, fls(mmc->voltages) - 1); if (host->quirks & SDHCI_QUIRK_NO_CD) { unsigned int status; sdhci_writel(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); } /* 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 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, clk_ctrl; sdhci_reset(host, mask); if (!(mask & SDHCI_RESET_ALL)) return; misc_ctrl = sdhci_readl(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; /* Advertise UHS modes as supported by host */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); tegra_host->ddr_signaling = false; }
static int armada_38x_quirks(struct platform_device *pdev, struct sdhci_host *host) { struct device_node *np = pdev->dev.of_node; host->quirks |= SDHCI_QUIRK_MISSING_CAPS; /* * According to erratum 'FE-2946959' both SDR50 and DDR50 * modes require specific clock adjustments in SDIO3 * Configuration register, if the adjustment is not done, * remove them from the capabilities. */ host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); /* * According to erratum 'ERR-7878951' Armada 38x SDHCI * controller has different capabilities than the ones shown * in its registers */ host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); if (of_property_read_bool(np, "no-1-8-v")) { host->caps &= ~SDHCI_CAN_VDD_180; host->mmc->caps &= ~MMC_CAP_1_8V_DDR; } else { host->caps &= ~SDHCI_CAN_VDD_330; } host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING); return 0; }
static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host) { unsigned int val; unsigned long timeout; /* This timeout should be sufficent for core to reset */ timeout = jiffies + msecs_to_jiffies(100); /* 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); while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) { if (time_is_before_jiffies(timeout)) { pr_err("Error: sd host is stuck in reset!!!\n"); return -EFAULT; } } /* 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) * Back-to-Back writes to same register needs delay when SD bus clock * is very low w.r.t AHB clock, mainly during boot-time and during card * insert-removal. */ usleep_range(1000, 5000); sdhci_writel(host, val, KONA_SDHOST_CORECTRL); return 0; }
static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, u32 start_addr) { u32 ctrl, stat, rdy, mask, timeout, block = 0; if (host->sdhci_caps & SDHCI_CAN_DO_SDMA) { ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; ctrl |= SDHCI_CTRL_SDMA; sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL); } 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) { vmm_printf("%s: Error detected in status(0x%X)!\n", __func__, stat); return VMM_EFAIL; } 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; } } if (host->sdhci_caps & SDHCI_CAN_DO_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); } } if (timeout-- > 0) { vmm_udelay(10); } else { vmm_printf("%s: Transfer data timeout\n", __func__); return VMM_ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); return VMM_OK; }
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 = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; u32 misc_ctrl, clk_ctrl, pad_ctrl; sdhci_reset(host, mask); if (!(mask & SDHCI_RESET_ALL)) return; tegra_sdhci_set_tap(host, tegra_host->default_tap); misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | SDHCI_MISC_CTRL_ENABLE_SDR50 | SDHCI_MISC_CTRL_ENABLE_DDR50 | SDHCI_MISC_CTRL_ENABLE_SDR104); clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); if (tegra_sdhci_is_pad_and_regulator_valid(host)) { /* 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; /* Advertise UHS modes as supported by host */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; } clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); tegra_host->pad_calib_required = true; } tegra_host->ddr_signaling = false; }
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 init_kona_mmc_core(struct sdhci_host *host) { unsigned int mask; unsigned int timeout; if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) { printf("%s: sd host controller reset error\n", __func__); return -EBUSY; } /* For kona a hardware reset before anything else. */ mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET; sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); /* Wait max 100 ms */ timeout = 1000; do { if (timeout == 0) { printf("%s: reset timeout error\n", __func__); return -ETIMEDOUT; } timeout--; udelay(100); } while (0 == (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) & SDHCI_CORECTRL_RESET)); /* Clear the reset bit. */ mask = mask & ~SDHCI_CORECTRL_RESET; sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); /* Enable AHB clock */ mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET); sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET); /* Enable interrupts */ sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET); /* Make sure Card is detected in controller */ mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET); sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET); /* Wait max 100 ms */ timeout = 1000; while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { if (timeout == 0) { printf("%s: CARD DETECT timeout error\n", __func__); return -ETIMEDOUT; } timeout--; udelay(100); } return 0; }
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 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); } }
int sdhci_complete_adma(struct sdhci_ctrlr *sdhci_ctrlr, struct mmc_command *cmd) { int retry; u32 stat = 0, mask; mask = SDHCI_INT_RESPONSE | SDHCI_INT_ERROR; retry = 10000; /* Command should be done in way less than 10 ms. */ while (--retry) { stat = sdhci_readl(sdhci_ctrlr, SDHCI_INT_STATUS); if (stat & mask) break; udelay(1); } sdhci_writel(sdhci_ctrlr, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS); if (retry && !(stat & SDHCI_INT_ERROR)) { /* Command OK, let's wait for data transfer completion. */ mask = SDHCI_INT_DATA_END | SDHCI_INT_ERROR | SDHCI_INT_ADMA_ERROR; /* Transfer should take 10 seconds tops. */ retry = 10 * 1000 * 1000; while (--retry) { stat = sdhci_readl(sdhci_ctrlr, SDHCI_INT_STATUS); if (stat & mask) break; udelay(1); } sdhci_writel(sdhci_ctrlr, stat, SDHCI_INT_STATUS); if (retry && !(stat & SDHCI_INT_ERROR)) { sdhci_cmd_done(sdhci_ctrlr, cmd); return 0; } } sdhc_error("%s: transfer error, stat %#x, adma error %#x, retry %d\n", __func__, stat, sdhci_readl(sdhci_ctrlr, SDHCI_ADMA_ERROR), retry); sdhci_reset(sdhci_ctrlr, SDHCI_RESET_CMD); sdhci_reset(sdhci_ctrlr, SDHCI_RESET_DATA); if (stat & SDHCI_INT_TIMEOUT) return CARD_TIMEOUT; return CARD_COMM_ERR; }
static void xenon_mmc_disable_tuning(struct sdhci_host *host, u8 slot) { u32 var; /* Clear the Re-Tuning Request functionality */ var = sdhci_readl(host, SDHC_SLOT_RETUNING_REQ_CTRL); var &= ~RETUNING_COMPATIBLE; sdhci_writel(host, var, SDHC_SLOT_RETUNING_REQ_CTRL); /* Clear the Re-tuning Event Signal Enable */ var = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); var &= ~SDHCI_RETUNE_EVT_INTSIG; sdhci_writel(host, var, SDHCI_SIGNAL_ENABLE); }
static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) { u32 ier; ier = sdhci_readl(host, SDHCI_INT_ENABLE); ier &= ~clear; ier |= set; sdhci_writel(host, ier, SDHCI_INT_ENABLE); ier = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); ier &= ~clear; ier |= set; sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); }
static int bxt_get_cd(struct mmc_host *mmc) { int gpio_cd = mmc_gpio_get_cd(mmc); struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; int ret = 0; if (!gpio_cd) return 0; pm_runtime_get_sync(mmc->parent); spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) goto out; ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); out: spin_unlock_irqrestore(&host->lock, flags); pm_runtime_mark_last_busy(mmc->parent); pm_runtime_put_autosuspend(mmc->parent); return ret; }
static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd) { int i; if (cmd->resp_type & MMC_RSP_136) { /* CRC is stripped so we need to do some shifting. */ for (i = 0; i < 4; i++) { cmd->response[i] = sdhci_readl(host, SDHCI_RESPONSE + (3-i)*4) << 8; if (i != 3) cmd->response[i] |= sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } } else { cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE); } }
int sdhci_query_command_backstage(struct mmc *mmc, struct mmc_data *data) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; unsigned int start_addr = 0; int ret = 0; unsigned int stat = 0; start_addr = (unsigned int)data->src; if (NULL != data) ret = sdhci_transfer_data(host, data, start_addr); stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) return 0; if (stat & SDHCI_INT_TIMEOUT) { //sdio_dump(host->ioaddr); sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); return TIMEOUT; } else { //sdio_dump(host->ioaddr); sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); return COMM_ERR; } }
static int sdhci_s3c_resume(struct platform_device *dev) { struct sdhci_host *host = platform_get_drvdata(dev); #if defined(CONFIG_WIMAX_CMC)/* && defined(CONFIG_TARGET_LOCALE_NA)*/ struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; u32 ier; #endif #ifdef CONFIG_MACH_MIDAS_01_BD /* turn vdd_tflash off if a card exists*/ if (sdhci_s3c_get_card_exist(host)) sdhci_s3c_vtf_on_off(1); else sdhci_s3c_vtf_on_off(0); #endif sdhci_resume_host(host); #if defined(CONFIG_WIMAX_CMC)/* && defined(CONFIG_TARGET_LOCALE_NA)*/ if (pdata->enable_intr_on_resume) { ier = sdhci_readl(host, SDHCI_INT_ENABLE); ier |= SDHCI_INT_CARD_INT; sdhci_writel(host, ier, SDHCI_INT_ENABLE); sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); } #endif return 0; }
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); }
/* * Software emulation of the SD card insertion/removal. Set insert=1 for insert * and insert=0 for removal. The card detection is done by GPIO. For Broadcom * IP to function properly the bit 0 of CORESTAT register needs to be set/reset * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. */ static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) { struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); u32 val; /* * Back-to-Back register write needs a delay of min 10uS. * Back-to-Back writes to same register needs delay when SD bus clock * is very low w.r.t AHB clock, mainly during boot-time and during card * insert-removal. * We keep 20uS */ mutex_lock(&kona_dev->write_lock); udelay(20); val = sdhci_readl(host, KONA_SDHOST_CORESTAT); if (insert) { int ret; ret = mmc_gpio_get_ro(host->mmc); if (ret >= 0) val = (val & ~KONA_SDHOST_WP) | ((ret) ? KONA_SDHOST_WP : 0); val |= KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); } else { val &= ~KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); } mutex_unlock(&kona_dev->write_lock); return 0; }
int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) { unsigned int caps; host->cfg.name = host->name; host->cfg.ops = &sdhci_ops; caps = sdhci_readl(host, SDHCI_CAPABILITIES); #ifdef CONFIG_MMC_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { printf("%s: Your controller doesn't support SDMA!!\n", __func__); return -1; } #endif if (max_clk) host->cfg.f_max = max_clk; else { if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; else host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; host->cfg.f_max *= 1000000; }
static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; bool card_clk_enabled = false; u32 reg; /* * Touching the tap values is a bit tricky on some SoC generations. * The quirk enables a workaround for a glitch that sometimes occurs if * the tap values are changed. */ if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && card_clk_enabled) { udelay(1); sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); tegra_sdhci_configure_card_clk(host, card_clk_enabled); } }
static int armada_38x_quirks(struct platform_device *pdev, struct sdhci_host *host) { struct device_node *np = pdev->dev.of_node; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); struct resource *res; host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "conf-sdio3"); if (res) { pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pxa->sdio3_conf_reg)) return PTR_ERR(pxa->sdio3_conf_reg); } else { /* * According to erratum 'FE-2946959' both SDR50 and DDR50 * modes require specific clock adjustments in SDIO3 * Configuration register, if the adjustment is not done, * remove them from the capabilities. */ host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); } /* * According to erratum 'ERR-7878951' Armada 38x SDHCI * controller has different capabilities than the ones shown * in its registers */ if (of_property_read_bool(np, "no-1-8-v")) { host->caps &= ~SDHCI_CAN_VDD_180; host->mmc->caps &= ~MMC_CAP_1_8V_DDR; } else { host->caps &= ~SDHCI_CAN_VDD_330; } host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING); 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; #ifdef CONFIG_MMC_SDMA unsigned char ctrl; ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; ctrl |= SDHCI_CTRL_SDMA; sdhci_writel(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) { printf("Error detected in status(0x%X)!\n", 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 { printf("Transfer data timeout\n"); 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; }
/* Enable Parallel Transfer Mode */ static void xenon_mmc_enable_parallel_tran(struct sdhci_host *host, u8 slot) { u32 var; var = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); var |= SLOT_MASK(slot); sdhci_writel(host, var, SDHC_SYS_EXT_OP_CTRL); }
/* Enable specific slot */ static void xenon_mmc_enable_slot(struct sdhci_host *host, u8 slot) { u32 var; var = sdhci_readl(host, SDHC_SYS_OP_CTRL); var |= SLOT_MASK(slot) << SLOT_ENABLE_SHIFT; sdhci_writel(host, var, SDHC_SYS_OP_CTRL); }
/* Mask command conflict error */ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) { u32 reg; reg = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); reg |= MASK_CMD_CONFLICT_ERROR; sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); }