2012/12/14 Kevin Liu <keyuan.liu@xxxxxxxxx>: > 2012/12/14 Ulf Hansson <ulf.hansson@xxxxxxxxxx>: >> On 14 December 2012 11:53, Kevin Liu <kliu5@xxxxxxxxxxx> wrote: >>> 1. if host does NOT implement signal voltage setting function, >>> should return error. >>> 2. add the check for data signal before voltage change according >>> to the spec. If host does NOT detect a low signal level, the host >>> should abort the voltage switch sequence. (phisical layer spec 4.2.4.2(4)) >>> 3. if voltage change failed then no need to restore the clock >>> before cycle power the card. >>> 4. call mmc_power_cycle here since it's a part of voltage switch. >>> besides -EAGAIN, any other error returned should also cycle power the card. >>> >>> Signed-off-by: Kevin Liu <kliu5@xxxxxxxxxxx> >>> --- >>> drivers/mmc/core/core.c | 71 ++++++++++++++++++++++++++++------------------ >>> 1 files changed, 43 insertions(+), 28 deletions(-) >>> >>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c >>> index d1aa8ab..da93186 100644 >>> --- a/drivers/mmc/core/core.c >>> +++ b/drivers/mmc/core/core.c >>> @@ -1226,6 +1226,9 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 >>> >>> BUG_ON(!host); >>> >>> + if (!host->ops->start_signal_voltage_switch) >>> + return -EPERM; >>> + >> >> No, this is not OK. >> For example, eMMC might default use 1.8V as I/O voltage, you don't >> want to force host drivers implementing this function to make this >> work. >> > I agree. > But then how can we make sure emmc's voltage? > Only depend on the voltage by default? > I will update the patch and move this judgement withine cmd11. > >>> /* >>> * Send CMD11 only if the request is to switch the card to >>> * 1.8V signalling. >>> @@ -1245,47 +1248,59 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 >>> >>> host->ios.signal_voltage = signal_voltage; >>> >>> - if (host->ops->start_signal_voltage_switch) { >>> - u32 clock; >>> + u32 clock; >>> + >>> + mmc_host_clk_hold(host); >>> + >>> + if (cmd11) { >>> + if (!host->ops->card_busy) >>> + pr_warning("%s: cannot verify signal voltage switch\n", >>> + mmc_hostname(host)); >>> >>> - mmc_host_clk_hold(host); >>> /* >>> * During a signal voltage level switch, the clock must be gated >>> * for a certain period of time according to the SD spec >>> */ >>> - if (cmd11) { >>> - clock = host->ios.clock; >>> - host->ios.clock = 0; >>> - mmc_set_ios(host); >>> - } >>> + clock = host->ios.clock; >>> + host->ios.clock = 0; >>> + mmc_set_ios(host); >>> >>> - err = host->ops->start_signal_voltage_switch(host, &host->ios); >>> + if (host->ops->card_busy && !host->ops->card_busy(host)) { >>> + err = -EAGAIN; >>> + } else { >> >> Great that you spotted this! We should check busy before we do the >> actual voltage switch. >> >> Although, I think it would make sense to do this before the clock is >> set to 0. Especially important for those host controllers that do >> support busy-detection, a qualified guess would be that those also >> could require the clock to be on to detect this. Or what do you think? >> From spec point of view it shall be safe to do it before setting clk >> to 0. >> > I considered this when I draft this patch. > My only concern is whether DAT level is stable at that point. > According to the spec, the card driver DAT[3:0] to low at the NEXT > clock of the end bit for R1 response after completing the R1 response. > I'm not sure whether the status is stable if we query the DAT level > just after cmd11. > How about adding a 1ms delay between cmd11 response and calling card_busy? And we can do this before the clock is set to 0. As spec said the timing > I agree with you that it will be safer to keep clock on when detecting. > >>> >>> - if (err && cmd11) { >>> - host->ios.clock = clock; >>> - mmc_set_ios(host); >>> - } else if (cmd11) { >>> - /* Keep clock gated for at least 5 ms */ >>> - mmc_delay(5); >>> - host->ios.clock = clock; >>> - mmc_set_ios(host); >>> + err = host->ops->start_signal_voltage_switch(host, &host->ios); >>> >>> - /* Wait for at least 1 ms according to spec */ >>> - mmc_delay(1); >>> + if (!err) { >>> + /* Keep clock gated for at least 5 ms */ >>> + mmc_delay(5); >>> + host->ios.clock = clock; >>> + mmc_set_ios(host); >>> >>> - /* >>> - * Failure to switch is indicated by the card holding >>> - * dat[0:3] low >>> - */ >>> - if (!host->ops->card_busy) >>> - pr_warning("%s: cannot verify signal voltage switch\n", >>> + /* Wait for at least 1 ms according to spec */ >>> + mmc_delay(1); >>> + >>> + /* >>> + * Failure to switch is indicated by the card holding >>> + * dat[0:3] low >>> + */ >>> + if (host->ops->card_busy && host->ops->card_busy(host)) >>> + err = -EAGAIN; >>> + } >>> + } >>> + if (err) { >>> + /* Power cycle card */ >>> + pr_debug("%s: Signal voltage switch failed, " >>> + "power cycling card \n", >>> mmc_hostname(host)); >>> - else if (host->ops->card_busy(host)) >>> - err = -EAGAIN; >>> + mmc_power_cycle(host); >>> } >>> - mmc_host_clk_release(host); >>> + } else { >>> + err = host->ops->start_signal_voltage_switch(host, &host->ios); >>> } >>> >>> + mmc_host_clk_release(host); >>> + >>> return err; >>> } >>> >>> -- >>> 1.7.0.4 >>> >> >> Kind regards >> Ulf Hansson -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html