Commit 844ce9f2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-fixes-for-3.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC fixes from Chris Ball:
 - sdhci-acpi: Fix initial runtime PM status, add more ACPI IDs
 - atmel-mci, omap_hsmmc: DT handling fixes
 - esdhc-imx: Fix SDIO IRQs, fix multiblock reads (both h/w errata)

* tag 'mmc-fixes-for-3.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: omap_hsmmc: Skip platform_get_resource_byname() for dt case
  mmc: omap_hsmmc: convert to dma_request_slave_channel_compat
  mmc: omap_hsmmc: Fix the DT pbias workaround for MMC controllers 2 to 5
  mmc: sdhci-pci: add more device ids
  mmc: sdhci-acpi: add more device ids
  mmc: sdhci-acpi: fix initial runtime pm status
  mmc: atmel-mci: convert to dma_request_slave_channel_compat()
  mmc: sdhci-esdhc-imx: fix multiblock reads on i.MX53
  mmc: sdhci-esdhc-imx: Fix SDIO interrupts
parents bb762929 4a29b559
...@@ -2230,10 +2230,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, ...@@ -2230,10 +2230,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_free_host(slot->mmc); mmc_free_host(slot->mmc);
} }
static bool atmci_filter(struct dma_chan *chan, void *slave) static bool atmci_filter(struct dma_chan *chan, void *pdata)
{ {
struct mci_dma_data *sl = slave; struct mci_platform_data *sl_pdata = pdata;
struct mci_dma_data *sl;
if (!sl_pdata)
return false;
sl = sl_pdata->dma_slave;
if (sl && find_slave_dev(sl) == chan->device->dev) { if (sl && find_slave_dev(sl) == chan->device->dev) {
chan->private = slave_data_ptr(sl); chan->private = slave_data_ptr(sl);
return true; return true;
...@@ -2245,24 +2250,18 @@ static bool atmci_filter(struct dma_chan *chan, void *slave) ...@@ -2245,24 +2250,18 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
static bool atmci_configure_dma(struct atmel_mci *host) static bool atmci_configure_dma(struct atmel_mci *host)
{ {
struct mci_platform_data *pdata; struct mci_platform_data *pdata;
dma_cap_mask_t mask;
if (host == NULL) if (host == NULL)
return false; return false;
pdata = host->pdev->dev.platform_data; pdata = host->pdev->dev.platform_data;
if (!pdata) dma_cap_zero(mask);
return false; dma_cap_set(DMA_SLAVE, mask);
if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) { host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
dma_cap_mask_t mask; &host->pdev->dev, "rxtx");
/* Try to grab a DMA channel */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma.chan =
dma_request_channel(mask, atmci_filter, pdata->dma_slave);
}
if (!host->dma.chan) { if (!host->dma.chan) {
dev_warn(&host->pdev->dev, "no DMA channel available\n"); dev_warn(&host->pdev->dev, "no DMA channel available\n");
return false; return false;
......
...@@ -161,6 +161,7 @@ struct omap_hsmmc_host { ...@@ -161,6 +161,7 @@ struct omap_hsmmc_host {
*/ */
struct regulator *vcc; struct regulator *vcc;
struct regulator *vcc_aux; struct regulator *vcc_aux;
int pbias_disable;
void __iomem *base; void __iomem *base;
resource_size_t mapbase; resource_size_t mapbase;
spinlock_t irq_lock; /* Prevent races with irq handler */ spinlock_t irq_lock; /* Prevent races with irq handler */
...@@ -255,11 +256,11 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, ...@@ -255,11 +256,11 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
if (!host->vcc) if (!host->vcc)
return 0; return 0;
/* /*
* With DT, never turn OFF the regulator. This is because * With DT, never turn OFF the regulator for MMC1. This is because
* the pbias cell programming support is still missing when * the pbias cell programming support is still missing when
* booting with Device tree * booting with Device tree
*/ */
if (dev->of_node && !vdd) if (host->pbias_disable && !vdd)
return 0; return 0;
if (mmc_slot(host).before_set_reg) if (mmc_slot(host).before_set_reg)
...@@ -1520,10 +1521,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1520,10 +1521,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
(ios->vdd == DUAL_VOLT_OCR_BIT) && (ios->vdd == DUAL_VOLT_OCR_BIT) &&
/* /*
* With pbias cell programming missing, this * With pbias cell programming missing, this
* can't be allowed when booting with device * can't be allowed on MMC1 when booting with device
* tree. * tree.
*/ */
!host->dev->of_node) { !host->pbias_disable) {
/* /*
* The mmc_select_voltage fn of the core does * The mmc_select_voltage fn of the core does
* not seem to set the power_mode to * not seem to set the power_mode to
...@@ -1871,6 +1872,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1871,6 +1872,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host); omap_hsmmc_context_save(host);
/* This can be removed once we support PBIAS with DT */
if (host->dev->of_node && host->mapbase == 0x4809c000)
host->pbias_disable = 1;
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
/* /*
* MMC can still work without debounce clock. * MMC can still work without debounce clock.
...@@ -1906,33 +1911,41 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1906,33 +1911,41 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_conf_bus_power(host); omap_hsmmc_conf_bus_power(host);
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); if (!pdev->dev.of_node) {
if (!res) { res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); if (!res) {
ret = -ENXIO; dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
goto err_irq; ret = -ENXIO;
} goto err_irq;
tx_req = res->start; }
tx_req = res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
if (!res) { if (!res) {
dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
ret = -ENXIO; ret = -ENXIO;
goto err_irq; goto err_irq;
}
rx_req = res->start;
} }
rx_req = res->start;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); host->rx_chan =
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
&rx_req, &pdev->dev, "rx");
if (!host->rx_chan) { if (!host->rx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
ret = -ENXIO; ret = -ENXIO;
goto err_irq; goto err_irq;
} }
host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); host->tx_chan =
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
&tx_req, &pdev->dev, "tx");
if (!host->tx_chan) { if (!host->tx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
ret = -ENXIO; ret = -ENXIO;
......
...@@ -87,6 +87,12 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { ...@@ -87,6 +87,12 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = {
.enable_dma = sdhci_acpi_enable_dma, .enable_dma = sdhci_acpi_enable_dma,
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
.caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
...@@ -94,23 +100,67 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { ...@@ -94,23 +100,67 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.pm_caps = MMC_PM_KEEP_POWER, .pm_caps = MMC_PM_KEEP_POWER,
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
};
struct sdhci_acpi_uid_slot {
const char *hid;
const char *uid;
const struct sdhci_acpi_slot *slot;
};
static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
{ "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio },
{ "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio },
{ "PNP0D40" },
{ },
};
static const struct acpi_device_id sdhci_acpi_ids[] = { static const struct acpi_device_id sdhci_acpi_ids[] = {
{ "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, { "80860F14" },
{ "PNP0D40" }, { "INT33BB" },
{ "INT33C6" },
{ "PNP0D40" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid,
const char *uid)
{ {
const struct acpi_device_id *id; const struct sdhci_acpi_uid_slot *u;
for (id = sdhci_acpi_ids; id->id[0]; id++) for (u = sdhci_acpi_uids; u->hid; u++) {
if (!strcmp(id->id, hid)) if (strcmp(u->hid, hid))
return (const struct sdhci_acpi_slot *)id->driver_data; continue;
if (!u->uid)
return u->slot;
if (uid && !strcmp(u->uid, uid))
return u->slot;
}
return NULL; return NULL;
} }
static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
const char *hid)
{
const struct sdhci_acpi_slot *slot;
struct acpi_device_info *info;
const char *uid = NULL;
acpi_status status;
status = acpi_get_object_info(handle, &info);
if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID))
uid = info->unique_id.string;
slot = sdhci_acpi_get_slot_by_ids(hid, uid);
kfree(info);
return slot;
}
static int sdhci_acpi_probe(struct platform_device *pdev) static int sdhci_acpi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -148,7 +198,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -148,7 +198,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
c = sdhci_priv(host); c = sdhci_priv(host);
c->host = host; c->host = host;
c->slot = sdhci_acpi_get_slot(hid); c->slot = sdhci_acpi_get_slot(handle, hid);
c->pdev = pdev; c->pdev = pdev;
c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
...@@ -202,6 +252,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -202,6 +252,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
goto err_free; goto err_free;
if (c->use_runtime_pm) { if (c->use_runtime_pm) {
pm_runtime_set_active(dev);
pm_suspend_ignore_children(dev, 1); pm_suspend_ignore_children(dev, 1);
pm_runtime_set_autosuspend_delay(dev, 50); pm_runtime_set_autosuspend_delay(dev, 50);
pm_runtime_use_autosuspend(dev); pm_runtime_use_autosuspend(dev);
......
...@@ -85,6 +85,12 @@ struct pltfm_imx_data { ...@@ -85,6 +85,12 @@ struct pltfm_imx_data {
struct clk *clk_ipg; struct clk *clk_ipg;
struct clk *clk_ahb; struct clk *clk_ahb;
struct clk *clk_per; struct clk *clk_per;
enum {
NO_CMD_PENDING, /* no multiblock command pending*/
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
}; };
static struct platform_device_id imx_esdhc_devtype[] = { static struct platform_device_id imx_esdhc_devtype[] = {
...@@ -154,6 +160,8 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i ...@@ -154,6 +160,8 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
static u32 esdhc_readl_le(struct sdhci_host *host, int reg) static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
u32 val = readl(host->ioaddr + reg); u32 val = readl(host->ioaddr + reg);
if (unlikely(reg == SDHCI_CAPABILITIES)) { if (unlikely(reg == SDHCI_CAPABILITIES)) {
...@@ -175,6 +183,18 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) ...@@ -175,6 +183,18 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
val |= SDHCI_INT_ADMA_ERROR; val |= SDHCI_INT_ADMA_ERROR;
} }
/*
* mask off the interrupt we get in response to the manually
* sent CMD12
*/
if ((imx_data->multiblock_status == WAIT_FOR_INT) &&
((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) {
val &= ~SDHCI_INT_RESPONSE;
writel(SDHCI_INT_RESPONSE, host->ioaddr +
SDHCI_INT_STATUS);
imx_data->multiblock_status = NO_CMD_PENDING;
}
} }
return val; return val;
...@@ -211,6 +231,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) ...@@ -211,6 +231,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS)
{
/* send a manual CMD12 with RESPTYP=none */
data = MMC_STOP_TRANSMISSION << 24 |
SDHCI_CMD_ABORTCMD << 16;
writel(data, host->ioaddr + SDHCI_TRANSFER_MODE);
imx_data->multiblock_status = WAIT_FOR_INT;
}
} }
if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
...@@ -277,11 +306,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -277,11 +306,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
} }
return; return;
case SDHCI_COMMAND: case SDHCI_COMMAND:
if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || if (host->cmd->opcode == MMC_STOP_TRANSMISSION)
host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
(imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
val |= SDHCI_CMD_ABORTCMD; val |= SDHCI_CMD_ABORTCMD;
if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
(imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
if (is_imx6q_usdhc(imx_data)) if (is_imx6q_usdhc(imx_data))
writel(val << 16, writel(val << 16,
host->ioaddr + SDHCI_TRANSFER_MODE); host->ioaddr + SDHCI_TRANSFER_MODE);
...@@ -324,8 +355,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) ...@@ -324,8 +355,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
/* /*
* Do not touch buswidth bits here. This is done in * Do not touch buswidth bits here. This is done in
* esdhc_pltfm_bus_width. * esdhc_pltfm_bus_width.
* Do not touch the D3CD bit either which is used for the
* SDIO interrupt errata workaround.
*/ */
mask = 0xffff & ~ESDHC_CTRL_BUSWIDTH_MASK; mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
esdhc_clrset_le(host, mask, new_val, reg); esdhc_clrset_le(host, mask, new_val, reg);
return; return;
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
*/ */
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 #define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a #define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
/* /*
* PCI registers * PCI registers
...@@ -304,6 +307,33 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { ...@@ -304,6 +307,33 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
.probe_slot = pch_hc_probe_slot, .probe_slot = pch_hc_probe_slot,
}; };
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
return 0;
}
static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
return 0;
}
static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
.allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot,
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.allow_runtime_pm = true,
.probe_slot = byt_sdio_probe_slot,
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
};
/* O2Micro extra registers */ /* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3 #define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE #define O2_SD_MULTI_VCC3V 0xEE
...@@ -855,6 +885,30 @@ static const struct pci_device_id pci_ids[] = { ...@@ -855,6 +885,30 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
}, },
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BYT_EMMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BYT_SDIO,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BYT_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
},
{ {
.vendor = PCI_VENDOR_ID_O2, .vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120, .device = PCI_DEVICE_ID_O2_8120,
......
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