Commit 8d86cf88 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.10-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:
 "MMC core:
   - further fix thread wake-up for requests
   - use a bounce buffer to fix DMA issue for SSR register read

  MMC host:
   - sdhci: Fix a regression for runtime PM
   - sdhci-cadence: Add a proper SoC specific DT compatible"

* tag 'mmc-v4.10-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sd: Meet alignment requirements for raw_ssr DMA
  mmc: core: Further fix thread wake-up
  mmc: sdhci: Fix to handle MMC_POWER_UNDEFINED
  mmc: sdhci-cadence: add Socionext UniPhier specific compatible string
parents 67327145 e85baa88
* Cadence SD/SDIO/eMMC Host Controller * Cadence SD/SDIO/eMMC Host Controller
Required properties: Required properties:
- compatible: should be "cdns,sd4hc". - compatible: should be one of the following:
"cdns,sd4hc" - default of the IP
"socionext,uniphier-sd4hc" - for Socionext UniPhier SoCs
- reg: offset and length of the register set for the device. - reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier. - interrupts: a single interrupt specifier.
- clocks: phandle to the input clock. - clocks: phandle to the input clock.
...@@ -19,7 +21,7 @@ if supported. See mmc.txt for details. ...@@ -19,7 +21,7 @@ if supported. See mmc.txt for details.
Example: Example:
emmc: sdhci@5a000000 { emmc: sdhci@5a000000 {
compatible = "cdns,sd4hc"; compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
reg = <0x5a000000 0x400>; reg = <0x5a000000 0x400>;
interrupts = <0 78 4>; interrupts = <0 78 4>;
clocks = <&clk 4>; clocks = <&clk 4>;
......
...@@ -496,8 +496,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) ...@@ -496,8 +496,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
* Returns enum mmc_blk_status after checking errors. * Returns enum mmc_blk_status after checking errors.
*/ */
static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
struct mmc_request *mrq, struct mmc_request *mrq)
struct mmc_async_req *next_req)
{ {
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info; struct mmc_context_info *context_info = &host->context_info;
...@@ -507,7 +506,7 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, ...@@ -507,7 +506,7 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
wait_event_interruptible(context_info->wait, wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv || (context_info->is_done_rcv ||
context_info->is_new_req)); context_info->is_new_req));
context_info->is_waiting_last_req = false;
if (context_info->is_done_rcv) { if (context_info->is_done_rcv) {
context_info->is_done_rcv = false; context_info->is_done_rcv = false;
cmd = mrq->cmd; cmd = mrq->cmd;
...@@ -527,10 +526,9 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, ...@@ -527,10 +526,9 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
__mmc_start_request(host, mrq); __mmc_start_request(host, mrq);
continue; /* wait for done/new event again */ continue; /* wait for done/new event again */
} }
} else if (context_info->is_new_req) {
if (!next_req)
return MMC_BLK_NEW_REQUEST;
} }
return MMC_BLK_NEW_REQUEST;
} }
mmc_retune_release(host); mmc_retune_release(host);
return status; return status;
...@@ -660,7 +658,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, ...@@ -660,7 +658,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
mmc_pre_req(host, areq->mrq); mmc_pre_req(host, areq->mrq);
if (host->areq) { if (host->areq) {
status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); status = mmc_wait_for_data_req_done(host, host->areq->mrq);
if (status == MMC_BLK_NEW_REQUEST) { if (status == MMC_BLK_NEW_REQUEST) {
if (ret_stat) if (ret_stat)
*ret_stat = status; *ret_stat = status;
......
...@@ -223,6 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card) ...@@ -223,6 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card)
static int mmc_read_ssr(struct mmc_card *card) static int mmc_read_ssr(struct mmc_card *card)
{ {
unsigned int au, es, et, eo; unsigned int au, es, et, eo;
u32 *raw_ssr;
int i; int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) { if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
...@@ -231,14 +232,21 @@ static int mmc_read_ssr(struct mmc_card *card) ...@@ -231,14 +232,21 @@ static int mmc_read_ssr(struct mmc_card *card)
return 0; return 0;
} }
if (mmc_app_sd_status(card, card->raw_ssr)) { raw_ssr = kmalloc(sizeof(card->raw_ssr), GFP_KERNEL);
if (!raw_ssr)
return -ENOMEM;
if (mmc_app_sd_status(card, raw_ssr)) {
pr_warn("%s: problem reading SD Status register\n", pr_warn("%s: problem reading SD Status register\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
kfree(raw_ssr);
return 0; return 0;
} }
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
card->raw_ssr[i] = be32_to_cpu(card->raw_ssr[i]); card->raw_ssr[i] = be32_to_cpu(raw_ssr[i]);
kfree(raw_ssr);
/* /*
* UNSTUFF_BITS only works with four u32s so we have to offset the * UNSTUFF_BITS only works with four u32s so we have to offset the
......
...@@ -262,6 +262,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev) ...@@ -262,6 +262,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
} }
static const struct of_device_id sdhci_cdns_match[] = { static const struct of_device_id sdhci_cdns_match[] = {
{ .compatible = "socionext,uniphier-sd4hc" },
{ .compatible = "cdns,sd4hc" }, { .compatible = "cdns,sd4hc" },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -1576,6 +1576,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1576,6 +1576,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
unsigned long flags; unsigned long flags;
u8 ctrl; u8 ctrl;
if (ios->power_mode == MMC_POWER_UNDEFINED)
return;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD) { if (host->flags & SDHCI_DEVICE_DEAD) {
...@@ -2938,22 +2941,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) ...@@ -2938,22 +2941,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init(host, 0); sdhci_init(host, 0);
/* Force clock and power re-program */ if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) {
host->pwr = 0; /* Force clock and power re-program */
host->clock = 0; host->pwr = 0;
mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); host->clock = 0;
mmc->ops->set_ios(mmc, &mmc->ios); mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
mmc->ops->set_ios(mmc, &mmc->ios);
if ((host_flags & SDHCI_PV_ENABLED) && if ((host_flags & SDHCI_PV_ENABLED) &&
!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
sdhci_enable_preset_value(host, true); sdhci_enable_preset_value(host, true);
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
if ((mmc->caps2 & MMC_CAP2_HS400_ES) && if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
mmc->ops->hs400_enhanced_strobe) mmc->ops->hs400_enhanced_strobe)
mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios); mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
}
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment