diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 10:03:52 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 10:03:52 -0800 |
| commit | 0e45384cecccaa950783e67e7a29ed470133f19d (patch) | |
| tree | c73c3c744b64140625a833e9e36cf8d7f795165d /drivers/mmc | |
| parent | dc5fa4656864d3391cdf13512ffa0733ef72fcdc (diff) | |
| parent | def7bd940f8cceb41ec3d1383acd8ab937056dcb (diff) | |
| download | linux-0e45384cecccaa950783e67e7a29ed470133f19d.tar.gz linux-0e45384cecccaa950783e67e7a29ed470133f19d.tar.bz2 linux-0e45384cecccaa950783e67e7a29ed470133f19d.zip | |
Merge tag 'mmc-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"These are the updates for MMC and MEMSTICK for v5.5.
Note that this also contains quite some additional changes reaching
beyond both the MMC and MEMSTICK subsystems. This is primarily because
of fixing an old regression for a WiFi driver based on the SDIO
interface on an OMAP openpandora board
MMC core:
- Add CMD13 polling for MMC IOCTLS with R1B response.
- Add common DT properties for clk-phase-delays for various speed
modes.
- Fix size overflow for mmc gp-partitions.
- Re-work HW reset for SDIO cards, which also includes a re-work for
Marvell's WiFi mwifiex SDIO func driver.
MMC host:
- jz4740: Add support for X1000 and JZ4760.
- jz4740: Add support for 8-bit bus and for low power mode.
- mmci: Add support for HW busy timeout for the stm32_sdmmc variant.
- owl-mmc: Add driver for Actions Semi Owl SoCs SD/MMC controller.
- renesas_sdhi: Add support for r8a774b1.
- sdhci_am654: Add support for Command Queuing Engine for J721E.
- sdhci-milbeaut: Add driver for the Milbeaut SD controller.
- sdhci-of-arasan: Add support for ZynqMP tap-delays.
- sdhci-of-arasan: Add support for clk-phase-delays for SD cards.
- sdhci-of-arasan: Add support for Intel LGM SDXC.
- sdhci-of-aspeed: Allow inversion of the internal card detect
signal.
- sdhci-of-esdhc: Fixup workaround for erratum A-008171 for tunings.
- sdhci-of-at91: Improve support for calibration.
- sdhci-pci: Add support for Intel JSL.
- sdhci-pci: Add quirk for AMD SDHC Device 0x7906.
- tmio: Enable support for erase/discard/trim requests.
MMC/OMAP/pandora/wl1251:
The TI wl1251 WiFi driver for SDIO on the OMAP openpandora board has
been broken since v4.7. To fix the problems, changes have been made
cross subsystems, but also to OMAP2 machine code and to openpandora
DTS files, as summarized below. Relevant changes have been tagged for
stable.
- mmc/wl1251: Re-introduce lost SDIO quirks and vendor-id for wl1251
- omap/omap_hsmmc: Remove redundant platform config for openpandora
- omap_hsmmc: Initialize non-std SDIO card for wl1251 for pandora
- omap/dts/pandora: Specify wl1251 through a child node of mmc3
- wl1251: Add devicetree support for TI wl1251 SDIO"
* tag 'mmc-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (73 commits)
dt-bindings: mmc: Correct the type of the clk phase properties
Revert "mmc: tmio: remove workaround for NON_REMOVABLE"
memstick: Fix Kconfig indentation
mmc: sdhci-of-arasan: Add support for ZynqMP Platform Tap Delays Setup
dt-bindings: mmc: arasan: Document 'xlnx,zynqmp-8.9a' controller
firmware: xilinx: Add SDIO Tap Delay nodes
mmc: sdhci-of-arasan: Add support to set clock phase delays for SD
dt-bindings: mmc: Add optional generic properties for mmc
mmc: sdhci-of-arasan: Add sampling clock for a phy to use
dt-bindings: mmc: arasan: Update Documentation for the input clock
mmc: sdhci-of-arasan: Separate out clk related data to another structure
mmc: sdhci: Fix grammar in warning message
mmc: sdhci-of-aspeed: add inversion signal presence
mmc: sdhci-of-aspeed: enable CONFIG_MMC_SDHCI_IO_ACCESSORS
mmc: sdhci_am654: Add Support for Command Queuing Engine to J721E
mmc: core: Fix size overflow for mmc partitions
mmc: tmio: Add MMC_CAP_ERASE to allow erase/discard/trim requests
net: wireless: ti: remove local VENDOR_ID and DEVICE_ID definitions
net: wireless: ti: wl1251 use new SDIO_VENDOR_ID_TI_WL1251 definition
mmc: core: fix wl1251 sdio quirks
...
Diffstat (limited to 'drivers/mmc')
36 files changed, 2336 insertions, 320 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2c71a434c915..95b41c0891d0 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -408,38 +408,6 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, return 0; } -static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, - u32 retries_max) -{ - int err; - u32 retry_count = 0; - - if (!status || !retries_max) - return -EINVAL; - - do { - err = __mmc_send_status(card, status, 5); - if (err) - break; - - if (!R1_STATUS(*status) && - (R1_CURRENT_STATE(*status) != R1_STATE_PRG)) - break; /* RPMB programming operation complete */ - - /* - * Rechedule to give the MMC device a chance to continue - * processing the previous command without being polled too - * frequently. - */ - usleep_range(1000, 5000); - } while (++retry_count < retries_max); - - if (retry_count == retries_max) - err = -EPERM; - - return err; -} - static int ioctl_do_sanitize(struct mmc_card *card) { int err; @@ -468,6 +436,58 @@ out: return err; } +static inline bool mmc_blk_in_tran_state(u32 status) +{ + /* + * Some cards mishandle the status bits, so make sure to check both the + * busy indication and the card state. + */ + return status & R1_READY_FOR_DATA && + (R1_CURRENT_STATE(status) == R1_STATE_TRAN); +} + +static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, + u32 *resp_errs) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); + int err = 0; + u32 status; + + do { + bool done = time_after(jiffies, timeout); + + err = __mmc_send_status(card, &status, 5); + if (err) { + dev_err(mmc_dev(card->host), + "error %d requesting status\n", err); + return err; + } + + /* Accumulate any response error bits seen */ + if (resp_errs) + *resp_errs |= status; + + /* + * Timeout if the device never becomes ready for data and never + * leaves the program state. + */ + if (done) { + dev_err(mmc_dev(card->host), + "Card stuck in wrong state! %s status: %#x\n", + __func__, status); + return -ETIMEDOUT; + } + + /* + * Some cards mishandle the status bits, + * so make sure to check both the busy + * indication and the card state. + */ + } while (!mmc_blk_in_tran_state(status)); + + return err; +} + static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_blk_ioc_data *idata) { @@ -477,7 +497,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct scatterlist sg; int err; unsigned int target_part; - u32 status = 0; if (!card || !md || !idata) return -EINVAL; @@ -611,16 +630,12 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); - if (idata->rpmb) { + if (idata->rpmb || (cmd.flags & MMC_RSP_R1B)) { /* - * Ensure RPMB command has completed by polling CMD13 + * Ensure RPMB/R1B command has completed by polling CMD13 * "Send Status". */ - err = ioctl_rpmb_card_status_poll(card, &status, 5); - if (err) - dev_err(mmc_dev(card->host), - "%s: Card Status=0x%08X, error %d\n", - __func__, status, err); + err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, NULL); } return err; @@ -970,58 +985,6 @@ static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host, return ms; } -static inline bool mmc_blk_in_tran_state(u32 status) -{ - /* - * Some cards mishandle the status bits, so make sure to check both the - * busy indication and the card state. - */ - return status & R1_READY_FOR_DATA && - (R1_CURRENT_STATE(status) == R1_STATE_TRAN); -} - -static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, - struct request *req, u32 *resp_errs) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); - int err = 0; - u32 status; - - do { - bool done = time_after(jiffies, timeout); - - err = __mmc_send_status(card, &status, 5); - if (err) { - pr_err("%s: error %d requesting status\n", - req->rq_disk->disk_name, err); - return err; - } - - /* Accumulate any response error bits seen */ - if (resp_errs) - *resp_errs |= status; - - /* - * Timeout if the device never becomes ready for data and never - * leaves the program state. - */ - if (done) { - pr_err("%s: Card stuck in wrong state! %s %s status: %#x\n", - mmc_hostname(card->host), - req->rq_disk->disk_name, __func__, status); - return -ETIMEDOUT; - } - - /* - * Some cards mishandle the status bits, - * so make sure to check both the busy - * indication and the card state. - */ - } while (!mmc_blk_in_tran_state(status)); - - return err; -} - static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, int type) { @@ -1671,7 +1634,7 @@ static int mmc_blk_fix_state(struct mmc_card *card, struct request *req) mmc_blk_send_stop(card, timeout); - err = card_busy_detect(card, timeout, req, NULL); + err = card_busy_detect(card, timeout, NULL); mmc_retune_release(card->host); @@ -1895,7 +1858,7 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ) return 0; - err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, req, &status); + err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, &status); /* * Do not assume data transferred correctly if there are any error bits diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 221127324709..abf8f5eb0a1c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1469,8 +1469,7 @@ void mmc_detach_bus(struct mmc_host *host) mmc_bus_put(host); } -static void _mmc_detect_change(struct mmc_host *host, unsigned long delay, - bool cd_irq) +void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq) { /* * If the device is configured as wakeup, we prevent a new sleep for @@ -2129,7 +2128,7 @@ int mmc_hw_reset(struct mmc_host *host) ret = host->bus_ops->hw_reset(host); mmc_bus_put(host); - if (ret) + if (ret < 0) pr_warn("%s: tried to HW reset card, got error %d\n", mmc_hostname(host), ret); @@ -2297,11 +2296,8 @@ void mmc_rescan(struct work_struct *work) mmc_bus_get(host); - /* - * if there is a _removable_ card registered, check whether it is - * still present - */ - if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host)) + /* Verify a registered card to be functional, else remove it. */ + if (host->bus_ops && !host->bus_dead) host->bus_ops->detect(host); host->detect_change = 0; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 328c78dbee66..575ac0257af2 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -70,6 +70,8 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); +void _mmc_detect_change(struct mmc_host *host, unsigned long delay, + bool cd_irq); int _mmc_detect_card_removed(struct mmc_host *host); int mmc_detect_card_removed(struct mmc_host *host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c8804895595f..f6912ded652d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -297,7 +297,7 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd) } } -static void mmc_part_add(struct mmc_card *card, unsigned int size, +static void mmc_part_add(struct mmc_card *card, u64 size, unsigned int part_cfg, char *name, int idx, bool ro, int area_type) { @@ -313,7 +313,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) { int idx; u8 hc_erase_grp_sz, hc_wp_grp_sz; - unsigned int part_size; + u64 part_size; /* * General purpose partition feature support -- @@ -343,8 +343,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; - part_size *= (size_t)(hc_erase_grp_sz * - hc_wp_grp_sz); + part_size *= (hc_erase_grp_sz * hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, @@ -362,7 +361,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; - unsigned int part_size; + u64 part_size; struct device_node *np; bool broken_hpi = false; diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 2d2d9ea8be4f..3dba15bccce2 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -119,7 +119,14 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = { END_FIXUP }; + static const struct mmc_fixup sdio_fixup_methods[] = { + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_DISABLE_CD), + SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 26cabd53ddc5..ebb387aa5158 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1048,9 +1048,35 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host) return ret; } +/* + * SDIO HW reset + * + * Returns 0 if the HW reset was executed synchronously, returns 1 if the HW + * reset was asynchronously scheduled, else a negative error code. + */ static int mmc_sdio_hw_reset(struct mmc_host *host) { - mmc_power_cycle(host, host->card->ocr); + struct mmc_card *card = host->card; + + /* + * In case the card is shared among multiple func drivers, reset the + * card through a rescan work. In this way it will be removed and + * re-detected, thus all func drivers becomes informed about it. + */ + if (atomic_read(&card->sdio_funcs_probed) > 1) { + if (mmc_card_removed(card)) + return 1; + host->rescan_entered = 0; + mmc_card_set_removed(card); + _mmc_detect_change(host, 0, false); + return 1; + } + + /* + * A single func driver has been probed, then let's skip the heavy + * hotplug dance above and execute the reset immediately. + */ + mmc_power_cycle(host, card->ocr); return mmc_sdio_reinit_card(host); } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2963e6542958..3cc928282af7 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -138,6 +138,8 @@ static int sdio_bus_probe(struct device *dev) if (ret) return ret; + atomic_inc(&func->card->sdio_funcs_probed); + /* Unbound SDIO functions are always suspended. * During probe, the function is set active and the usage count * is incremented. If the driver supports runtime PM, @@ -153,7 +155,10 @@ static int sdio_bus_probe(struct device *dev) /* Set the default block size so the driver is sure it's something * sensible. */ sdio_claim_host(func); - ret = sdio_set_block_size(func, 0); + if (mmc_card_removed(func->card)) + ret = -ENOMEDIUM; + else + ret = sdio_set_block_size(func, 0); sdio_release_host(func); if (ret) goto disable_runtimepm; @@ -165,6 +170,7 @@ static int sdio_bus_probe(struct device *dev) return 0; disable_runtimepm: + atomic_dec(&func->card->sdio_funcs_probed); if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) pm_runtime_put_noidle(dev); dev_pm_domain_detach(dev, false); @@ -181,6 +187,7 @@ static int sdio_bus_remove(struct device *dev) pm_runtime_get_sync(dev); drv->remove(func); + atomic_dec(&func->card->sdio_funcs_probed); if (func->irq_handler) { pr_warn("WARNING: driver %s did not remove its interrupt handler!\n", diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 49ea02c467bf..d06b2dfe3c95 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -159,6 +159,7 @@ config MMC_SDHCI_OF_ASPEED tristate "SDHCI OF support for the ASPEED SDHCI controller" depends on MMC_SDHCI_PLTFM depends on OF && OF_ADDRESS + select MMC_SDHCI_IO_ACCESSORS help This selects the ASPEED Secure Digital Host Controller Interface. @@ -368,6 +369,17 @@ config MMC_SDHCI_F_SDH30 If unsure, say N. +config MMC_SDHCI_MILBEAUT + tristate "SDHCI support for Socionext Milbeaut Serieas using F_SDH30" + depends on MMC_SDHCI_PLTFM + depends on OF + help + This selects the Secure Digital Host Controller Interface (SDHCI) + Needed by Milbeaut SoC for MMC / SD / SDIO support. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_IPROC tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller" depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST @@ -1011,6 +1023,7 @@ config MMC_SDHCI_AM654 tristate "Support for the SDHCI Controller in TI's AM654 SOCs" depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO select MMC_SDHCI_IO_ACCESSORS + select MMC_CQHCI help This selects the Secure Digital Host Controller Interface (SDHCI) support present in TI's AM654 SOCs. The controller supports @@ -1019,3 +1032,11 @@ config MMC_SDHCI_AM654 If you have a controller with this interface, say Y or M here. If unsure, say N. + +config MMC_OWL + tristate "Actions Semi Owl SD/MMC Host Controller support" + depends on HAS_DMA + depends on ARCH_ACTIONS || COMPILE_TEST + help + This selects support for the SD/MMC Host Controller on + Actions Semi Owl SoCs. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 11c4598e91d9..21d9089e5eda 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o +obj-$(CONFIG_MMC_SDHCI_MILBEAUT) += sdhci-milbeaut.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_SDHCI_AM654) += sdhci_am654.o obj-$(CONFIG_MMC_WBSD) += wbsd.o @@ -73,6 +74,7 @@ obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o obj-$(CONFIG_MMC_BCM2835) += bcm2835.o +obj-$(CONFIG_MMC_OWL) += owl-mmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index c26fbe5f2222..581b99f9e113 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2347,8 +2347,7 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, static int atmci_configure_dma(struct atmel_mci *host) { - host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, - "rxtx"); + host->dma.chan = dma_request_chan(&host->pdev->dev, "rxtx"); if (PTR_ERR(host->dma.chan) == -ENODEV) { struct mci_platform_data *pdata = host->pdev->dev.platform_data; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 148414d7f0c9..99f61fd2a658 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1357,7 +1357,6 @@ static int bcm2835_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct clk *clk; - struct resource *iomem; struct bcm2835_host *host; struct mmc_host *mmc; const __be32 *regaddr_p; @@ -1373,8 +1372,7 @@ static int bcm2835_probe(struct platform_device *pdev) host->pdev = pdev; spin_lock_init(&host->lock); - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->ioaddr = devm_ioremap_resource(dev, iomem); + host->ioaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(host->ioaddr)) { ret = PTR_ERR(host->ioaddr); goto err; diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index 22aded1065ae..916746c6c2c7 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -148,7 +148,6 @@ static int octeon_mmc_probe(struct platform_device *pdev) { struct device_node *cn, *node = pdev->dev.of_node; struct cvm_mmc_host *host; - struct resource *res; void __iomem *base; int mmc_irq[9]; int i, ret = 0; @@ -205,23 +204,13 @@ static int octeon_mmc_probe(struct platform_device *pdev) host->last_slot = -1; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Platform resource[0] is missing\n"); - return -ENXIO; - } - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); host->base = (void __iomem *)base; host->reg_off = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "Platform resource[1] is missing\n"); - return -EINVAL; - } - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(base)) return PTR_ERR(base); host->dma_base = (void __iomem *)base; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 79c55c7b4afd..bf0048ebbda3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3441,8 +3441,8 @@ int dw_mci_runtime_resume(struct device *dev) * Restore the initial value at FIFOTH register * And Invalidate the prev_blksz with zero */ - mci_writel(host, FIFOTH, host->fifoth_val); - host->prev_blksz = 0; + mci_writel(host, FIFOTH, host->fifoth_val); + host->prev_blksz = 0; /* Put in max timeout */ mci_writel(host, TMOUT, 0xFFFFFFFF); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index f816c06ef916..78383f60a3dc 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -41,6 +41,7 @@ #define JZ_REG_MMC_RESP_FIFO 0x34 #define JZ_REG_MMC_RXFIFO 0x38 #define JZ_REG_MMC_TXFIFO 0x3C +#define JZ_REG_MMC_LPM 0x40 #define JZ_REG_MMC_DMAC 0x44 #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) @@ -77,6 +78,8 @@ #define JZ_MMC_CMDAT_IO_ABORT BIT(11) #define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) +#define JZ_MMC_CMDAT_BUS_WIDTH_8BIT (BIT(10) | BIT(9)) +#define JZ_MMC_CMDAT_BUS_WIDTH_MASK (BIT(10) | BIT(9)) #define JZ_MMC_CMDAT_DMA_EN BIT(8) #define JZ_MMC_CMDAT_INIT BIT(7) #define JZ_MMC_CMDAT_BUSY BIT(6) @@ -98,12 +101,20 @@ #define JZ_MMC_DMAC_DMA_SEL BIT(1) #define JZ_MMC_DMAC_DMA_EN BIT(0) +#define JZ_MMC_LPM_DRV_RISING BIT(31) +#define JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY BIT(31) +#define JZ_MMC_LPM_DRV_RISING_1NS_DLY BIT(30) +#define JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY BIT(29) +#define JZ_MMC_LPM_LOW_POWER_MODE_EN BIT(0) + #define JZ_MMC_CLK_RATE 24000000 enum jz4740_mmc_version { JZ_MMC_JZ4740, JZ_MMC_JZ4725B, + JZ_MMC_JZ4760, JZ_MMC_JZ4780, + JZ_MMC_X1000, }; enum jz4740_mmc_state { @@ -852,6 +863,22 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) } writew(div, host->base + JZ_REG_MMC_CLKRT); + + if (real_rate > 25000000) { + if (host->version >= JZ_MMC_X1000) { + writel(JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY | + JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY | + JZ_MMC_LPM_LOW_POWER_MODE_EN, + host->base + JZ_REG_MMC_LPM); + } else if (host->version >= JZ_MMC_JZ4760) { + writel(JZ_MMC_LPM_DRV_RISING | + JZ_MMC_LPM_LOW_POWER_MODE_EN, + host->base + JZ_REG_MMC_LPM); + } else if (host->version >= JZ_MMC_JZ4725B) + writel(JZ_MMC_LPM_LOW_POWER_MODE_EN, + host->base + JZ_REG_MMC_LPM); + } + return real_rate; } @@ -895,11 +922,16 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->bus_width) { case MMC_BUS_WIDTH_1: - host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; + host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK; break; case MMC_BUS_WIDTH_4: + host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK; host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; break; + case MMC_BUS_WIDTH_8: + host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK; + host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_8BIT; + break; default: break; } @@ -924,7 +956,9 @@ static const struct mmc_host_ops jz4740_mmc_ops = { static const struct of_device_id jz4740_mmc_of_match[] = { { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 }, { .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B }, + { .compatible = "ingenic,jz4760-mmc", .data = (void *) JZ_MMC_JZ4760 }, { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 }, + { .compatible = "ingenic,x1000-mmc", .data = (void *) JZ_MMC_X1000 }, {}, }; MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match); @@ -1025,11 +1059,12 @@ static int jz4740_mmc_probe(struct platform_device* pdev) dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); goto err_release_dma; } - dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); + dev_info(&pdev->dev, "Ingenic SD/MMC card driver registered\n"); dev_info(&pdev->dev, "Using %s, %d-bit mode\n", host->use_dma ? "DMA" : "PIO", - (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); + (mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : + ((mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1)); return 0; |
