static int tegra_mmc_set_ios(struct udevice *dev) { struct tegra_mmc_priv *priv = dev_get_priv(dev); struct mmc *mmc = mmc_get_mmc_dev(dev); unsigned char ctrl; debug(" mmc_set_ios called\n"); debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); /* Change clock first */ tegra_mmc_change_clock(priv, mmc->clock); ctrl = readb(&priv->reg->hostctl); /* * WIDE8[5] * 0 = Depend on WIDE4 * 1 = 8-bit mode * WIDE4[1] * 1 = 4-bit mode * 0 = 1-bit mode */ if (mmc->bus_width == 8) ctrl |= (1 << 5); else if (mmc->bus_width == 4) ctrl |= (1 << 1); else ctrl &= ~(1 << 1 | 1 << 5); writeb(ctrl, &priv->reg->hostctl); debug("mmc_set_ios: hostctl = %08X\n", ctrl); return 0; }
static int ftsdc010_get_cd(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; return !(readl(®s->status) & FTSDC010_STATUS_CARD_DETECT); }
static int meson_dm_mmc_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); uint32_t meson_mmc_cfg; meson_mmc_config_clock(mmc); meson_mmc_cfg = meson_read(mmc, MESON_SD_EMMC_CFG); meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK; if (mmc->bus_width == 1) meson_mmc_cfg |= CFG_BUS_WIDTH_1; else if (mmc->bus_width == 4) meson_mmc_cfg |= CFG_BUS_WIDTH_4; else if (mmc->bus_width == 8) meson_mmc_cfg |= CFG_BUS_WIDTH_8; else return -EINVAL; /* 512 bytes block length */ meson_mmc_cfg &= ~CFG_BL_LEN_MASK; meson_mmc_cfg |= CFG_BL_LEN_512; /* Response timeout 256 clk */ meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK; meson_mmc_cfg |= CFG_RESP_TIMEOUT_256; /* Command-command gap 16 clk */ meson_mmc_cfg &= ~CFG_RC_CC_MASK; meson_mmc_cfg |= CFG_RC_CC_16; meson_write(mmc, meson_mmc_cfg, MESON_SD_EMMC_CFG); return 0; }
void print_mmc_devices(char separator) { struct udevice *dev; char *mmc_type; bool first = true; for (uclass_first_device(UCLASS_MMC, &dev); dev; uclass_next_device(&dev), first = false) { struct mmc *m = mmc_get_mmc_dev(dev); if (!first) { printf("%c", separator); if (separator != '\n') puts(" "); } if (m->has_init) mmc_type = IS_SD(m) ? "SD" : "eMMC"; else mmc_type = NULL; printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); if (mmc_type) printf(" (%s)", mmc_type); } printf("\n"); }
static int ftsdc010_get_wp(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { printf("ftsdc010: write protected\n"); chip->wprot = 1; } return 0; }
static int mmc_select_hwpart(struct udevice *bdev, int hwpart) { struct udevice *mmc_dev = dev_get_parent(bdev); struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); struct blk_desc *desc = dev_get_uclass_platdata(bdev); if (desc->hwpart == hwpart) return 0; if (mmc->part_config == MMCPART_NOAVAILABLE) return -EMEDIUMTYPE; return mmc_switch_part(mmc, hwpart); }
int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct dm_mmc_ops *ops = mmc_get_ops(dev); int ret; mmmc_trace_before_send(mmc, cmd); if (ops->send_cmd) ret = ops->send_cmd(dev, cmd, data); else ret = -ENOSYS; mmmc_trace_after_send(mmc, cmd, ret); return ret; }
static int uniphier_sd_set_ios(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); struct mmc *mmc = mmc_get_mmc_dev(dev); int ret; dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n", mmc->clock, mmc->ddr_mode, mmc->bus_width); ret = uniphier_sd_set_bus_width(priv, mmc); if (ret) return ret; uniphier_sd_set_ddr_mode(priv, mmc); uniphier_sd_set_clk_rate(priv, mmc); 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; }
struct mmc *find_mmc_device(int dev_num) { struct udevice *dev, *mmc_dev; int ret; ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev); if (ret) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) printf("MMC Device %d not found\n", dev_num); #endif return NULL; } mmc_dev = dev_get_parent(dev); return mmc_get_mmc_dev(mmc_dev); }
static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct meson_mmc_platdata *pdata = mmc->priv; uint32_t status; ulong start; int ret = 0; /* max block size supported by chip is 512 byte */ if (data && data->blocksize > 512) return -EINVAL; meson_mmc_setup_cmd(mmc, data, cmd); meson_mmc_setup_addr(mmc, data); meson_write(mmc, cmd->cmdarg, MESON_SD_EMMC_CMD_ARG); /* use 10s timeout */ start = get_timer(0); do { status = meson_read(mmc, MESON_SD_EMMC_STATUS); } while(!(status & STATUS_END_OF_CHAIN) && get_timer(start) < 10000); if (!(status & STATUS_END_OF_CHAIN)) ret = -ETIMEDOUT; else if (status & STATUS_RESP_TIMEOUT) ret = -ETIMEDOUT; else if (status & STATUS_ERR_MASK) ret = -EIO; meson_mmc_read_response(mmc, cmd); if (data && data->flags == MMC_DATA_WRITE) free(pdata->w_buf); /* reset status bits */ meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); return ret; }
void mmc_do_preinit(void) { struct udevice *dev; struct uclass *uc; int ret; ret = uclass_get(UCLASS_MMC, &uc); if (ret) return; uclass_foreach_dev(dev, uc) { struct mmc *m = mmc_get_mmc_dev(dev); if (!m) continue; #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT mmc_set_preinit(m, 1); #endif if (m->preinit) mmc_start_init(m); } }
static int stm32_sdmmc2_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); struct mmc_config *cfg = &plat->cfg; u32 desired = mmc->clock; u32 sys_clock = clk_get_rate(&priv->clk); u32 clk = 0; debug("%s: bus_with = %d, clock = %d\n", __func__, mmc->bus_width, mmc->clock); if ((mmc->bus_width == 1) && (desired == cfg->f_min)) stm32_sdmmc2_pwron(priv); /* * clk_div = 0 => command and data generated on SDMMCCLK falling edge * clk_div > 0 and NEGEDGE = 0 => command and data generated on * SDMMCCLK rising edge * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */ if (desired && ((sys_clock > desired) || IS_RISING_EDGE(priv->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; } if (mmc->bus_width == 4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mmc->bus_width == 8) clk |= SDMMC_CLKCR_WIDBUS_8; writel(clk | priv->clk_reg_msk | SDMMC_CLKCR_HWFC_EN, priv->base + SDMMC_CLKCR); return 0; }
static int ftsdc010_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; ftsdc010_clkset(mmc, mmc->clock); clrbits_le32(®s->bwr, FTSDC010_BWR_MODE_MASK); switch (mmc->bus_width) { case 4: setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT); break; case 8: setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT); break; default: setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT); break; } 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; }
int sdhci_probe(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); return sdhci_init(mmc); }
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 tegra_mmc_init(struct udevice *dev) { struct tegra_mmc_priv *priv = dev_get_priv(dev); struct mmc *mmc = mmc_get_mmc_dev(dev); unsigned int mask; debug(" tegra_mmc_init called\n"); tegra_mmc_reset(priv, mmc); #if defined(CONFIG_TEGRA124_MMC_DISABLE_EXT_LOOPBACK) /* * Disable the external clock loopback and use the internal one on * SDMMC3 as per the SDMMC_VENDOR_MISC_CNTRL_0 register's SDMMC_SPARE1 * bits being set to 0xfffd according to the TRM. * * TODO([email protected]): Move to device tree controlled * approach once proper kernel integration made it mainline. */ if (priv->reg == (void *)0x700b0400) { mask = readl(&priv->reg->venmiscctl); mask &= ~TEGRA_MMC_MISCON_ENABLE_EXT_LOOPBACK; writel(mask, &priv->reg->venmiscctl); } #endif priv->version = readw(&priv->reg->hcver); debug("host version = %x\n", priv->version); /* mask all */ writel(0xffffffff, &priv->reg->norintstsen); writel(0xffffffff, &priv->reg->norintsigen); writeb(0xe, &priv->reg->timeoutcon); /* TMCLK * 2^27 */ /* * NORMAL Interrupt Status Enable Register init * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable * [3] ENSTADMAINT : DMA boundary interrupt * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable * [0] ENSTACMDCMPLT : Command Complete Status Enable */ mask = readl(&priv->reg->norintstsen); mask &= ~(0xffff); mask |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT | TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY | TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY); writel(mask, &priv->reg->norintstsen); /* * NORMAL Interrupt Signal Enable Register init * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable */ mask = readl(&priv->reg->norintsigen); mask &= ~(0xffff); mask |= TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE; writel(mask, &priv->reg->norintsigen); return 0; }
/* * u-boot mmc api */ static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); int ret = -EOPNOTSUPP; uint32_t len = 0; struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) { printf("ftsdc010: the card is write protected!\n"); return ret; } if (data) { uint32_t dcr; len = data->blocksize * data->blocks; /* 1. data disable + fifo reset */ dcr = 0; #ifdef CONFIG_FTSDC010_SDIO dcr |= FTSDC010_DCR_FIFO_RST; #endif writel(dcr, ®s->dcr); /* 2. clear status register */ writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN | FTSDC010_STATUS_FIFO_ORUN, ®s->clr); /* 3. data timeout (1 sec) */ writel(chip->rate, ®s->dtr); /* 4. data length (bytes) */ writel(len, ®s->dlr); /* 5. data enable */ dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN; if (data->flags & MMC_DATA_WRITE) dcr |= FTSDC010_DCR_DATA_WRITE; writel(dcr, ®s->dcr); } ret = ftsdc010_send_cmd(mmc, cmd); if (ret) { printf("ftsdc010: CMD%d failed\n", cmd->cmdidx); return ret; } if (!data) return ret; if (data->flags & MMC_DATA_WRITE) { const uint8_t *buf = (const uint8_t *)data->src; while (len > 0) { int wlen; /* wait for tx ready */ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN); if (ret) break; /* write bytes to ftsdc010 */ for (wlen = 0; wlen < len && wlen < chip->fifo; ) { writel(*(uint32_t *)buf, ®s->dwr); buf += 4; wlen += 4; } len -= wlen; } } else { uint8_t *buf = (uint8_t *)data->dest; while (len > 0) { int rlen; /* wait for rx ready */ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN); if (ret) break; /* fetch bytes from ftsdc010 */ for (rlen = 0; rlen < len && rlen < chip->fifo; ) { *(uint32_t *)buf = readl(®s->dwr); buf += 4; rlen += 4; } len -= rlen; } } if (!ret) { ret = ftsdc010_wait(regs, FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_CRC_OK); } return ret; }
static int ftsdc010_probe(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); return ftsdc010_init(mmc); }