Commit 85579ad7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.3' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Fix a race condition in the request handling
   - Skip trim commands for some buggy kingston eMMCs
   - An optimization and a correction for erase groups
   - Set CMD23 quirk for some Sandisk cards

  MMC host:
   - sdhci: Give GPIO CD higher precedence and don't poll when it's used
   - sdhci: Fix DMA memory leakage
   - sdhci: Some updates for clock management
   - sdhci-of-at91: introduce driver for the Atmel SDMMC
   - sdhci-of-arasan: Add support for sdhci-5.1
   - sdhci-esdhc-imx: Add support for imx7d which also supports HS400
   - sdhci: A collection of fixes and improvements for various sdhci hosts
   - omap_hsmmc: Modernization of the regulator code
   - dw_mmc: A couple of fixes for DMA and PIO mode
   - usdhi6rol0: A few fixes and support probe deferral for regulators
   - pxamci: Convert to use dmaengine
   - sh_mmcif: Fix the suspend process in a short term solution
   - tmio: Adjust timeout for commands
   - sunxi: Fix timeout while gating/ungating clock"

* tag 'mmc-v4.3' of git://git.linaro.org/people/ulf.hansson/mmc: (67 commits)
  mmc: android-goldfish: remove incorrect __iomem annotation
  mmc: core: fix race condition in mmc_wait_data_done
  mmc: host: omap_hsmmc: remove CONFIG_REGULATOR check
  mmc: host: omap_hsmmc: use ios->vdd for setting vmmc voltage
  mmc: host: omap_hsmmc: use regulator_is_enabled to find pbias status
  mmc: host: omap_hsmmc: enable/disable vmmc_aux regulator based on previous state
  mmc: host: omap_hsmmc: don't use ->set_power to set initial regulator state
  mmc: host: omap_hsmmc: avoid pbias regulator enable on power off
  mmc: host: omap_hsmmc: add separate function to set pbias
  mmc: host: omap_hsmmc: add separate functions for enable/disable supply
  mmc: host: omap_hsmmc: return error if any of the regulator APIs fail
  mmc: host: omap_hsmmc: remove unnecessary pbias set_voltage
  mmc: host: omap_hsmmc: use mmc_host's vmmc and vqmmc
  mmc: host: omap_hsmmc: use the ocrmask provided by the vmmc regulator
  mmc: host: omap_hsmmc: cleanup omap_hsmmc_reg_get()
  mmc: host: omap_hsmmc: return on fatal errors from omap_hsmmc_reg_get
  mmc: host: omap_hsmmc: use devm_regulator_get_optional() for vmmc
  mmc: sdhci-of-at91: fix platform_no_drv_owner.cocci warnings
  mmc: sh_mmcif: Fix suspend process
  mmc: usdhi6rol0: fix error return code
  ...
