diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 924 |
1 files changed, 562 insertions, 362 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6bf58d27b6fc..efe4c8ae9d61 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -14,6 +14,7 @@ */ #include <linux/delay.h> +#include <linux/ktime.h> #include <linux/highmem.h> #include <linux/io.h> #include <linux/module.h> @@ -22,6 +23,7 @@ #include <linux/scatterlist.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include <linux/leds.h> @@ -36,7 +38,10 @@ #define DRIVER_NAME "sdhci" #define DBG(f, x...) \ - pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) + pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) + +#define SDHCI_DUMP(f, x...) \ + pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) #define MAX_TUNING_LOOP 40 @@ -47,61 +52,68 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static void sdhci_dumpregs(struct sdhci_host *host) -{ - pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", - mmc_hostname(host->mmc)); - - pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", - sdhci_readl(host, SDHCI_DMA_ADDRESS), - sdhci_readw(host, SDHCI_HOST_VERSION)); - pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", - sdhci_readw(host, SDHCI_BLOCK_SIZE), - sdhci_readw(host, SDHCI_BLOCK_COUNT)); - pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", - sdhci_readl(host, SDHCI_ARGUMENT), - sdhci_readw(host, SDHCI_TRANSFER_MODE)); - pr_err(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", - sdhci_readl(host, SDHCI_PRESENT_STATE), - sdhci_readb(host, SDHCI_HOST_CONTROL)); - pr_err(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", - sdhci_readb(host, SDHCI_POWER_CONTROL), - sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - pr_err(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", - sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), - sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - pr_err(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", - sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), - sdhci_readl(host, SDHCI_INT_STATUS)); - pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", - sdhci_readl(host, SDHCI_INT_ENABLE), - sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", - sdhci_readw(host, SDHCI_ACMD12_ERR), - sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - pr_err(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", - sdhci_readl(host, SDHCI_CAPABILITIES), - sdhci_readl(host, SDHCI_CAPABILITIES_1)); - pr_err(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", - sdhci_readw(host, SDHCI_COMMAND), - sdhci_readl(host, SDHCI_MAX_CURRENT)); - pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n", - sdhci_readw(host, SDHCI_HOST_CONTROL2)); +void sdhci_dumpregs(struct sdhci_host *host) +{ + SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n"); + + SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n", + sdhci_readl(host, SDHCI_DMA_ADDRESS), + sdhci_readw(host, SDHCI_HOST_VERSION)); + SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n", + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); + SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n", + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); + SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n", + sdhci_readl(host, SDHCI_PRESENT_STATE), + sdhci_readb(host, SDHCI_HOST_CONTROL)); + SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n", + sdhci_readb(host, SDHCI_POWER_CONTROL), + sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); + SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n", + sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), + sdhci_readw(host, SDHCI_CLOCK_CONTROL)); + SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n", + sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), + sdhci_readl(host, SDHCI_INT_STATUS)); + SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n", + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + SDHCI_DUMP("AC12 err: 0x%08x | Slot int: 0x%08x\n", + sdhci_readw(host, SDHCI_ACMD12_ERR), + sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); + SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n", + sdhci_readl(host, SDHCI_CAPABILITIES), + sdhci_readl(host, SDHCI_CAPABILITIES_1)); + SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n", + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_MAX_CURRENT)); + SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n", + sdhci_readl(host, SDHCI_RESPONSE), + sdhci_readl(host, SDHCI_RESPONSE + 4)); + SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n", + sdhci_readl(host, SDHCI_RESPONSE + 8), + sdhci_readl(host, SDHCI_RESPONSE + 12)); + SDHCI_DUMP("Host ctl2: 0x%08x\n", + sdhci_readw(host, SDHCI_HOST_CONTROL2)); if (host->flags & SDHCI_USE_ADMA) { - if (host->flags & SDHCI_USE_64_BIT_DMA) - pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); - else - pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + if (host->flags & SDHCI_USE_64_BIT_DMA) { + SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", + sdhci_readl(host, SDHCI_ADMA_ERROR), + sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI), + sdhci_readl(host, SDHCI_ADMA_ADDRESS)); + } else { + SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + sdhci_readl(host, SDHCI_ADMA_ERROR), + sdhci_readl(host, SDHCI_ADMA_ADDRESS)); + } } - pr_err(DRIVER_NAME ": ===========================================\n"); + SDHCI_DUMP("============================================\n"); } +EXPORT_SYMBOL_GPL(sdhci_dumpregs); /*****************************************************************************\ * * @@ -117,9 +129,10 @@ static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { u32 present; + int gpio_cd = mmc_gpio_get_cd(host->mmc); if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - !mmc_card_is_removable(host->mmc)) + !mmc_card_is_removable(host->mmc) || (gpio_cd >= 0)) return; if (enable) { @@ -164,7 +177,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) void sdhci_reset(struct sdhci_host *host, u8 mask) { - unsigned long timeout; + ktime_t timeout; sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); @@ -176,18 +189,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) } /* Wait max 100 ms */ - timeout = 100; + timeout = ktime_add_ms(ktime_get(), 100); /* hw clears the bit when it's done */ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { - if (timeout == 0) { + if (ktime_after(ktime_get(), timeout)) { pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); sdhci_dumpregs(host); return; } - timeout--; - mdelay(1); + udelay(10); } } EXPORT_SYMBOL_GPL(sdhci_reset); @@ -214,15 +226,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask) } } -static void sdhci_init(struct sdhci_host *host, int soft) +static void sdhci_set_default_irqs(struct sdhci_host *host) { - struct mmc_host *mmc = host->mmc; - - if (soft) - sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); - else - sdhci_do_reset(host, SDHCI_RESET_ALL); - host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | @@ -235,6 +240,20 @@ static void sdhci_init(struct sdhci_host *host, int soft) sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + +static void sdhci_init(struct sdhci_host *host, int soft) +{ + struct mmc_host *mmc = host->mmc; + + if (soft) + sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + else + sdhci_do_reset(host, SDHCI_RESET_ALL); + + sdhci_set_default_irqs(host); + + host->cqe_on = false; if (soft) { /* force clock reconfiguration */ @@ -484,8 +503,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, return data->sg_count; sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); + mmc_get_dma_dir(data)); if (sg_count == 0) return -ENOSPC; @@ -658,7 +676,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) { u8 count; - struct mmc_data *data = cmd->data; + struct mmc_data *data; unsigned target_timeout, current_timeout; /* @@ -670,6 +688,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; + /* Unspecified command, assume max */ + if (cmd == NULL) + return 0xE; + + data = cmd->data; + /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; @@ -714,8 +738,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - DBG("%s: Too large timeout 0x%x requested for CMD%d!\n", - mmc_hostname(host->mmc), count, cmd->opcode); + DBG("Too large timeout 0x%x requested for CMD%d!\n", + count, cmd->opcode); count = 0xE; } @@ -1343,42 +1367,47 @@ clock_set: } EXPORT_SYMBOL_GPL(sdhci_calc_clk); -void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +void sdhci_enable_clk(struct sdhci_host *host, u16 clk) { - u16 clk; - unsigned long timeout; - - host->mmc->actual_clock = 0; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - return; - - clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + ktime_t timeout; clk |= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); /* Wait max 20 ms */ - timeout = 20; + timeout = ktime_add_ms(ktime_get(), 20); while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { + if (ktime_after(ktime_get(), timeout)) { pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; } - timeout--; spin_unlock_irq(&host->lock); - usleep_range(900, 1100); + udelay(10); spin_lock_irq(&host->lock); } clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } +EXPORT_SYMBOL_GPL(sdhci_enable_clk); + +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + + host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_enable_clk(host, clk); +} EXPORT_SYMBOL_GPL(sdhci_set_clock); static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode, @@ -1386,9 +1415,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode, { struct mmc_host *mmc = host->mmc; - spin_unlock_irq(&host->lock); mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); - spin_lock_irq(&host->lock); if (mode != MMC_POWER_OFF) sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); @@ -1572,16 +1599,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) } EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; u8 ctrl; - spin_lock_irqsave(&host->lock, flags); + if (ios->power_mode == MMC_POWER_UNDEFINED) + return; if (host->flags & SDHCI_DEVICE_DEAD) { - spin_unlock_irqrestore(&host->lock, flags); if (!IS_ERR(mmc->supply.vmmc) && ios->power_mode == MMC_POWER_OFF) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); @@ -1632,7 +1658,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if ((ios->timing == MMC_TIMING_SD_HS || - ios->timing == MMC_TIMING_MMC_HS) + ios->timing == MMC_TIMING_MMC_HS || + ios->timing == MMC_TIMING_MMC_HS400 || + ios->timing == MMC_TIMING_MMC_HS200 || + ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_UHS_SDR50 || + ios->timing == MMC_TIMING_UHS_SDR104 || + ios->timing == MMC_TIMING_UHS_DDR50 || + ios->timing == MMC_TIMING_UHS_SDR25) && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; else @@ -1641,16 +1674,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->version >= SDHCI_SPEC_300) { u16 clk, ctrl_2; - /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_MMC_HS400) || - (ios->timing == MMC_TIMING_MMC_HS200) || - (ios->timing == MMC_TIMING_MMC_DDR52) || - (ios->timing == MMC_TIMING_UHS_SDR50) || - (ios->timing == MMC_TIMING_UHS_SDR104) || - (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25)) - ctrl |= SDHCI_CTRL_HISPD; - if (!host->preset_enabled) { sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); /* @@ -1730,8 +1753,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); } +EXPORT_SYMBOL_GPL(sdhci_set_ios); static int sdhci_get_cd(struct mmc_host *mmc) { @@ -1825,7 +1848,7 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) } } -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; @@ -1845,9 +1868,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) if (!enable) pm_runtime_put_noidle(host->mmc->parent); } +EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq); -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) +int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); u16 ctrl; @@ -1939,6 +1963,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } } +EXPORT_SYMBOL_GPL(sdhci_start_signal_voltage_switch); static int sdhci_card_busy(struct mmc_host *mmc) { @@ -1963,64 +1988,9 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) return 0; } -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) +static void sdhci_start_tuning(struct sdhci_host *host) { - struct sdhci_host *host = mmc_priv(mmc); u16 ctrl; - int tuning_loop_counter = MAX_TUNING_LOOP; - int err = 0; - unsigned long flags; - unsigned int tuning_count = 0; - bool hs400_tuning; - - spin_lock_irqsave(&host->lock, flags); - - hs400_tuning = host->flags & SDHCI_HS400_TUNING; - host->flags &= ~SDHCI_HS400_TUNING; - - if (host->tuning_mode == SDHCI_TUNING_MODE_1) - tuning_count = host->tuning_count; - - /* - * The Host Controller needs tuning in case of SDR104 and DDR50 - * mode, and for SDR50 mode when Use Tuning for SDR50 is set in - * the Capabilities register. - * If the Host Controller supports the HS200 mode then the - * tuning function has to be executed. - */ - switch (host->timing) { - /* HS400 tuning is done in HS200 mode */ - case MMC_TIMING_MMC_HS400: - err = -EINVAL; - goto out_unlock; - - case MMC_TIMING_MMC_HS200: - /* - * Periodic re-tuning for HS400 is not expected to be needed, so - * disable it here. - */ - if (hs400_tuning) - tuning_count = 0; - break; - - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_UHS_DDR50: - break; - - case MMC_TIMING_UHS_SDR50: - if (host->flags & SDHCI_SDR50_NEEDS_TUNING) - break; - /* FALLTHROUGH */ - - default: - goto out_unlock; - } - - if (host->ops->platform_execute_tuning) { - spin_unlock_irqrestore(&host->lock, flags); - err = host->ops->platform_execute_tuning(host, opcode); - return err; - } ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; @@ -2040,151 +2010,217 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) */ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); +} + +static void sdhci_end_tuning(struct sdhci_host *host) +{ + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + +static void sdhci_reset_tuning(struct sdhci_host *host) +{ + u16 ctrl; + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl &= ~SDHCI_CTRL_TUNED_CLK; + ctrl &= ~SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); +} + +static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode) +{ + sdhci_reset_tuning(host); + + sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); + + sdhci_end_tuning(host); + + mmc_abort_tuning(host->mmc, opcode); +} + +/* + * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI + * tuning command does not have a data payload (or rather the hardware does it + * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command + * interrupt setup is different to other commands and there is no timeout + * interrupt so special handling is needed. + */ +static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) +{ + struct mmc_host *mmc = host->mmc; + struct mmc_command cmd = {}; + struct mmc_request mrq = {}; + unsigned long flags; + u8 ctrl; + + spin_lock_irqsave(&host->lock, flags); + + cmd.opcode = opcode; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.mrq = &mrq; + + mrq.cmd = &cmd; /* - * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches 40 times. + * In response to CMD19, the card sends 64 bytes of tuning + * block to the Host Controller. So we set the block size + * to 64 here. */ - do { - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - cmd.retries = 0; - cmd.data = NULL; - cmd.mrq = &mrq; - cmd.error = 0; - - if (tuning_loop_counter-- == 0) - break; - - mrq.cmd = &cmd; + if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200 && + mmc->ios.bus_width == MMC_BUS_WIDTH_8) + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE); + else + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); - /* - * In response to CMD19, the card sends 64 bytes of tuning - * block to the Host Controller. So we set the block size - * to 64 here. - */ - if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), - SDHCI_BLOCK_SIZE); - else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } else { - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } + /* + * The tuning block is sent by the card to the host controller. + * So we set the TRNS_READ bit in the Transfer Mode register. + * This also takes care of setting DMA Enable and Multi Block + * Select in the same register to 0. + */ + sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); - /* - * The tuning block is sent by the card to the host controller. - * So we set the TRNS_READ bit in the Transfer Mode register. - * This also takes care of setting DMA Enable and Multi Block - * Select in the same register to 0. - */ - sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); + /* + * DMA already disabled, so clear the DMA Select here. + * Otherwise, if use ADMA2, even disable DMA, some + * controllers like i.MX usdhc will still prefetch the + * ADMA script when send tuning command, which will cause + * IOMMU report lack of TLB mapping error + */ + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - sdhci_send_command(host, &cmd); + sdhci_send_command(host, &cmd); - host->cmd = NULL; - sdhci_del_timer(host, &mrq); + host->cmd = NULL; - spin_unlock_irqrestore(&host->lock, flags); - /* Wait for Buffer Read Ready interrupt */ - wait_event_timeout(host->buf_ready_int, - (host->tuning_done == 1), - msecs_to_jiffies(50)); - spin_lock_irqsave(&host->lock, flags); + sdhci_del_timer(host, &mrq); - if (!host->tuning_done) { - pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n"); - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl &= ~SDHCI_CTRL_TUNED_CLK; - ctrl &= ~SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + host->tuning_done = 0; - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); - err = -EIO; + /* Wait for Buffer Read Ready interrupt */ + wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1), + msecs_to_jiffies(50)); - if (cmd.opcode != MMC_SEND_TUNING_BLOCK_HS200) - goto out; +} - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int i; - spin_unlock_irqrestore(&host->lock, flags); + /* + * Issue opcode repeatedly till Execute Tuning is set to 0 or the number + * of loops reaches 40 times. + */ + for (i = 0; i < MAX_TUNING_LOOP; i++) { + u16 ctrl; - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = MMC_STOP_TRANSMISSION; - cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - cmd.busy_timeout = 50; - mmc_wait_for_cmd(mmc, &cmd, 0); + sdhci_send_tuning(host, opcode); - spin_lock_irqsave(&host->lock, flags); + if (!host->tuning_done) { + pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_abort_tuning(host, opcode); + return; + } - goto out; + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { + if (ctrl & SDHCI_CTRL_TUNED_CLK) { + /* + * need to wait some time, make sure sd/mmc fininsh + * send out tuning data, otherwise, the sd/mmc can't + * response to any command when the card still out + * put the tuning data. + */ + mdelay(1); + return; /* Success! */ + } + break; } - host->tuning_done = 0; + mdelay(1); + } - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_reset_tuning(host); +} - /* eMMC spec does not require a delay between tuning cycles */ - if (opcode == MMC_SEND_TUNING_BLOCK) - mdelay(1); - } while (ctrl & SDHCI_CTRL_EXEC_TUNING); +int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + int err = 0; + unsigned int tuning_count = 0; + bool hs400_tuning; + + hs400_tuning = host->flags & SDHCI_HS400_TUNING; + + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = host->tuning_count; /* - * The Host Driver has exhausted the maximum number of loops allowed, - * so use fixed sampling frequency. + * The Host Controller needs tuning in case of SDR104 and DDR50 + * mode, and for SDR50 mode when Use Tuning for SDR50 is set in + * the Capabilities register. + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. */ - if (tuning_loop_counter < 0) { - ctrl &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - } - if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n"); - err = -EIO; - } + switch (host->timing) { + /* HS400 tuning is done in HS200 mode */ + case MMC_TIMING_MMC_HS400: + err = -EINVAL; + goto out; -out: - if (tuning_count) { + case MMC_TIMING_MMC_HS200: /* - * In case tuning fails, host controllers which support - * re-tuning can try tuning again at a later time, when the - * re-tuning timer expires. So for these controllers, we - * return 0. Since there might be other controllers who do not - * have this capability, we return error for them. + * Periodic re-tuning for HS400 is not expected to be needed, so + * disable it here. */ - err = 0; + if (hs400_tuning) + tuning_count = 0; + break; + + case MMC_TIMING_UHS_SDR104: + break; + + case MMC_TIMING_UHS_SDR50: + if (host->flags & SDHCI_SDR50_NEEDS_TUNING) + break; + /* FALLTHROUGH */ + + case MMC_TIMING_UHS_DDR50: + if (host->flags & SDHCI_DDR50_NEEDS_TUNING) + break; + /* FALLTHROUGH */ + + default: + goto out; } - host->mmc->retune_period = err ? 0 : tuning_count; + if (host->ops->platform_execute_tuning) { + err = host->ops->platform_execute_tuning(host, opcode); + goto out; + } - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -out_unlock: - spin_unlock_irqrestore(&host->lock, flags); - return err; -} + host->mmc->retune_period = tuning_count; -static int sdhci_select_drive_strength(struct mmc_card *card, - unsigned int max_dtr, int host_drv, - int card_drv, int *drv_type) -{ - struct sdhci_host *host = mmc_priv(card->host); + sdhci_start_tuning(host); - if (!host->ops->select_drive_strength) - return 0; + __sdhci_execute_tuning(host, opcode); - return host->ops->select_drive_strength(host, card, max_dtr, host_drv, - card_drv, drv_type); + sdhci_end_tuning(host); +out: + host->flags &= ~SDHCI_HS400_TUNING; + + return err; } +EXPORT_SYMBOL_GPL(sdhci_execute_tuning); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) { @@ -2223,14 +2259,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, if (data->host_cookie != COOKIE_UNMAPPED) dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); + mmc_get_dma_dir(data)); data->host_cookie = COOKIE_UNMAPPED; } -static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host = mmc_priv(mmc); @@ -2300,7 +2334,6 @@ static const struct mmc_host_ops sdhci_ops = { .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .prepare_hs400_tuning = sdhci_prepare_hs400_tuning, .execute_tuning = sdhci_execute_tuning, - .select_drive_strength = sdhci_select_drive_strength, .card_event = sdhci_card_event, .card_busy = sdhci_card_busy, }; @@ -2342,8 +2375,7 @@ static bool sdhci_request_done(struct sdhci_host *host) if (data && data->host_cookie == COOKIE_MAPPED) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); + mmc_get_dma_dir(data)); data->host_cookie = COOKIE_UNMAPPED; } } @@ -2508,7 +2540,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) #ifdef CONFIG_MMC_DEBUG static void sdhci_adma_show_error(struct sdhci_host *host) { - const char *name = mmc_hostname(host->mmc); void *desc = host->adma_table; sdhci_dumpregs(host); @@ -2517,14 +2548,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host) struct sdhci_adma2_64_desc *dma_desc = desc; if (host->flags & SDHCI_USE_64_BIT_DMA) - DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(dma_desc->addr_hi), + DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n", + desc, le32_to_cpu(dma_desc->addr_hi), le32_to_cpu(dma_desc->addr_lo), le16_to_cpu(dma_desc->len), le16_to_cpu(dma_desc->cmd)); else - DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(dma_desc->addr_lo), + DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", + desc, le32_to_cpu(dma_desc->addr_lo), le16_to_cpu(dma_desc->len), le16_to_cpu(dma_desc->cmd)); @@ -2640,10 +2671,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + SDHCI_DEFAULT_BOUNDARY_SIZE; host->data->bytes_xfered = dmanow - dmastart; - DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes," - " next 0x%08x\n", - mmc_hostname(host->mmc), dmastart, - host->data->bytes_xfered, dmanow); + DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n", + dmastart, host->data->bytes_xfered, dmanow); sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); } @@ -2668,6 +2697,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) struct sdhci_host *host = dev_id; u32 intmask, mask, unexpected = 0; int max_loops = 16; + int cardint = 0; spin_lock(&host->lock); @@ -2683,14 +2713,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } do { + DBG("IRQ status 0x%08x\n", intmask); + + if (host->ops->irq) { + intmask = host->ops->irq(host, intmask); + if (!intmask) + goto cont; + } + /* Clear selected interrupts. */ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | SDHCI_INT_BUS_POWER); sdhci_writel(host, mask, SDHCI_INT_STATUS); - DBG("*** %s got interrupt: 0x%08x\n", - mmc_hostname(host->mmc), intmask); - if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; @@ -2736,9 +2771,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if ((intmask & SDHCI_INT_CARD_INT) && (host->ier & SDHCI_INT_CARD_INT)) { - sdhci_enable_sdio_irq_nolock(host, false); - host->thread_isr |= SDHCI_INT_CARD_INT; - result = IRQ_WAKE_THREAD; + if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) { + sdhci_enable_sdio_irq_nolock(host, false); + host->thread_isr |= SDHCI_INT_CARD_INT; + result = IRQ_WAKE_THREAD; + } else { + cardint = 1; + } } intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | @@ -2750,7 +2789,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) unexpected |= intmask; sdhci_writel(host, intmask, SDHCI_INT_STATUS); } - +cont: if (result == IRQ_NONE) result = IRQ_HANDLED; @@ -2765,6 +2804,9 @@ out: sdhci_dumpregs(host); } + if (cardint && host->mmc->sdio_irqs) + mmc_signal_sdio_irq(host->mmc); + return result; } @@ -2787,12 +2829,13 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) } if (isr & SDHCI_INT_CARD_INT) { - sdio_run_irqs(host->mmc); - - spin_lock_irqsave(&host->lock, flags); - if (host->flags & SDHCI_SDIO_IRQ_ENABLED) - sdhci_enable_sdio_irq_nolock(host, true); - spin_unlock_irqrestore(&host->lock, flags); + if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) { + sdio_run_irqs(host->mmc); + spin_lock_irqsave(&host->lock, flags); + if (host->flags & SDHCI_SDIO_IRQ_ENABLED) + sdhci_enable_sdio_irq_nolock(host, true); + spin_unlock_irqrestore(&host->lock, flags); + } } return isr ? IRQ_HANDLED : IRQ_NONE; @@ -2815,6 +2858,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) */ void sdhci_enable_irq_wakeups(struct sdhci_host *host) { + int gpio_cd = mmc_gpio_get_cd(host->mmc); u8 val; u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE | SDHCI_WAKE_ON_INT; @@ -2824,7 +2868,8 @@ void sdhci_enable_irq_wakeups(struct sdhci_host *host) val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); val |= mask ; /* Avoid fake wake up */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION || + (gpio_cd >= 0)) { val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE); irq_val &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); } @@ -2849,14 +2894,12 @@ int sdhci_suspend_host(struct sdhci_host *host) sdhci_disable_card_detection(host); mmc_retune_timer_stop(host->mmc); - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); if (!device_may_wakeup(mmc_dev(host->mmc))) { host->ier = 0; sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - free_irq(host->irq, host); + disable_irq(host->irq); } else { sdhci_enable_irq_wakeups(host); enable_irq_wake(host->irq); @@ -2869,7 +2912,6 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host); int sdhci_resume_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; - int ret = 0; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) @@ -2889,11 +2931,7 @@ int sdhci_resume_host(struct sdhci_host *host) } if (!device_may_wakeup(mmc_dev(host->mmc))) { - ret = request_threaded_irq(host->irq, sdhci_irq, - sdhci_thread_irq, IRQF_SHARED, - mmc_hostname(host->mmc), host); - if (ret) - return ret; + enable_irq(host->irq); } else { sdhci_disable_irq_wakeups(host); disable_irq_wake(host->irq); @@ -2901,7 +2939,7 @@ int sdhci_resume_host(struct sdhci_host *host) sdhci_enable_card_detection(host); - return ret; + return 0; } EXPORT_SYMBOL_GPL(sdhci_resume_host); @@ -2911,8 +2949,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) unsigned long flags; mmc_retune_timer_stop(host->mmc); - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); spin_lock_irqsave(&host->lock, flags); host->ier &= SDHCI_INT_CARD_INT; @@ -2943,22 +2979,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_init(host, 0); - /* Force clock and power re-program */ - host->pwr = 0; - host->clock = 0; - mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); - mmc->ops->set_ios(mmc, &mmc->ios); + if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) { + /* Force clock and power re-program */ + host->pwr = 0; + host->clock = 0; + mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); - if ((host_flags & SDHCI_PV_ENABLED) && - !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { - spin_lock_irqsave(&host->lock, flags); - sdhci_enable_preset_value(host, true); - spin_unlock_irqrestore(&host->lock, flags); - } + if ((host_flags & SDHCI_PV_ENABLED) && + !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { + spin_lock_irqsave(&host->lock, flags); + sdhci_enable_preset_value(host, true); + spin_unlock_irqrestore(&host->lock, flags); + } - if ((mmc->caps2 & MMC_CAP2_HS400_ES) && - mmc->ops->hs400_enhanced_strobe) - mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios); + if ((mmc->caps2 & MMC_CAP2_HS400_ES) && + mmc->ops->hs400_enhanced_strobe) + mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios); + } spin_lock_irqsave(&host->lock, flags); @@ -2981,6 +3019,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); /*****************************************************************************\ * * + * Command Queue Engine (CQE) helpers * + * * +\*****************************************************************************/ + +void sdhci_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + u8 ctrl; + + spin_lock_irqsave(&host->lock, flags); + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + if (host->flags & SDHCI_USE_64_BIT_DMA) + ctrl |= SDHCI_CTRL_ADMA64; + else + ctrl |= SDHCI_CTRL_ADMA32; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 512), + SDHCI_BLOCK_SIZE); + + /* Set maximum timeout */ + sdhci_set_timeout(host, NULL); + + host->ier = host->cqe_ier; + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + + host->cqe_on = true; + + pr_debug("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n", + mmc_hostname(mmc), host->ier, + sdhci_readl(host, SDHCI_INT_STATUS)); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} +EXPORT_SYMBOL_GPL(sdhci_cqe_enable); + +void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + sdhci_set_default_irqs(host); + + host->cqe_on = false; + + if (recovery) { + sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); + } + + pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n", + mmc_hostname(mmc), host->ier, + sdhci_readl(host, SDHCI_INT_STATUS)); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} +EXPORT_SYMBOL_GPL(sdhci_cqe_disable); + +bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, + int *data_error) +{ + u32 mask; + + if (!host->cqe_on) + return false; + + if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) + *cmd_error = -EILSEQ; + else if (intmask & SDHCI_INT_TIMEOUT) + *cmd_error = -ETIMEDOUT; + else + *cmd_error = 0; + + if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) + *data_error = -EILSEQ; + else if (intmask & SDHCI_INT_DATA_TIMEOUT) + *data_error = -ETIMEDOUT; + else if (intmask & SDHCI_INT_ADMA_ERROR) + *data_error = -EIO; + else + *data_error = 0; + + /* Clear selected interrupts. */ + mask = intmask & host->cqe_ier; + sdhci_writel(host, mask, SDHCI_INT_STATUS); + + if (intmask & SDHCI_INT_BUS_POWER) + pr_err("%s: Card is consuming too much power!\n", + mmc_hostname(host->mmc)); + + intmask &= ~(host->cqe_ier | SDHCI_INT_ERROR); + if (intmask) { + sdhci_writel(host, intmask, SDHCI_INT_STATUS); + pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n", + mmc_hostname(host->mmc), intmask); + sdhci_dumpregs(host); + } + + return true; +} +EXPORT_SYMBOL_GPL(sdhci_cqe_irq); + +/*****************************************************************************\ + * * * Device allocation/registration * * * \*****************************************************************************/ @@ -3004,6 +3155,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host->flags = SDHCI_SIGNALING_330; + host->cqe_ier = SDHCI_CQE_INT_MASK; + host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK; + return host; } @@ -3042,6 +3196,8 @@ static int sdhci_set_dma_mask(struct sdhci_host *host) void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1) { u16 v; + u64 dt_caps_mask = 0; + u64 dt_caps = 0; if (host->read_caps) return; @@ -3056,24 +3212,42 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1) sdhci_do_reset(host, SDHCI_RESET_ALL); + of_property_read_u64(mmc_dev(host->mmc)->of_node, + "sdhci-caps-mask", &dt_caps_mask); + of_property_read_u64(mmc_dev(host->mmc)->of_node, + "sdhci-caps", &dt_caps); + v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION); host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (host->quirks & SDHCI_QUIRK_MISSING_CAPS) return; - host->caps = caps ? *caps : sdhci_readl(host, SDHCI_CAPABILITIES); + if (caps) { + host->caps = *caps; + } else { + host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); + host->caps &= ~lower_32_bits(dt_caps_mask); + host->caps |= lower_32_bits(dt_caps); + } if (host->version < SDHCI_SPEC_300) return; - host->caps1 = caps1 ? *caps1 : sdhci_readl(host, SDHCI_CAPABILITIES_1); + if (caps1) { + host->caps1 = *caps1; + } else { + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->caps1 &= ~upper_32_bits(dt_caps_mask); + host->caps1 |= upper_32_bits(dt_caps); + } } EXPORT_SYMBOL_GPL(__sdhci_read_caps); int sdhci_setup_host(struct sdhci_host *host) { struct mmc_host *mmc; + struct device *dev; u32 max_current_caps; unsigned int ocr_avail; unsigned int override_timeout_clk; @@ -3085,6 +3259,7 @@ int sdhci_setup_host(struct sdhci_host *host) return -EINVAL; mmc = host->mmc; + dev = mmc_dev(mmc); /* * If there are external regulators, get them. Note this must be done @@ -3267,20 +3442,22 @@ int sdhci_setup_host(struct sdhci_host *host) if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + + if (host->caps & SDHCI_TIMEOUT_CLK_UNIT) + host->timeout_clk *= 1000; + if (host->timeout_clk == 0) { - if (host->ops->get_timeout_clock) { - host->timeout_clk = - host->ops->get_timeout_clock(host); - } else { + if (!host->ops->get_timeout_clock) { pr_err("%s: Hardware doesn't specify timeout clock frequency.\n", mmc_hostname(mmc)); ret = -ENODEV; goto undma; } - } - if (host->caps & SDHCI_TIMEOUT_CLK_UNIT) - host->timeout_clk *= 1000; + host->timeout_clk = + DIV_ROUND_UP(host->ops->get_timeout_clock(host), + 1000); + } if (override_timeout_clk) host->timeout_clk = override_timeout_clk; @@ -3291,7 +3468,8 @@ int sdhci_setup_host(struct sdhci_host *host) } mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; - mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + if (!(host->quirks2 & SDHCI_QUIRK2_SDIO_IRQ_THREAD)) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) host->flags |= SDHCI_AUTO_CMD12; @@ -3302,9 +3480,9 @@ int sdhci_setup_host(struct sdhci_host *host) !(host->flags & SDHCI_USE_SDMA)) && !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) { host->flags |= SDHCI_AUTO_CMD23; - DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc)); + DBG("Auto-CMD23 available\n"); } else { - DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc)); + DBG("Auto-CMD23 unavailable\n"); } /* @@ -3323,11 +3501,6 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - mmc_card_is_removable(mmc) && - mmc_gpio_get_cd(host->mmc) < 0) - mmc->caps |= MMC_CAP_NEEDS_POLL; - if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc); @@ -3353,6 +3526,7 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + mmc->caps2 |= MMC_CAP2_DDR52_3_3V; } /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ @@ -3492,10 +3666,11 @@ int sdhci_setup_host(struct sdhci_host *host) goto unreg; } - if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + if (((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) || - (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) + (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) && + !(mmc->caps2 & MMC_CAP2_DDR52_3_3V)) host->flags |= SDHCI_SIGNALING_180; if (mmc->caps2 & MMC_CAP2_HSX00_1_2V) @@ -3527,10 +3702,20 @@ int sdhci_setup_host(struct sdhci_host *host) * be larger than 64 KiB though. */ if (host->flags & SDHCI_USE_ADMA) { - if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) + if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) { mmc->max_seg_size = 65535; - else + + /* + * send the ADMA limitation to IOMMU. In default, + * the max segment size of IOMMU is 64KB, this exceed + * the ADMA max segment limitation, which is 65535. + */ + dev->dma_parms = devm_kzalloc(dev, + sizeof(*dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(dev, SZ_64K - 1); + } else { mmc->max_seg_size = 65536; + } } else { mmc->max_seg_size = mmc->max_req_size; } @@ -3575,6 +3760,22 @@ undma: } EXPORT_SYMBOL_GPL(sdhci_setup_host); +void sdhci_cleanup_host(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + + if (!IS_ERR(mmc->supply.vqmmc)) + regulator_disable(mmc->supply.vqmmc); + + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, host->align_buffer, + host->align_addr); + host->adma_table = NULL; + host->align_buffer = NULL; +} +EXPORT_SYMBOL_GPL(sdhci_cleanup_host); + int __sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; @@ -3639,16 +3840,6 @@ unirq: untasklet: tasklet_kill(&host->finish_tasklet); - if (!IS_ERR(mmc->supply.vqmmc)) - regulator_disable(mmc->supply.vqmmc); - - if (host->align_buffer) - dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + - host->adma_table_sz, host->align_buffer, - host->align_addr); - host->adma_table = NULL; - host->align_buffer = NULL; - return ret; } EXPORT_SYMBOL_GPL(__sdhci_add_host); @@ -3661,7 +3852,16 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) return ret; - return __sdhci_add_host(host); + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + return 0; + +cleanup: + sdhci_cleanup_host(host); + + return ret; } EXPORT_SYMBOL_GPL(sdhci_add_host); |