X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=drivers%2Fmmc%2Fsdhci.c;h=d89e3028417b0942cabffec34f58ea8c3e283917;hb=3a926a304b9f7a74dbe67ae7dc4cb6c7a174c6c0;hp=46ae9cb52d9cfb45781080c04b9ec84a27d6f7e3;hpb=c0bb110b695130866838518e680bdd5473e47928;p=karo-tx-uboot.git diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 46ae9cb52d..d89e302841 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -13,7 +13,11 @@ #include #include +#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) +void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; +#else void *aligned_buffer; +#endif static void sdhci_reset(struct sdhci_host *host, u8 mask) { @@ -24,7 +28,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printf("Reset 0x%x never completed.\n", (int)mask); + printf("%s: Reset 0x%x never completed.\n", + __func__, (int)mask); return; } timeout--; @@ -79,7 +84,8 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { - printf("Error detected in status(0x%X)!\n", stat); + printf("%s: Error detected in status(0x%X)!\n", + __func__, stat); return -1; } if (stat & rdy) { @@ -102,7 +108,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, if (timeout-- > 0) udelay(10); else { - printf("Transfer data timeout\n"); + printf("%s: Transfer data timeout\n", __func__); return -1; } } while (!(stat & SDHCI_INT_DATA_END)); @@ -122,17 +128,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, #endif #define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 -int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, +static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { - struct sdhci_host *host = (struct sdhci_host *)mmc->priv; + 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; - unsigned int retry = 10000; int mmc_dev = mmc->block_dev.dev; + unsigned start = get_timer(0); /* Timeout unit - ms */ static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT; @@ -147,7 +153,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { - printf("MMC: %d busy ", mmc_dev); + printf("%s: MMC: %d busy ", __func__, mmc_dev); if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", @@ -179,7 +185,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (data) flags |= SDHCI_CMD_DATA; - /*Set Transfer mode regarding to data flag*/ + /* Set Transfer mode regarding to data flag */ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; @@ -192,17 +198,28 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, #ifdef CONFIG_MMC_SDMA if (data->flags == MMC_DATA_READ) - start_addr = (unsigned int)data->dest; + start_addr = (unsigned long)data->dest; else - start_addr = (unsigned int)data->src; + start_addr = (unsigned long)data->src; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (start_addr & 0x7) != 0x0) { is_aligned = 0; - start_addr = (unsigned int)aligned_buffer; + 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 @@ -211,6 +228,8 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, 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); @@ -218,19 +237,19 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, 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 (--retry == 0) - break; - } while ((stat & mask) != mask); + } while (((stat & mask) != mask) && + (get_timer(start) < CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT)); - if (retry == 0) { + if (get_timer(start) >= CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT) { if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) return 0; else { - printf("Timeout for status update!\n"); + printf("%s: Timeout for status update!\n", __func__); return TIMEOUT; } } @@ -266,7 +285,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { - struct sdhci_host *host = (struct sdhci_host *)mmc->priv; + struct sdhci_host *host = mmc->priv; unsigned int div, clk, timeout; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); @@ -276,18 +295,18 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { /* Version 3.00 divisors must be a multiple of 2. */ - if (mmc->f_max <= clock) + if (mmc->cfg->f_max <= clock) div = 1; else { for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { - if ((mmc->f_max / div) <= clock) + if ((mmc->cfg->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) + if ((mmc->cfg->f_max / div) <= clock) break; } } @@ -307,7 +326,8 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printf("Internal clock never stabilised.\n"); + printf("%s: Internal clock never stabilised.\n", + __func__); return -1; } timeout--; @@ -352,10 +372,10 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } -void sdhci_set_ios(struct mmc *mmc) +static void sdhci_set_ios(struct mmc *mmc) { u32 ctrl; - struct sdhci_host *host = (struct sdhci_host *)mmc->priv; + struct sdhci_host *host = mmc->priv; if (host->set_control_reg) host->set_control_reg(host); @@ -371,7 +391,8 @@ void sdhci_set_ios(struct mmc *mmc) (host->quirks & SDHCI_QUIRK_USE_WIDE8)) ctrl |= SDHCI_CTRL_8BITBUS; } else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) + 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; @@ -390,24 +411,25 @@ void sdhci_set_ios(struct mmc *mmc) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -int sdhci_init(struct mmc *mmc) +static int sdhci_init(struct mmc *mmc) { - struct sdhci_host *host = (struct sdhci_host *)mmc->priv; + struct sdhci_host *host = mmc->priv; if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { - printf("Aligned buffer alloc failed!!!"); + printf("%s: Aligned buffer alloc failed!!!\n", + __func__); return -1; } } - sdhci_set_power(host, fls(mmc->voltages) - 1); + sdhci_set_power(host, fls(mmc->cfg->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_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL); status = sdhci_readl(host, SDHCI_PRESENT_STATE); @@ -418,88 +440,92 @@ int sdhci_init(struct mmc *mmc) } /* Enable only interrupts served by the SD controller */ - sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK - , SDHCI_INT_ENABLE); + 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 const struct mmc_ops sdhci_ops = { + .send_cmd = sdhci_send_command, + .set_ios = sdhci_set_ios, + .init = sdhci_init, +}; + int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) { - struct mmc *mmc; unsigned int caps; - mmc = malloc(sizeof(struct mmc)); - if (!mmc) { - printf("mmc malloc fail!\n"); - return -1; - } - - mmc->priv = host; - host->mmc = mmc; - - sprintf(mmc->name, "%s", host->name); - mmc->send_cmd = sdhci_send_command; - mmc->set_ios = sdhci_set_ios; - mmc->init = sdhci_init; - mmc->getcd = NULL; - mmc->getwp = NULL; + 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("Your controller don't support sdma!!\n"); + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); return -1; } #endif if (max_clk) - mmc->f_max = max_clk; + host->cfg.f_max = max_clk; else { if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) + host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; else - mmc->f_max = (caps & SDHCI_CLOCK_BASE_MASK) + host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; - mmc->f_max *= 1000000; + host->cfg.f_max *= 1000000; } - if (mmc->f_max == 0) { - printf("Hardware doesn't specify base clock frequency\n"); + if (host->cfg.f_max == 0) { + printf("%s: Hardware doesn't specify base clock frequency\n", + __func__); return -1; } if (min_clk) - mmc->f_min = min_clk; + host->cfg.f_min = min_clk; else { if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300; + host->cfg.f_min = host->cfg.f_max / + SDHCI_MAX_DIV_SPEC_300; else - mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200; + host->cfg.f_min = host->cfg.f_max / + SDHCI_MAX_DIV_SPEC_200; } - mmc->voltages = 0; + host->cfg.voltages = 0; if (caps & SDHCI_CAN_VDD_330) - mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; + host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; if (caps & SDHCI_CAN_VDD_300) - mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; + host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; if (caps & SDHCI_CAN_VDD_180) - mmc->voltages |= MMC_VDD_165_195; + host->cfg.voltages |= MMC_VDD_165_195; if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) - mmc->voltages |= host->voltages; + host->cfg.voltages |= host->voltages; - mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; + host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { if (caps & SDHCI_CAN_DO_8BIT) - mmc->host_caps |= MMC_MODE_8BIT; + host->cfg.host_caps |= MMC_MODE_8BIT; } if (host->host_caps) - mmc->host_caps |= host->host_caps; + host->cfg.host_caps |= host->host_caps; + + host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; sdhci_reset(host, SDHCI_RESET_ALL); - mmc_register(mmc); + + host->mmc = mmc_create(&host->cfg, host); + if (host->mmc == NULL) { + printf("%s: mmc create fail!\n", __func__); + return -1; + } return 0; }