parents 3af6e98f 092b6dbe
...@@ -9,7 +9,7 @@ Device Tree Bindings for the Arasan SDHCI Controller ...@@ -9,7 +9,7 @@ Device Tree Bindings for the Arasan SDHCI Controller
Required Properties: Required Properties:
- compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
'arasan,sdhci-4.9a' 'arasan,sdhci-4.9a' or 'arasan,sdhci-5.1'
- reg: From mmc bindings: Register location and length. - reg: From mmc bindings: Register location and length.
- clocks: From clock bindings: Handles to clock inputs. - clocks: From clock bindings: Handles to clock inputs.
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
......
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
"fsl,imx6q-usdhc" "fsl,imx6q-usdhc"
"fsl,imx6sl-usdhc" "fsl,imx6sl-usdhc"
"fsl,imx6sx-usdhc" "fsl,imx6sx-usdhc"
"fsl,imx7d-usdhc"
Optional properties: Optional properties:
- fsl,wp-controller : Indicate to use controller internal write protection - fsl,wp-controller : Indicate to use controller internal write protection
...@@ -27,6 +28,11 @@ Optional properties: ...@@ -27,6 +28,11 @@ Optional properties:
transparent level shifters on the outputs of the controller. Two cells are transparent level shifters on the outputs of the controller. Two cells are
required, first cell specifies minimum slot voltage (mV), second cell required, first cell specifies minimum slot voltage (mV), second cell
specifies maximum slot voltage (mV). Several ranges could be specified. specifies maximum slot voltage (mV). Several ranges could be specified.
- fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure.
The uSDHC use one delay cell as default increasing step to do tuning process.
This property allows user to change the tuning step to more than one delay
cells which is useful for some special boards or cards when the default
tuning step can't find the proper delay window within limited tuning retries.
Examples: Examples:
......
* Atmel SDHCI controller
This file documents the differences between the core properties in
Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the
sdhci-of-at91 driver.
Required properties:
- compatible: Must be "atmel,sama5d2-sdhci".
- clocks: Phandlers to the clocks.
- clock-names: Must be "hclock", "multclk", "baseclk";
Example:
sdmmc0: sdio-host@a0000000 {
compatible = "atmel,sama5d2-sdhci";
reg = <0xa0000000 0x300>;
interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>;
clock-names = "hclock", "multclk", "baseclk";
};
...@@ -102,7 +102,7 @@ not every application needs SDIO irq, e.g. MMC cards. ...@@ -102,7 +102,7 @@ not every application needs SDIO irq, e.g. MMC cards.
pinctrl-1 = <&mmc1_idle>; pinctrl-1 = <&mmc1_idle>;
pinctrl-2 = <&mmc1_sleep>; pinctrl-2 = <&mmc1_sleep>;
... ...
interrupts-extended = <&intc 64 &gpio2 28 0>; interrupts-extended = <&intc 64 &gpio2 28 GPIO_ACTIVE_LOW>;
}; };
mmc1_idle : pinmux_cirq_pin { mmc1_idle : pinmux_cirq_pin {
......
...@@ -1905,6 +1905,12 @@ L: linux-mtd@lists.infradead.org ...@@ -1905,6 +1905,12 @@ L: linux-mtd@lists.infradead.org
S: Supported S: Supported
F: drivers/mtd/nand/atmel_nand* F: drivers/mtd/nand/atmel_nand*
ATMEL SDMMC DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
L: linux-mmc@vger.kernel.org
S: Supported
F: drivers/mmc/host/sdhci-of-at91.c
ATMEL SPI DRIVER ATMEL SPI DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com> M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported S: Supported
......
...@@ -47,10 +47,13 @@ ...@@ -47,10 +47,13 @@
#include "queue.h" #include "queue.h"
MODULE_ALIAS("mmc:block"); MODULE_ALIAS("mmc:block");
#ifdef KERNEL
#ifdef MODULE_PARAM_PREFIX #ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX
#endif #endif
#define MODULE_PARAM_PREFIX "mmcblk." #define MODULE_PARAM_PREFIX "mmcblk."
#endif
#define INAND_CMD38_ARG_EXT_CSD 113 #define INAND_CMD38_ARG_EXT_CSD 113
#define INAND_CMD38_ARG_ERASE 0x00 #define INAND_CMD38_ARG_ERASE 0x00
...@@ -2386,6 +2389,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) ...@@ -2386,6 +2389,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
#define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_TOSHIBA 0x11
#define CID_MANFID_MICRON 0x13 #define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15 #define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_KINGSTON 0x70
static const struct mmc_fixup blk_fixups[] = static const struct mmc_fixup blk_fixups[] =
{ {
...@@ -2408,6 +2412,10 @@ static const struct mmc_fixup blk_fixups[] = ...@@ -2408,6 +2412,10 @@ static const struct mmc_fixup blk_fixups[] =
* *
* N.B. This doesn't affect SD cards. * N.B. This doesn't affect SD cards.
*/ */
MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23), MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
...@@ -2444,6 +2452,15 @@ static const struct mmc_fixup blk_fixups[] = ...@@ -2444,6 +2452,15 @@ static const struct mmc_fixup blk_fixups[] =
MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
/*
* On Some Kingston eMMCs, performing trim can result in
* unrecoverable data conrruption occasionally due to a firmware bug.
*/
MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
END_FIXUP END_FIXUP
}; };
......
...@@ -358,8 +358,10 @@ EXPORT_SYMBOL(mmc_start_bkops); ...@@ -358,8 +358,10 @@ EXPORT_SYMBOL(mmc_start_bkops);
*/ */
static void mmc_wait_data_done(struct mmc_request *mrq) static void mmc_wait_data_done(struct mmc_request *mrq)
{ {
mrq->host->context_info.is_done_rcv = true; struct mmc_context_info *context_info = &mrq->host->context_info;
wake_up_interruptible(&mrq->host->context_info.wait);
context_info->is_done_rcv = true;
wake_up_interruptible(&context_info->wait);
} }
static void mmc_wait_done(struct mmc_request *mrq) static void mmc_wait_done(struct mmc_request *mrq)
...@@ -2168,6 +2170,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, ...@@ -2168,6 +2170,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
unsigned int arg) unsigned int arg)
{ {
unsigned int rem, to = from + nr; unsigned int rem, to = from + nr;
int err;
if (!(card->host->caps & MMC_CAP_ERASE) || if (!(card->host->caps & MMC_CAP_ERASE) ||
!(card->csd.cmdclass & CCC_ERASE)) !(card->csd.cmdclass & CCC_ERASE))
...@@ -2218,6 +2221,22 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, ...@@ -2218,6 +2221,22 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
/* 'from' and 'to' are inclusive */ /* 'from' and 'to' are inclusive */
to -= 1; to -= 1;
/*
* Special case where only one erase-group fits in the timeout budget:
* If the region crosses an erase-group boundary on this particular
* case, we will be trimming more than one erase-group which, does not
* fit in the timeout budget of the controller, so we need to split it
* and call mmc_do_erase() twice if necessary. This special case is
* identified by the card->eg_boundary flag.
*/
rem = card->erase_size - (from % card->erase_size);
if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
err = mmc_do_erase(card, from, from + rem - 1, arg);
from += rem;
if ((err) || (to <= from))
return err;
}
return mmc_do_erase(card, from, to, arg); return mmc_do_erase(card, from, to, arg);
} }
EXPORT_SYMBOL(mmc_erase); EXPORT_SYMBOL(mmc_erase);
...@@ -2233,7 +2252,8 @@ EXPORT_SYMBOL(mmc_can_erase); ...@@ -2233,7 +2252,8 @@ EXPORT_SYMBOL(mmc_can_erase);
int mmc_can_trim(struct mmc_card *card) int mmc_can_trim(struct mmc_card *card)
{ {
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) &&
(!(card->quirks & MMC_QUIRK_TRIM_BROKEN)))
return 1; return 1;
return 0; return 0;
} }
...@@ -2313,16 +2333,28 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, ...@@ -2313,16 +2333,28 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
if (!qty) if (!qty)
return 0; return 0;
/*
* When specifying a sector range to trim, chances are we might cross
* an erase-group boundary even if the amount of sectors is less than
* one erase-group.
* If we can only fit one erase-group in the controller timeout budget,
* we have to care that erase-group boundaries are not crossed by a
* single trim operation. We flag that special case with "eg_boundary".
* In all other cases we can just decrement qty and pretend that we
* always touch (qty + 1) erase-groups as a simple optimization.
*/
if (qty == 1) if (qty == 1)
return 1; card->eg_boundary = 1;
else
qty--;
/* Convert qty to sectors */ /* Convert qty to sectors */
if (card->erase_shift) if (card->erase_shift)
max_discard = --qty << card->erase_shift; max_discard = qty << card->erase_shift;
else if (mmc_card_sd(card)) else if (mmc_card_sd(card))
max_discard = qty; max_discard = qty + 1;
else else
max_discard = --qty * card->erase_size; max_discard = qty * card->erase_size;
return max_discard; return max_discard;
} }
......
...@@ -398,7 +398,7 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -398,7 +398,7 @@ int mmc_of_parse(struct mmc_host *host)
{ {
struct device_node *np; struct device_node *np;
u32 bus_width; u32 bus_width;
int len, ret; int ret;
bool cd_cap_invert, cd_gpio_invert = false; bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false;
...@@ -445,12 +445,12 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -445,12 +445,12 @@ int mmc_of_parse(struct mmc_host *host)
*/ */
/* Parse Card Detection */ /* Parse Card Detection */
if (of_find_property(np, "non-removable", &len)) { if (of_property_read_bool(np, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE; host->caps |= MMC_CAP_NONREMOVABLE;
} else { } else {
cd_cap_invert = of_property_read_bool(np, "cd-inverted"); cd_cap_invert = of_property_read_bool(np, "cd-inverted");
if (of_find_property(np, "broken-cd", &len)) if (of_property_read_bool(np, "broken-cd"))
host->caps |= MMC_CAP_NEEDS_POLL; host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true, ret = mmc_gpiod_request_cd(host, "cd", 0, true,
...@@ -491,41 +491,41 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -491,41 +491,41 @@ int mmc_of_parse(struct mmc_host *host)
if (ro_cap_invert ^ ro_gpio_invert) if (ro_cap_invert ^ ro_gpio_invert)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
if (of_find_property(np, "cap-sd-highspeed", &len)) if (of_property_read_bool(np, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED; host->caps |= MMC_CAP_SD_HIGHSPEED;
if (of_find_property(np, "cap-mmc-highspeed", &len)) if (of_property_read_bool(np, "cap-mmc-highspeed"))
host->caps |= MMC_CAP_MMC_HIGHSPEED; host->caps |= MMC_CAP_MMC_HIGHSPEED;
if (of_find_property(np, "sd-uhs-sdr12", &len)) if (of_property_read_bool(np, "sd-uhs-sdr12"))
host->caps |= MMC_CAP_UHS_SDR12; host->caps |= MMC_CAP_UHS_SDR12;
if (of_find_property(np, "sd-uhs-sdr25", &len)) if (of_property_read_bool(np, "sd-uhs-sdr25"))
host->caps |= MMC_CAP_UHS_SDR25; host->caps |= MMC_CAP_UHS_SDR25;
if (of_find_property(np, "sd-uhs-sdr50", &len)) if (of_property_read_bool(np, "sd-uhs-sdr50"))
host->caps |= MMC_CAP_UHS_SDR50; host->caps |= MMC_CAP_UHS_SDR50;
if (of_find_property(np, "sd-uhs-sdr104", &len)) if (of_property_read_bool(np, "sd-uhs-sdr104"))
host->caps |= MMC_CAP_UHS_SDR104; host->caps |= MMC_CAP_UHS_SDR104;
if (of_find_property(np, "sd-uhs-ddr50", &len)) if (of_property_read_bool(np, "sd-uhs-ddr50"))
host->caps |= MMC_CAP_UHS_DDR50; host->caps |= MMC_CAP_UHS_DDR50;
if (of_find_property(np, "cap-power-off-card", &len)) if (of_property_read_bool(np, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD; host->caps |= MMC_CAP_POWER_OFF_CARD;
if (of_find_property(np, "cap-sdio-irq", &len)) if (of_property_read_bool(np, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ; host->caps |= MMC_CAP_SDIO_IRQ;
if (of_find_property(np, "full-pwr-cycle", &len)) if (of_property_read_bool(np, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_find_property(np, "keep-power-in-suspend", &len)) if (of_property_read_bool(np, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER; host->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", &len)) if (of_property_read_bool(np, "enable-sdio-wakeup"))
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
if (of_find_property(np, "mmc-ddr-1_8v", &len)) if (of_property_read_bool(np, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR; host->caps |= MMC_CAP_1_8V_DDR;
if (of_find_property(np, "mmc-ddr-1_2v", &len)) if (of_property_read_bool(np, "mmc-ddr-1_2v"))
host->caps |= MMC_CAP_1_2V_DDR; host->caps |= MMC_CAP_1_2V_DDR;
if (of_find_property(np, "mmc-hs200-1_8v", &len)) if (of_property_read_bool(np, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "mmc-hs200-1_2v", &len)) if (of_property_read_bool(np, "mmc-hs200-1_2v"))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
if (of_find_property(np, "mmc-hs400-1_8v", &len)) if (of_property_read_bool(np, "mmc-hs400-1_8v"))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR; host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "mmc-hs400-1_2v", &len)) if (of_property_read_bool(np, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr); host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
......
...@@ -129,6 +129,14 @@ config MMC_SDHCI_OF_ARASAN ...@@ -129,6 +129,14 @@ config MMC_SDHCI_OF_ARASAN
If unsure, say N. If unsure, say N.
config MMC_SDHCI_OF_AT91
tristate "SDHCI OF support for the Atmel SDMMC controller"
depends on MMC_SDHCI_PLTFM
depends on OF
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Atmel SDMMC driver
config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller" tristate "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
......
...@@ -67,6 +67,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o ...@@ -67,6 +67,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
......
...@@ -118,7 +118,7 @@ struct goldfish_mmc_host { ...@@ -118,7 +118,7 @@ struct goldfish_mmc_host {
struct mmc_host *mmc; struct mmc_host *mmc;
struct device *dev; struct device *dev;
unsigned char id; /* 16xx chips have 2 MMC blocks */ unsigned char id; /* 16xx chips have 2 MMC blocks */
void __iomem *virt_base; void *virt_base;
unsigned int phys_base; unsigned int phys_base;
int irq; int irq;
unsigned char bus_mode; unsigned char bus_mode;
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/platform_data/atmel.h>
#include <linux/platform_data/mmc-atmel-mci.h> #include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
......
...@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host) ...@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* It is slot 8 on Rockchip SoCs */ /* It is slot 8 on Rockchip SoCs */
host->sdio_id0 = 8; host->sdio_id0 = 8;
/* It needs this quirk on all Rockchip SoCs */
host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO;
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -948,6 +948,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) ...@@ -948,6 +948,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
{ {
struct mmc_data *data = req->data; struct mmc_data *data = req->data;
int i, use_dma = 1, block_size; int i, use_dma = 1, block_size;
struct scatterlist *sg;
unsigned sg_len; unsigned sg_len;
host->data = data; host->data = data;
...@@ -972,8 +973,8 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) ...@@ -972,8 +973,8 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
sg_len = (data->blocks == 1) ? 1 : data->sg_len; sg_len = (data->blocks == 1) ? 1 : data->sg_len;
/* Only do DMA for entire blocks */ /* Only do DMA for entire blocks */
for (i = 0; i < sg_len; i++) { for_each_sg(data->sg, sg, sg_len, i) {
if ((data->sg[i].length % block_size) != 0) { if ((sg->length % block_size) != 0) {
use_dma = 0; use_dma = 0;
break; break;
} }
...@@ -1419,8 +1420,10 @@ static int mmc_omap_probe(struct platform_device *pdev) ...@@ -1419,8 +1420,10 @@ static int mmc_omap_probe(struct platform_device *pdev)
host->reg_shift = (mmc_omap7xx() ? 1 : 2); host->reg_shift = (mmc_omap7xx() ? 1 : 2);
host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0);
if (!host->mmc_omap_wq) if (!host->mmc_omap_wq) {
ret = -ENOMEM;
goto err_plat_cleanup; goto err_plat_cleanup;
}
for (i = 0; i < pdata->nr_slots; i++) { for (i = 0; i < pdata->nr_slots; i++) {
ret = mmc_omap_new_slot(host, i); ret = mmc_omap_new_slot(host, i);
......
This diff is collapsed.
This diff is collapsed.
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "sdhci-esdhc.h" #include "sdhci-esdhc.h"
#define ESDHC_CTRL_D3CD 0x08 #define ESDHC_CTRL_D3CD 0x08
#define ESDHC_BURST_LEN_EN_INCR (1 << 27)
/* VENDOR SPEC register */ /* VENDOR SPEC register */
#define ESDHC_VENDOR_SPEC 0xc0 #define ESDHC_VENDOR_SPEC 0xc0
#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
#define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22) #define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22)
#define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23) #define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23)
#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
#define ESDHC_MIX_CTRL_HS400_EN (1 << 26)
/* Bits 3 and 6 are not SDHCI standard definitions */ /* Bits 3 and 6 are not SDHCI standard definitions */
#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
/* Tuning bits */ /* Tuning bits */
...@@ -60,10 +62,21 @@ ...@@ -60,10 +62,21 @@
#define ESDHC_TUNE_CTRL_MIN 0 #define ESDHC_TUNE_CTRL_MIN 0
#define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1)
/* strobe dll register */
#define ESDHC_STROBE_DLL_CTRL 0x70
#define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0)
#define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1)
#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3
#define ESDHC_STROBE_DLL_STATUS 0x74
#define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1)
#define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1
#define ESDHC_TUNING_CTRL 0xcc #define ESDHC_TUNING_CTRL 0xcc
#define ESDHC_STD_TUNING_EN (1 << 24) #define ESDHC_STD_TUNING_EN (1 << 24)
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1 #define ESDHC_TUNING_START_TAP 0x1
#define ESDHC_TUNING_STEP_SHIFT 16
/* pinctrl state */ /* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
...@@ -120,6 +133,11 @@ ...@@ -120,6 +133,11 @@
#define ESDHC_FLAG_ERR004536 BIT(7) #define ESDHC_FLAG_ERR004536 BIT(7)
/* The IP supports HS200 mode */ /* The IP supports HS200 mode */
#define ESDHC_FLAG_HS200 BIT(8) #define ESDHC_FLAG_HS200 BIT(8)
/* The IP supports HS400 mode */
#define ESDHC_FLAG_HS400 BIT(9)
/* A higher clock ferquency than this rate requires strobell dll control */
#define ESDHC_STROBE_DLL_CLK_FREQ 100000000
struct esdhc_soc_data { struct esdhc_soc_data {
u32 flags; u32 flags;
...@@ -156,6 +174,12 @@ static struct esdhc_soc_data usdhc_imx6sx_data = { ...@@ -156,6 +174,12 @@ static struct esdhc_soc_data usdhc_imx6sx_data = {
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
}; };
static struct esdhc_soc_data usdhc_imx7d_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_HS400,
};
struct pltfm_imx_data { struct pltfm_imx_data {
u32 scratchpad; u32 scratchpad;
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
...@@ -199,6 +223,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { ...@@ -199,6 +223,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
...@@ -274,6 +299,9 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) ...@@ -274,6 +299,9 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
| SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR50
| SDHCI_USE_SDR50_TUNING; | SDHCI_USE_SDR50_TUNING;
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
val |= SDHCI_SUPPORT_HS400;
} }
} }
...@@ -448,6 +476,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -448,6 +476,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
u32 tuning_ctrl;
if (val & SDHCI_CTRL_TUNED_CLK) { if (val & SDHCI_CTRL_TUNED_CLK) {
v |= ESDHC_MIX_CTRL_SMPCLK_SEL; v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
} else { } else {
...@@ -458,6 +487,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -458,6 +487,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
if (val & SDHCI_CTRL_EXEC_TUNING) { if (val & SDHCI_CTRL_EXEC_TUNING) {
v |= ESDHC_MIX_CTRL_EXE_TUNE; v |= ESDHC_MIX_CTRL_EXE_TUNE;
m |= ESDHC_MIX_CTRL_FBCLK_SEL; m |= ESDHC_MIX_CTRL_FBCLK_SEL;
tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
if (imx_data->boarddata.tuning_step)
tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
} else { } else {
v &= ~ESDHC_MIX_CTRL_EXE_TUNE; v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
} }
...@@ -774,6 +808,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host, ...@@ -774,6 +808,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
break; break;
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
case MMC_TIMING_MMC_HS400:
pinctrl = imx_data->pins_200mhz; pinctrl = imx_data->pins_200mhz;
break; break;
default: default:
...@@ -784,24 +819,68 @@ static int esdhc_change_pinstate(struct sdhci_host *host, ...@@ -784,24 +819,68 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
return pinctrl_select_state(imx_data->pinctrl, pinctrl); return pinctrl_select_state(imx_data->pinctrl, pinctrl);
} }
/*
* For HS400 eMMC, there is a data_strobe line, this signal is generated
* by the device and used for data output and CRC status response output
* in HS400 mode. The frequency of this signal follows the frequency of
* CLK generated by host. Host receive the data which is aligned to the
* edge of data_strobe line. Due to the time delay between CLK line and
* data_strobe line, if the delay time is larger than one clock cycle,
* then CLK and data_strobe line will misaligned, read error shows up.
* So when the CLK is higher than 100MHz, each clock cycle is short enough,
* host should config the delay target.
*/
static void esdhc_set_strobe_dll(struct sdhci_host *host)
{
u32 v;
if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
/* force a reset on strobe dll */
writel(ESDHC_STROBE_DLL_CTRL_RESET,
host->ioaddr + ESDHC_STROBE_DLL_CTRL);
/*
* enable strobe dll ctrl and adjust the delay target
* for the uSDHC loopback read clock
*/
v = ESDHC_STROBE_DLL_CTRL_ENABLE |
(7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
/* wait 1us to make sure strobe dll status register stable */
udelay(1);
v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
dev_warn(mmc_dev(host->mmc),
"warning! HS400 strobe DLL status REF not lock!\n");
if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
dev_warn(mmc_dev(host->mmc),
"warning! HS400 strobe DLL status SLV not lock!\n");
}
}
static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{ {
u32 m;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = pltfm_host->priv;
struct esdhc_platform_data *boarddata = &imx_data->boarddata; struct esdhc_platform_data *boarddata = &imx_data->boarddata;
/* disable ddr mode and disable HS400 mode */
m = readl(host->ioaddr + ESDHC_MIX_CTRL);
m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN);
imx_data->is_ddr = 0;
switch (timing) { switch (timing) {
case MMC_TIMING_UHS_SDR12: case MMC_TIMING_UHS_SDR12:
case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_SDR25:
case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR50:
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
break; break;
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_MMC_DDR52: case MMC_TIMING_MMC_DDR52:
writel(readl(host->ioaddr + ESDHC_MIX_CTRL) | m |= ESDHC_MIX_CTRL_DDREN;
ESDHC_MIX_CTRL_DDREN, writel(m, host->ioaddr + ESDHC_MIX_CTRL);
host->ioaddr + ESDHC_MIX_CTRL);
imx_data->is_ddr = 1; imx_data->is_ddr = 1;
if (boarddata->delay_line) { if (boarddata->delay_line) {
u32 v; u32 v;
...@@ -813,6 +892,12 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) ...@@ -813,6 +892,12 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
writel(v, host->ioaddr + ESDHC_DLL_CTRL); writel(v, host->ioaddr + ESDHC_DLL_CTRL);
} }
break; break;
case MMC_TIMING_MMC_HS400:
m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
imx_data->is_ddr = 1;
esdhc_set_strobe_dll(host);
break;
} }
esdhc_change_pinstate(host, timing); esdhc_change_pinstate(host, timing);
...@@ -886,6 +971,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, ...@@ -886,6 +971,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
if (gpio_is_valid(boarddata->wp_gpio)) if (gpio_is_valid(boarddata->wp_gpio))
boarddata->wp_type = ESDHC_WP_GPIO; boarddata->wp_type = ESDHC_WP_GPIO;
of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
if (of_find_property(np, "no-1-8-v", NULL)) if (of_find_property(np, "no-1-8-v", NULL))
boarddata->support_vsel = false; boarddata->support_vsel = false;
else else
...@@ -1073,10 +1160,26 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1073,10 +1160,26 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
* to something insane. Change it back here. * to something insane. Change it back here.
*/ */
if (esdhc_is_usdhc(imx_data)) { if (esdhc_is_usdhc(imx_data)) {
writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->mmc->caps |= MMC_CAP_1_8V_DDR; host->mmc->caps |= MMC_CAP_1_8V_DDR;
/*
* ROM code will change the bit burst_length_enable setting
* to zero if this usdhc is choosed to boot system. Change
* it back here, otherwise it will impact the performance a
* lot. This bit is used to enable/disable the burst length
* for the external AHB2AXI bridge, it's usefully especially
* for INCR transfer because without burst length indicator,
* the AHB2AXI bridge does not know the burst length in
* advance. And without burst length indicator, AHB INCR
* transfer can only be converted to singles on the AXI side.
*/
writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
| ESDHC_BURST_LEN_EN_INCR,
host->ioaddr + SDHCI_HOST_CONTROL);
if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
...@@ -1100,6 +1203,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1100,6 +1203,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
if (of_id) if (of_id)
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
else else
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
SDHCI_QUIRK_NO_BUSY_IRQ | \ SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY) SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT)
#define ESDHC_SYSTEM_CONTROL 0x2c #define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_CLOCK_MASK 0x0000fff0
......
...@@ -489,6 +489,11 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -489,6 +489,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto pclk_disable; goto pclk_disable;
} }
/* Vote for maximum clock rate for maximum performance */
ret = clk_set_rate(msm_host->clk, INT_MAX);
if (ret)
dev_warn(&pdev->dev, "core clock boost failed\n");
ret = clk_prepare_enable(msm_host->clk); ret = clk_prepare_enable(msm_host->clk);
if (ret) if (ret)
goto pclk_disable; goto pclk_disable;
......
...@@ -63,6 +63,9 @@ static struct sdhci_ops sdhci_arasan_ops = { ...@@ -63,6 +63,9 @@ static struct sdhci_ops sdhci_arasan_ops = {
static struct sdhci_pltfm_data sdhci_arasan_pdata = { static struct sdhci_pltfm_data sdhci_arasan_pdata = {
.ops = &sdhci_arasan_ops, .ops = &sdhci_arasan_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
}; };
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -214,6 +217,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev) ...@@ -214,6 +217,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
static const struct of_device_id sdhci_arasan_of_match[] = { static const struct of_device_id sdhci_arasan_of_match[] = {
{ .compatible = "arasan,sdhci-8.9a" }, { .compatible = "arasan,sdhci-8.9a" },
{ .compatible = "arasan,sdhci-5.1" },
{ .compatible = "arasan,sdhci-4.9a" }, { .compatible = "arasan,sdhci-4.9a" },
{ } { }
}; };
......
/*
* Atmel SDMMC controller driver.
*
* Copyright (C) 2015 Atmel,
* 2015 Ludovic Desroches <ludovic.desroches@atmel.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci-pltfm.h"
#define SDMMC_CACR 0x230
#define SDMMC_CACR_CAPWREN BIT(0)
#define SDMMC_CACR_KEY (0x46 << 8)
struct sdhci_at91_priv {
struct clk *hclock;
struct clk *gck;
struct clk *mainck;
};
static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static const struct sdhci_pltfm_data soc_data_sama5d2 = {
.ops = &sdhci_at91_sama5d2_ops,
};
static const struct of_device_id sdhci_at91_dt_match[] = {
{ .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 },
{}
};
static int sdhci_at91_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct sdhci_pltfm_data *soc_data;
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_at91_priv *priv;
unsigned int caps0, caps1;
unsigned int clk_base, clk_mul;
unsigned int gck_rate, real_gck_rate;
int ret;
match = of_match_device(sdhci_at91_dt_match, &pdev->dev);
if (!match)
return -EINVAL;
soc_data = match->data;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "unable to allocate private data\n");
return -ENOMEM;
}
priv->mainck = devm_clk_get(&pdev->dev, "baseclk");
if (IS_ERR(priv->mainck)) {
dev_err(&pdev->dev, "failed to get baseclk\n");
return PTR_ERR(priv->mainck);
}
priv->hclock = devm_clk_get(&pdev->dev, "hclock");
if (IS_ERR(priv->hclock)) {
dev_err(&pdev->dev, "failed to get hclock\n");
return PTR_ERR(priv->hclock);
}
priv->gck = devm_clk_get(&pdev->dev, "multclk");
if (IS_ERR(priv->gck)) {
dev_err(&pdev->dev, "failed to get multclk\n");
return PTR_ERR(priv->gck);
}
host = sdhci_pltfm_init(pdev, soc_data, 0);
if (IS_ERR(host))
return PTR_ERR(host);
/*
* The mult clock is provided by as a generated clock by the PMC
* controller. In order to set the rate of gck, we have to get the
* base clock rate and the clock mult from capabilities.
*/
clk_prepare_enable(priv->hclock);
caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES);
caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1);
clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
gck_rate = clk_base * 1000000 * (clk_mul + 1);
ret = clk_set_rate(priv->gck, gck_rate);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set gck");
goto hclock_disable_unprepare;
return -EINVAL;
}
/*
* We need to check if we have the requested rate for gck because in
* some cases this rate could be not supported. If it happens, the rate
* is the closest one gck can provide. We have to update the value
* of clk mul.
*/
real_gck_rate = clk_get_rate(priv->gck);
if (real_gck_rate != gck_rate) {
clk_mul = real_gck_rate / (clk_base * 1000000) - 1;
caps1 &= (~SDHCI_CLOCK_MUL_MASK);
caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK);
/* Set capabilities in r/w mode. */
writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR);
writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1);
/* Set capabilities in ro mode. */
writel(0, host->ioaddr + SDMMC_CACR);
dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n",
clk_mul, real_gck_rate);
}
clk_prepare_enable(priv->mainck);
clk_prepare_enable(priv->gck);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
ret = mmc_of_parse(host->mmc);
if (ret)
goto clocks_disable_unprepare;
sdhci_get_of_property(pdev);
ret = sdhci_add_host(host);
if (ret)
goto clocks_disable_unprepare;
return 0;
clocks_disable_unprepare:
clk_disable_unprepare(priv->gck);
clk_disable_unprepare(priv->mainck);
hclock_disable_unprepare:
clk_disable_unprepare(priv->hclock);
sdhci_pltfm_free(pdev);
return ret;
}
static int sdhci_at91_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_at91_priv *priv = pltfm_host->priv;
sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(priv->gck);
clk_disable_unprepare(priv->hclock);
clk_disable_unprepare(priv->mainck);
return 0;
}
static struct platform_driver sdhci_at91_driver = {
.driver = {
.name = "sdhci-at91",
.of_match_table = sdhci_at91_dt_match,
.pm = SDHCI_PLTFM_PMOPS,
},
.probe = sdhci_at91_probe,
.remove = sdhci_at91_remove,
};
module_platform_driver(sdhci_at91_driver);
MODULE_DESCRIPTION("SDHCI driver for at91");
MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@atmel.com>");
MODULE_LICENSE("GPL v2");
...@@ -208,6 +208,12 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -208,6 +208,12 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0) if (clock == 0)
return; return;
/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
temp = esdhc_readw(host, SDHCI_HOST_VERSION);
temp = (temp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (temp < VENDOR_V_23)
pre_div = 2;
/* Workaround to reduce the clock frequency for p1010 esdhc */ /* Workaround to reduce the clock frequency for p1010 esdhc */
if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
if (clock > 20000000) if (clock > 20000000)
......
...@@ -618,6 +618,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) ...@@ -618,6 +618,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
static const struct sdhci_pci_fixes sdhci_o2 = { static const struct sdhci_pci_fixes sdhci_o2 = {
.probe = sdhci_pci_o2_probe, .probe = sdhci_pci_o2_probe,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD,
.probe_slot = sdhci_pci_o2_probe_slot, .probe_slot = sdhci_pci_o2_probe_slot,
.resume = sdhci_pci_o2_resume, .resume = sdhci_pci_o2_resume,
}; };
......
...@@ -161,8 +161,8 @@ static struct sdhci_pltfm_data sdhci_sirf_pdata = { ...@@ -161,8 +161,8 @@ static struct sdhci_pltfm_data sdhci_sirf_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT | SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
SDHCI_QUIRK_DELAY_AFTER_POWER, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
}; };
static int sdhci_sirf_probe(struct platform_device *pdev) static int sdhci_sirf_probe(struct platform_device *pdev)
......
...@@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *); ...@@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
static int sdhci_pre_dma_transfer(struct sdhci_host *host, static int sdhci_pre_dma_transfer(struct sdhci_host *host,
struct mmc_data *data, struct mmc_data *data);
struct sdhci_host_next *next);
static int sdhci_do_get_cd(struct sdhci_host *host); static int sdhci_do_get_cd(struct sdhci_host *host);
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -207,8 +206,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset); ...@@ -207,8 +206,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
static void sdhci_do_reset(struct sdhci_host *host, u8 mask) static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
{ {
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & if (!sdhci_do_get_cd(host))
SDHCI_CARD_PRESENT))
return; return;
} }
...@@ -496,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, ...@@ -496,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
goto fail; goto fail;
BUG_ON(host->align_addr & host->align_mask); BUG_ON(host->align_addr & host->align_mask);
host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); host->sg_count = sdhci_pre_dma_transfer(host, data);
if (host->sg_count < 0) if (host->sg_count < 0)
goto unmap_align; goto unmap_align;
...@@ -635,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, ...@@ -635,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
} }
} }
if (!data->host_cookie) if (data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, dma_unmap_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, direction); data->sg_len, direction);
data->host_cookie = COOKIE_UNMAPPED;
}
} }
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
...@@ -833,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) ...@@ -833,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} else { } else {
int sg_cnt; int sg_cnt;
sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); sg_cnt = sdhci_pre_dma_transfer(host, data);
if (sg_cnt <= 0) { if (sg_cnt <= 0) {
/* /*
* This only happens when someone fed * This only happens when someone fed
...@@ -949,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host) ...@@ -949,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host)
if (host->flags & SDHCI_USE_ADMA) if (host->flags & SDHCI_USE_ADMA)
sdhci_adma_table_post(host, data); sdhci_adma_table_post(host, data);
else { else {
if (!data->host_cookie) if (data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc), dma_unmap_sg(mmc_dev(host->mmc),
data->sg, data->sg_len, data->sg, data->sg_len,
(data->flags & MMC_DATA_READ) ? (data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE); DMA_FROM_DEVICE : DMA_TO_DEVICE);
data->host_cookie = COOKIE_UNMAPPED;
}
} }
} }
...@@ -1132,6 +1134,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) ...@@ -1132,6 +1134,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
break; break;
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_MMC_DDR52:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
break; break;
case MMC_TIMING_MMC_HS400: case MMC_TIMING_MMC_HS400:
...@@ -1152,6 +1155,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1152,6 +1155,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
int real_div = div, clk_mul = 1; int real_div = div, clk_mul = 1;
u16 clk = 0; u16 clk = 0;
unsigned long timeout; unsigned long timeout;
bool switch_base_clk = false;
host->mmc->actual_clock = 0; host->mmc->actual_clock = 0;
...@@ -1189,6 +1193,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1189,6 +1193,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
<= clock) <= clock)
break; break;
} }
if ((host->max_clk * host->clk_mul / div) <= clock) {
/* /*
* Set Programmable Clock Mode in the Clock * Set Programmable Clock Mode in the Clock
* Control register. * Control register.
...@@ -1198,6 +1203,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1198,6 +1203,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clk_mul = host->clk_mul; clk_mul = host->clk_mul;
div--; div--;
} else { } else {
/*
* Divisor can be too small to reach clock
* speed requirement. Then use the base clock.
*/
switch_base_clk = true;
}
}
if (!host->clk_mul || switch_base_clk) {
/* Version 3.00 divisors must be a multiple of 2. */ /* Version 3.00 divisors must be a multiple of 2. */
if (host->max_clk <= clock) if (host->max_clk <= clock)
div = 1; div = 1;
...@@ -1210,6 +1224,9 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1210,6 +1224,9 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
} }
real_div = div; real_div = div;
div >>= 1; div >>= 1;
if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
&& !div && host->max_clk <= 25000000)
div = 1;
} }
} else { } else {
/* Version 2.00 divisors must be a power of 2. */ /* Version 2.00 divisors must be a power of 2. */
...@@ -1559,7 +1576,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ...@@ -1559,7 +1576,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
(ios->timing == MMC_TIMING_UHS_SDR25) || (ios->timing == MMC_TIMING_UHS_SDR25) ||
(ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR50) ||
(ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_SDR104) ||
(ios->timing == MMC_TIMING_UHS_DDR50))) { (ios->timing == MMC_TIMING_UHS_DDR50) ||
(ios->timing == MMC_TIMING_MMC_DDR52))) {
u16 preset; u16 preset;
sdhci_enable_preset_value(host, true); sdhci_enable_preset_value(host, true);
...@@ -1601,15 +1619,21 @@ static int sdhci_do_get_cd(struct sdhci_host *host) ...@@ -1601,15 +1619,21 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
if (host->flags & SDHCI_DEVICE_DEAD) if (host->flags & SDHCI_DEVICE_DEAD)
return 0; return 0;
/* If polling/nonremovable, assume that the card is always present. */ /* If nonremovable, assume that the card is always present. */
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
(host->mmc->caps & MMC_CAP_NONREMOVABLE))
return 1; return 1;
/* Try slot gpio detect */ /*
* Try slot gpio detect, if defined it take precedence
* over build in controller functionality
*/
if (!IS_ERR_VALUE(gpio_cd)) if (!IS_ERR_VALUE(gpio_cd))
return !!gpio_cd; return !!gpio_cd;
/* If polling, assume that the card is always present. */
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
return 1;
/* Host native card detect */ /* Host native card detect */
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
} }
...@@ -2097,49 +2121,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, ...@@ -2097,49 +2121,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_REQ_USE_DMA) {
if (data->host_cookie) if (data->host_cookie == COOKIE_GIVEN ||
data->host_cookie == COOKIE_MAPPED)
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
data->flags & MMC_DATA_WRITE ? data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE); DMA_TO_DEVICE : DMA_FROM_DEVICE);
mrq->data->host_cookie = 0; data->host_cookie = COOKIE_UNMAPPED;
} }
} }
static int sdhci_pre_dma_transfer(struct sdhci_host *host, static int sdhci_pre_dma_transfer(struct sdhci_host *host,
struct mmc_data *data, struct mmc_data *data)
struct sdhci_host_next *next)
{ {
int sg_count; int sg_count;
if (!next && data->host_cookie && if (data->host_cookie == COOKIE_MAPPED) {
data->host_cookie != host->next_data.cookie) { data->host_cookie = COOKIE_GIVEN;
pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", return data->sg_count;
__func__, data->host_cookie, host->next_data.cookie);
data->host_cookie = 0;
} }
/* Check if next job is already prepared */ WARN_ON(data->host_cookie == COOKIE_GIVEN);
if (next ||
(!next && data->host_cookie != host->next_data.cookie)) { sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
data->sg_len,
data->flags & MMC_DATA_WRITE ? data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE); DMA_TO_DEVICE : DMA_FROM_DEVICE);
} else {
sg_count = host->next_data.sg_count;
host->next_data.sg_count = 0;
}
if (sg_count == 0) if (sg_count == 0)
return -EINVAL; return -ENOSPC;
if (next) { data->sg_count = sg_count;
next->sg_count = sg_count; data->host_cookie = COOKIE_MAPPED;
data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
} else
host->sg_count = sg_count;
return sg_count; return sg_count;
} }
...@@ -2149,16 +2160,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, ...@@ -2149,16 +2160,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
{ {
struct sdhci_host *host = mmc_priv(mmc); struct sdhci_host *host = mmc_priv(mmc);
if (mrq->data->host_cookie) { mrq->data->host_cookie = COOKIE_UNMAPPED;
mrq->data->host_cookie = 0;
return;
}
if (host->flags & SDHCI_REQ_USE_DMA) if (host->flags & SDHCI_REQ_USE_DMA)
if (sdhci_pre_dma_transfer(host, sdhci_pre_dma_transfer(host, mrq->data);
mrq->data,
&host->next_data) < 0)
mrq->data->host_cookie = 0;
} }
static void sdhci_card_event(struct mmc_host *mmc) static void sdhci_card_event(struct mmc_host *mmc)
...@@ -3030,7 +3035,6 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3030,7 +3035,6 @@ int sdhci_add_host(struct sdhci_host *host)
host->max_clk = host->ops->get_max_clock(host); host->max_clk = host->ops->get_max_clock(host);
} }
host->next_data.cookie = 1;
/* /*
* In case of Host Controller v3.00, find out whether clock * In case of Host Controller v3.00, find out whether clock
* multiplier is supported. * multiplier is supported.
...@@ -3126,7 +3130,8 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3126,7 +3130,8 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
!(mmc->caps & MMC_CAP_NONREMOVABLE)) !(mmc->caps & MMC_CAP_NONREMOVABLE) &&
IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
mmc->caps |= MMC_CAP_NEEDS_POLL; mmc->caps |= MMC_CAP_NEEDS_POLL;
/* If there are external regulators, get them */ /* If there are external regulators, get them */
......
...@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc { ...@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc {
*/ */
#define SDHCI_MAX_SEGS 128 #define SDHCI_MAX_SEGS 128
struct sdhci_host_next { enum sdhci_cookie {
unsigned int sg_count; COOKIE_UNMAPPED,
s32 cookie; COOKIE_MAPPED,
COOKIE_GIVEN,
}; };
struct sdhci_host { struct sdhci_host {
...@@ -409,6 +410,8 @@ struct sdhci_host { ...@@ -409,6 +410,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) #define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13)
/* Controller broken with using ACMD23 */ /* Controller broken with using ACMD23 */
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) #define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
int irq; /* Device IRQ */ int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */ void __iomem *ioaddr; /* Mapped address */
...@@ -503,7 +506,6 @@ struct sdhci_host { ...@@ -503,7 +506,6 @@ struct sdhci_host {
unsigned int tuning_mode; /* Re-tuning mode supported by host */ unsigned int tuning_mode; /* Re-tuning mode supported by host */
#define SDHCI_TUNING_MODE_1 0 #define SDHCI_TUNING_MODE_1 0
struct sdhci_host_next next_data;
unsigned long private[0] ____cacheline_aligned; unsigned long private[0] ____cacheline_aligned;
}; };
......
...@@ -1632,7 +1632,9 @@ static int sh_mmcif_suspend(struct device *dev) ...@@ -1632,7 +1632,9 @@ static int sh_mmcif_suspend(struct device *dev)
{ {
struct sh_mmcif_host *host = dev_get_drvdata(dev); struct sh_mmcif_host *host = dev_get_drvdata(dev);
pm_runtime_get_sync(dev);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
pm_runtime_put(dev);
return 0; return 0;
} }
......
...@@ -595,7 +595,7 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id) ...@@ -595,7 +595,7 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id)
static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
{ {
unsigned long expire = jiffies + msecs_to_jiffies(250); unsigned long expire = jiffies + msecs_to_jiffies(750);
u32 rval; u32 rval;
rval = mmc_readl(host, REG_CLKCR); rval = mmc_readl(host, REG_CLKCR);
......
...@@ -83,6 +83,8 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host) ...@@ -83,6 +83,8 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
return --host->sg_len; return --host->sg_len;
} }
#define CMDREQ_TIMEOUT 5000
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
#define STATUS_TO_TEXT(a, status, i) \ #define STATUS_TO_TEXT(a, status, i) \
...@@ -230,7 +232,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) ...@@ -230,7 +232,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
*/ */
if (IS_ERR_OR_NULL(mrq) if (IS_ERR_OR_NULL(mrq)
|| time_is_after_jiffies(host->last_req_ts + || time_is_after_jiffies(host->last_req_ts +
msecs_to_jiffies(2000))) { msecs_to_jiffies(CMDREQ_TIMEOUT))) {
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
return; return;
} }
...@@ -818,7 +820,7 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -818,7 +820,7 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
ret = tmio_mmc_start_command(host, mrq->cmd); ret = tmio_mmc_start_command(host, mrq->cmd);
if (!ret) { if (!ret) {
schedule_delayed_work(&host->delayed_reset_work, schedule_delayed_work(&host->delayed_reset_work,
msecs_to_jiffies(2000)); msecs_to_jiffies(CMDREQ_TIMEOUT));
return; return;
} }
......
...@@ -1611,7 +1611,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id) ...@@ -1611,7 +1611,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
/* Ack */ /* Ack */
usdhi6_write(host, USDHI6_SD_INFO1, !status); usdhi6_write(host, USDHI6_SD_INFO1, ~status);
if (!work_pending(&mmc->detect.work) && if (!work_pending(&mmc->detect.work) &&
(((status & USDHI6_SD_INFO1_CARD_INSERT) && (((status & USDHI6_SD_INFO1_CARD_INSERT) &&
...@@ -1634,6 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work) ...@@ -1634,6 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
struct mmc_request *mrq = host->mrq; struct mmc_request *mrq = host->mrq;
struct mmc_data *data = mrq ? mrq->data : NULL; struct mmc_data *data = mrq ? mrq->data : NULL;
struct scatterlist *sg = host->sg ?: data->sg;
dev_warn(mmc_dev(host->mmc), dev_warn(mmc_dev(host->mmc),
"%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n", "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
...@@ -1669,7 +1670,7 @@ static void usdhi6_timeout_work(struct work_struct *work) ...@@ -1669,7 +1670,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
"%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n", "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n",
data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx, data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
host->offset, data->blocks, data->blksz, data->sg_len, host->offset, data->blocks, data->blksz, data->sg_len,
sg_dma_len(host->sg), host->sg->offset); sg_dma_len(sg), sg->offset);
usdhi6_sg_unmap(host, true); usdhi6_sg_unmap(host, true);
/* /*
* If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped
...@@ -1715,12 +1716,14 @@ static int usdhi6_probe(struct platform_device *pdev) ...@@ -1715,12 +1716,14 @@ static int usdhi6_probe(struct platform_device *pdev)
if (!mmc) if (!mmc)
return -ENOMEM; return -ENOMEM;
ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER)
goto e_free_mmc;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret < 0) if (ret < 0)
goto e_free_mmc; goto e_free_mmc;
mmc_regulator_get_supply(mmc);
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->wait = USDHI6_WAIT_FOR_REQUEST; host->wait = USDHI6_WAIT_FOR_REQUEST;
...@@ -1734,8 +1737,10 @@ static int usdhi6_probe(struct platform_device *pdev) ...@@ -1734,8 +1737,10 @@ static int usdhi6_probe(struct platform_device *pdev)
} }
host->clk = devm_clk_get(dev, NULL); host->clk = devm_clk_get(dev, NULL);
if (IS_ERR(host->clk)) if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
goto e_free_mmc; goto e_free_mmc;
}
host->imclk = clk_get_rate(host->clk); host->imclk = clk_get_rate(host->clk);
......
...@@ -279,10 +279,13 @@ struct mmc_card { ...@@ -279,10 +279,13 @@ struct mmc_card {
#define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */ #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */
#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */ #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */
#define MMC_QUIRK_BROKEN_IRQ_POLLING (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */ #define MMC_QUIRK_BROKEN_IRQ_POLLING (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */
#define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */
unsigned int erase_size; /* erase size in sectors */ unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int erase_shift; /* if erase unit is power 2 */
unsigned int pref_erase; /* in sectors */ unsigned int pref_erase; /* in sectors */
unsigned int eg_boundary; /* don't cross erase-group boundaries */
u8 erased_byte; /* value of erased bytes */ u8 erased_byte; /* value of erased bytes */
u32 raw_cid[4]; /* raw card CID */ u32 raw_cid[4]; /* raw card CID */
......
...@@ -98,6 +98,7 @@ struct mmc_data; ...@@ -98,6 +98,7 @@ struct mmc_data;
* @irq_flags: The flags to be passed to request_irq. * @irq_flags: The flags to be passed to request_irq.
* @irq: The irq value to be passed to request_irq. * @irq: The irq value to be passed to request_irq.
* @sdio_id0: Number of slot0 in the SDIO interrupt registers. * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
* @dto_timer: Timer for broken data transfer over scheme.
* *
* Locking * Locking
* ======= * =======
...@@ -153,11 +154,7 @@ struct dw_mci { ...@@ -153,11 +154,7 @@ struct dw_mci {
dma_addr_t sg_dma; dma_addr_t sg_dma;
void *sg_cpu; void *sg_cpu;
const struct dw_mci_dma_ops *dma_ops; const struct dw_mci_dma_ops *dma_ops;
#ifdef CONFIG_MMC_DW_IDMAC
unsigned int ring_size; unsigned int ring_size;
#else
struct dw_mci_dma_data *dma_data;
#endif
u32 cmd_status; u32 cmd_status;
u32 data_status; u32 data_status;
u32 stop_cmdr; u32 stop_cmdr;
...@@ -204,6 +201,7 @@ struct dw_mci { ...@@ -204,6 +201,7 @@ struct dw_mci {
int sdio_id0; int sdio_id0;
struct timer_list cmd11_timer; struct timer_list cmd11_timer;
struct timer_list dto_timer;
}; };
/* DMA ops for Internal/External DMAC interface */ /* DMA ops for Internal/External DMAC interface */
...@@ -226,6 +224,8 @@ struct dw_mci_dma_ops { ...@@ -226,6 +224,8 @@ struct dw_mci_dma_ops {
#define DW_MCI_QUIRK_HIGHSPEED BIT(2) #define DW_MCI_QUIRK_HIGHSPEED BIT(2)
/* Unreliable card detection */ /* Unreliable card detection */
#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3) #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3)
/* Timer for broken data transfer over scheme */
#define DW_MCI_QUIRK_BROKEN_DTO BIT(4)
struct dma_pdata; struct dma_pdata;
...@@ -259,7 +259,6 @@ struct dw_mci_board { ...@@ -259,7 +259,6 @@ struct dw_mci_board {
struct dw_mci_dma_ops *dma_ops; struct dw_mci_dma_ops *dma_ops;
struct dma_pdata *data; struct dma_pdata *data;
struct block_settings *blk_settings;
}; };
#endif /* LINUX_MMC_DW_MMC_H */ #endif /* LINUX_MMC_DW_MMC_H */
...@@ -412,6 +412,7 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) ...@@ -412,6 +412,7 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
{ {
host->ops->enable_sdio_irq(host, 0); host->ops->enable_sdio_irq(host, 0);
host->sdio_irq_pending = true; host->sdio_irq_pending = true;
if (host->sdio_irq_thread)
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
} }
......
...@@ -45,5 +45,6 @@ struct esdhc_platform_data { ...@@ -45,5 +45,6 @@ struct esdhc_platform_data {
int max_bus_width; int max_bus_width;
bool support_vsel; bool support_vsel;
unsigned int delay_line; unsigned int delay_line;
unsigned int tuning_step; /* The delay cell steps in tuning procedure */
}; };
#endif /* __ASM_ARCH_IMX_ESDHC_H */ #endif /* __ASM_ARCH_IMX_ESDHC_H */
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