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;
} }
......
...@@ -99,6 +99,9 @@ struct idmac_desc { ...@@ -99,6 +99,9 @@ struct idmac_desc {
__le32 des3; /* buffer 2 physical address */ __le32 des3; /* buffer 2 physical address */
}; };
/* Each descriptor can transfer up to 4KB of data in chained mode */
#define DW_MCI_DESC_DATA_LENGTH 0x1000
#endif /* CONFIG_MMC_DW_IDMAC */ #endif /* CONFIG_MMC_DW_IDMAC */
static bool dw_mci_reset(struct dw_mci *host); static bool dw_mci_reset(struct dw_mci *host);
...@@ -235,8 +238,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) ...@@ -235,8 +238,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
const struct dw_mci_drv_data *drv_data = slot->host->drv_data; const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 cmdr; u32 cmdr;
cmd->error = -EINPROGRESS;
cmd->error = -EINPROGRESS;
cmdr = cmd->opcode; cmdr = cmd->opcode;
if (cmd->opcode == MMC_STOP_TRANSMISSION || if (cmd->opcode == MMC_STOP_TRANSMISSION ||
...@@ -371,7 +374,7 @@ static void dw_mci_start_command(struct dw_mci *host, ...@@ -371,7 +374,7 @@ static void dw_mci_start_command(struct dw_mci *host,
cmd->arg, cmd_flags); cmd->arg, cmd_flags);
mci_writel(host, CMDARG, cmd->arg); mci_writel(host, CMDARG, cmd->arg);
wmb(); wmb(); /* drain writebuffer */
dw_mci_wait_while_busy(host, cmd_flags); dw_mci_wait_while_busy(host, cmd_flags);
mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
...@@ -380,6 +383,7 @@ static void dw_mci_start_command(struct dw_mci *host, ...@@ -380,6 +383,7 @@ static void dw_mci_start_command(struct dw_mci *host,
static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
{ {
struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
dw_mci_start_command(host, stop, host->stop_cmdr); dw_mci_start_command(host, stop, host->stop_cmdr);
} }
...@@ -462,69 +466,102 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host) ...@@ -462,69 +466,102 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
unsigned int sg_len) unsigned int sg_len)
{ {
unsigned int desc_len;
int i; int i;
if (host->dma_64bit_address == 1) { if (host->dma_64bit_address == 1) {
struct idmac_desc_64addr *desc = host->sg_cpu; struct idmac_desc_64addr *desc_first, *desc_last, *desc;
for (i = 0; i < sg_len; i++, desc++) { desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]); unsigned int length = sg_dma_len(&data->sg[i]);
u64 mem_addr = sg_dma_address(&data->sg[i]); u64 mem_addr = sg_dma_address(&data->sg[i]);
/* for ( ; length ; desc++) {
* Set the OWN bit and disable interrupts for this desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
* descriptor length : DW_MCI_DESC_DATA_LENGTH;
*/
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | length -= desc_len;
IDMAC_DES0_CH;
/* Buffer length */ /*
IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length); * Set the OWN bit and disable interrupts
* for this descriptor
/* Physical address to DMA to/from */ */
desc->des4 = mem_addr & 0xffffffff; desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
desc->des5 = mem_addr >> 32; IDMAC_DES0_CH;
/* Buffer length */
IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
} }
/* Set first descriptor */ /* Set first descriptor */
desc = host->sg_cpu; desc_first->des0 |= IDMAC_DES0_FD;
desc->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */ /* Set last descriptor */
desc = host->sg_cpu + (i - 1) * desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
sizeof(struct idmac_desc_64addr); desc_last->des0 |= IDMAC_DES0_LD;
desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc->des0 |= IDMAC_DES0_LD;
} else { } else {
struct idmac_desc *desc = host->sg_cpu; struct idmac_desc *desc_first, *desc_last, *desc;
for (i = 0; i < sg_len; i++, desc++) { desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]); unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&data->sg[i]); u32 mem_addr = sg_dma_address(&data->sg[i]);
/* for ( ; length ; desc++) {
* Set the OWN bit and disable interrupts for this desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
* descriptor length : DW_MCI_DESC_DATA_LENGTH;
*/
desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | length -= desc_len;
IDMAC_DES0_DIC | IDMAC_DES0_CH);
/* Buffer length */ /*
IDMAC_SET_BUFFER1_SIZE(desc, length); * Set the OWN bit and disable interrupts
* for this descriptor
*/
desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
IDMAC_DES0_DIC |
IDMAC_DES0_CH);
/* Physical address to DMA to/from */ /* Buffer length */
desc->des2 = cpu_to_le32(mem_addr); IDMAC_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des2 = cpu_to_le32(mem_addr);
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
} }
/* Set first descriptor */ /* Set first descriptor */
desc = host->sg_cpu; desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
desc->des0 |= cpu_to_le32(IDMAC_DES0_FD);
/* Set last descriptor */ /* Set last descriptor */
desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH |
desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC)); IDMAC_DES0_DIC));
desc->des0 |= cpu_to_le32(IDMAC_DES0_LD); desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD);
} }
wmb(); wmb(); /* drain writebuffer */
} }
static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
...@@ -542,6 +579,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) ...@@ -542,6 +579,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
temp |= SDMMC_CTRL_USE_IDMAC; temp |= SDMMC_CTRL_USE_IDMAC;
mci_writel(host, CTRL, temp); mci_writel(host, CTRL, temp);
/* drain writebuffer */
wmb(); wmb();
/* Enable the IDMAC */ /* Enable the IDMAC */
...@@ -589,7 +627,9 @@ static int dw_mci_idmac_init(struct dw_mci *host) ...@@ -589,7 +627,9 @@ static int dw_mci_idmac_init(struct dw_mci *host)
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
/* Forward link the descriptor list */ /* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) { for (i = 0, p = host->sg_cpu;
i < host->ring_size - 1;
i++, p++) {
p->des3 = cpu_to_le32(host->sg_dma + p->des3 = cpu_to_le32(host->sg_dma +
(sizeof(struct idmac_desc) * (i + 1))); (sizeof(struct idmac_desc) * (i + 1)));
p->des1 = 0; p->des1 = 0;
...@@ -718,7 +758,7 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) ...@@ -718,7 +758,7 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
u32 fifo_width = 1 << host->data_shift; u32 fifo_width = 1 << host->data_shift;
u32 blksz_depth = blksz / fifo_width, fifoth_val; u32 blksz_depth = blksz / fifo_width, fifoth_val;
u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1; int idx = ARRAY_SIZE(mszs) - 1;
tx_wmark = (host->fifo_depth) / 2; tx_wmark = (host->fifo_depth) / 2;
tx_wmark_invers = host->fifo_depth - tx_wmark; tx_wmark_invers = host->fifo_depth - tx_wmark;
...@@ -843,6 +883,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) ...@@ -843,6 +883,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
{ {
unsigned long irqflags; unsigned long irqflags;
int flags = SG_MITER_ATOMIC;
u32 temp; u32 temp;
data->error = -EINPROGRESS; data->error = -EINPROGRESS;
...@@ -859,7 +900,6 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) ...@@ -859,7 +900,6 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
} }
if (dw_mci_submit_data_dma(host, data)) { if (dw_mci_submit_data_dma(host, data)) {
int flags = SG_MITER_ATOMIC;
if (host->data->flags & MMC_DATA_READ) if (host->data->flags & MMC_DATA_READ)
flags |= SG_MITER_TO_SG; flags |= SG_MITER_TO_SG;
else else
...@@ -906,7 +946,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) ...@@ -906,7 +946,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
unsigned int cmd_status = 0; unsigned int cmd_status = 0;
mci_writel(host, CMDARG, arg); mci_writel(host, CMDARG, arg);
wmb(); wmb(); /* drain writebuffer */
dw_mci_wait_while_busy(host, cmd); dw_mci_wait_while_busy(host, cmd);
mci_writel(host, CMD, SDMMC_CMD_START | cmd); mci_writel(host, CMD, SDMMC_CMD_START | cmd);
...@@ -1019,7 +1059,7 @@ static void __dw_mci_start_request(struct dw_mci *host, ...@@ -1019,7 +1059,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (data) { if (data) {
dw_mci_submit_data(host, data); dw_mci_submit_data(host, data);
wmb(); wmb(); /* drain writebuffer */
} }
dw_mci_start_command(host, cmd, cmdflags); dw_mci_start_command(host, cmd, cmdflags);
...@@ -1384,14 +1424,15 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1384,14 +1424,15 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
const struct dw_mci_drv_data *drv_data = host->drv_data; const struct dw_mci_drv_data *drv_data = host->drv_data;
int err = -ENOSYS; int err = -EINVAL;
if (drv_data && drv_data->execute_tuning) if (drv_data && drv_data->execute_tuning)
err = drv_data->execute_tuning(slot); err = drv_data->execute_tuning(slot);
return err; return err;
} }
static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc,
struct mmc_ios *ios)
{ {
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
...@@ -1533,6 +1574,20 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) ...@@ -1533,6 +1574,20 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
return data->error; return data->error;
} }
static void dw_mci_set_drto(struct dw_mci *host)
{
unsigned int drto_clks;
unsigned int drto_ms;
drto_clks = mci_readl(host, TMOUT) >> 8;
drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000);
/* add a bit spare time */
drto_ms += 10;
mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
}
static void dw_mci_tasklet_func(unsigned long priv) static void dw_mci_tasklet_func(unsigned long priv)
{ {
struct dw_mci *host = (struct dw_mci *)priv; struct dw_mci *host = (struct dw_mci *)priv;
...@@ -1610,8 +1665,16 @@ static void dw_mci_tasklet_func(unsigned long priv) ...@@ -1610,8 +1665,16 @@ static void dw_mci_tasklet_func(unsigned long priv)
} }
if (!test_and_clear_bit(EVENT_XFER_COMPLETE, if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
&host->pending_events)) &host->pending_events)) {
/*
* If all data-related interrupts don't come
* within the given time in reading data state.
*/
if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
(host->dir_status == DW_MCI_RECV_STATUS))
dw_mci_set_drto(host);
break; break;
}
set_bit(EVENT_XFER_COMPLETE, &host->completed_events); set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
...@@ -1644,8 +1707,17 @@ static void dw_mci_tasklet_func(unsigned long priv) ...@@ -1644,8 +1707,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
case STATE_DATA_BUSY: case STATE_DATA_BUSY:
if (!test_and_clear_bit(EVENT_DATA_COMPLETE, if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
&host->pending_events)) &host->pending_events)) {
/*
* If data error interrupt comes but data over
* interrupt doesn't come within the given time.
* in reading data state.
*/
if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
(host->dir_status == DW_MCI_RECV_STATUS))
dw_mci_set_drto(host);
break; break;
}
host->data = NULL; host->data = NULL;
set_bit(EVENT_DATA_COMPLETE, &host->completed_events); set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
...@@ -1743,7 +1815,7 @@ static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) ...@@ -1743,7 +1815,7 @@ static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
/* pull first bytes from part_buf, only use during pull */ /* pull first bytes from part_buf, only use during pull */
static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
{ {
cnt = min(cnt, (int)host->part_buf_count); cnt = min_t(int, cnt, host->part_buf_count);
if (cnt) { if (cnt) {
memcpy(buf, (void *)&host->part_buf + host->part_buf_start, memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
cnt); cnt);
...@@ -1769,6 +1841,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) ...@@ -1769,6 +1841,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
/* try and push anything in the part_buf */ /* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) { if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt); int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len; buf += len;
cnt -= len; cnt -= len;
if (host->part_buf_count == 2) { if (host->part_buf_count == 2) {
...@@ -1795,6 +1868,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) ...@@ -1795,6 +1868,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u16 *pdata = buf; u16 *pdata = buf;
for (; cnt >= 2; cnt -= 2) for (; cnt >= 2; cnt -= 2)
mci_fifo_writew(host->fifo_reg, *pdata++); mci_fifo_writew(host->fifo_reg, *pdata++);
buf = pdata; buf = pdata;
...@@ -1819,6 +1893,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) ...@@ -1819,6 +1893,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
int len = min(cnt & -2, (int)sizeof(aligned_buf)); int len = min(cnt & -2, (int)sizeof(aligned_buf));
int items = len >> 1; int items = len >> 1;
int i; int i;
for (i = 0; i < items; ++i) for (i = 0; i < items; ++i)
aligned_buf[i] = mci_fifo_readw(host->fifo_reg); aligned_buf[i] = mci_fifo_readw(host->fifo_reg);
/* memcpy from aligned buffer into output buffer */ /* memcpy from aligned buffer into output buffer */
...@@ -1830,6 +1905,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) ...@@ -1830,6 +1905,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u16 *pdata = buf; u16 *pdata = buf;
for (; cnt >= 2; cnt -= 2) for (; cnt >= 2; cnt -= 2)
*pdata++ = mci_fifo_readw(host->fifo_reg); *pdata++ = mci_fifo_readw(host->fifo_reg);
buf = pdata; buf = pdata;
...@@ -1848,6 +1924,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) ...@@ -1848,6 +1924,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
/* try and push anything in the part_buf */ /* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) { if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt); int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len; buf += len;
cnt -= len; cnt -= len;
if (host->part_buf_count == 4) { if (host->part_buf_count == 4) {
...@@ -1874,6 +1951,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) ...@@ -1874,6 +1951,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u32 *pdata = buf; u32 *pdata = buf;
for (; cnt >= 4; cnt -= 4) for (; cnt >= 4; cnt -= 4)
mci_fifo_writel(host->fifo_reg, *pdata++); mci_fifo_writel(host->fifo_reg, *pdata++);
buf = pdata; buf = pdata;
...@@ -1898,6 +1976,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) ...@@ -1898,6 +1976,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
int len = min(cnt & -4, (int)sizeof(aligned_buf)); int len = min(cnt & -4, (int)sizeof(aligned_buf));
int items = len >> 2; int items = len >> 2;
int i; int i;
for (i = 0; i < items; ++i) for (i = 0; i < items; ++i)
aligned_buf[i] = mci_fifo_readl(host->fifo_reg); aligned_buf[i] = mci_fifo_readl(host->fifo_reg);
/* memcpy from aligned buffer into output buffer */ /* memcpy from aligned buffer into output buffer */
...@@ -1909,6 +1988,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) ...@@ -1909,6 +1988,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u32 *pdata = buf; u32 *pdata = buf;
for (; cnt >= 4; cnt -= 4) for (; cnt >= 4; cnt -= 4)
*pdata++ = mci_fifo_readl(host->fifo_reg); *pdata++ = mci_fifo_readl(host->fifo_reg);
buf = pdata; buf = pdata;
...@@ -1927,6 +2007,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) ...@@ -1927,6 +2007,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
/* try and push anything in the part_buf */ /* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) { if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt); int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len; buf += len;
cnt -= len; cnt -= len;
...@@ -1954,6 +2035,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) ...@@ -1954,6 +2035,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u64 *pdata = buf; u64 *pdata = buf;
for (; cnt >= 8; cnt -= 8) for (; cnt >= 8; cnt -= 8)
mci_fifo_writeq(host->fifo_reg, *pdata++); mci_fifo_writeq(host->fifo_reg, *pdata++);
buf = pdata; buf = pdata;
...@@ -1978,6 +2060,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) ...@@ -1978,6 +2060,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
int len = min(cnt & -8, (int)sizeof(aligned_buf)); int len = min(cnt & -8, (int)sizeof(aligned_buf));
int items = len >> 3; int items = len >> 3;
int i; int i;
for (i = 0; i < items; ++i) for (i = 0; i < items; ++i)
aligned_buf[i] = mci_fifo_readq(host->fifo_reg); aligned_buf[i] = mci_fifo_readq(host->fifo_reg);
...@@ -1990,6 +2073,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) ...@@ -1990,6 +2073,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
#endif #endif
{ {
u64 *pdata = buf; u64 *pdata = buf;
for (; cnt >= 8; cnt -= 8) for (; cnt >= 8; cnt -= 8)
*pdata++ = mci_fifo_readq(host->fifo_reg); *pdata++ = mci_fifo_readq(host->fifo_reg);
buf = pdata; buf = pdata;
...@@ -2065,7 +2149,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) ...@@ -2065,7 +2149,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
done: done:
sg_miter_stop(sg_miter); sg_miter_stop(sg_miter);
host->sg = NULL; host->sg = NULL;
smp_wmb(); smp_wmb(); /* drain writebuffer */
set_bit(EVENT_XFER_COMPLETE, &host->pending_events); set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
} }
...@@ -2119,7 +2203,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host) ...@@ -2119,7 +2203,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
done: done:
sg_miter_stop(sg_miter); sg_miter_stop(sg_miter);
host->sg = NULL; host->sg = NULL;
smp_wmb(); smp_wmb(); /* drain writebuffer */
set_bit(EVENT_XFER_COMPLETE, &host->pending_events); set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
} }
...@@ -2128,7 +2212,7 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) ...@@ -2128,7 +2212,7 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
if (!host->cmd_status) if (!host->cmd_status)
host->cmd_status = status; host->cmd_status = status;
smp_wmb(); smp_wmb(); /* drain writebuffer */
set_bit(EVENT_CMD_COMPLETE, &host->pending_events); set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
...@@ -2192,7 +2276,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) ...@@ -2192,7 +2276,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & DW_MCI_CMD_ERROR_FLAGS) { if (pending & DW_MCI_CMD_ERROR_FLAGS) {
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
host->cmd_status = pending; host->cmd_status = pending;
smp_wmb(); smp_wmb(); /* drain writebuffer */
set_bit(EVENT_CMD_COMPLETE, &host->pending_events); set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
} }
...@@ -2200,16 +2284,19 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) ...@@ -2200,16 +2284,19 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
/* if there is an error report DATA_ERROR */ /* if there is an error report DATA_ERROR */
mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
host->data_status = pending; host->data_status = pending;
smp_wmb(); smp_wmb(); /* drain writebuffer */
set_bit(EVENT_DATA_ERROR, &host->pending_events); set_bit(EVENT_DATA_ERROR, &host->pending_events);
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
} }
if (pending & SDMMC_INT_DATA_OVER) { if (pending & SDMMC_INT_DATA_OVER) {
if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
del_timer(&host->dto_timer);
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host->data_status) if (!host->data_status)
host->data_status = pending; host->data_status = pending;
smp_wmb(); smp_wmb(); /* drain writebuffer */
if (host->dir_status == DW_MCI_RECV_STATUS) { if (host->dir_status == DW_MCI_RECV_STATUS) {
if (host->sg != NULL) if (host->sg != NULL)
dw_mci_read_data_pio(host, true); dw_mci_read_data_pio(host, true);
...@@ -2383,27 +2470,20 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) ...@@ -2383,27 +2470,20 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (ret) if (ret)
goto err_host_allocated; goto err_host_allocated;
if (host->pdata->blk_settings) { /* Useful defaults if platform data is unset. */
mmc->max_segs = host->pdata->blk_settings->max_segs; if (host->use_dma) {
mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
mmc->max_req_size = host->pdata->blk_settings->max_req_size;
mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
} else {
/* Useful defaults if platform data is unset. */
#ifdef CONFIG_MMC_DW_IDMAC
mmc->max_segs = host->ring_size; mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65536; mmc->max_blk_size = 65536;
mmc->max_seg_size = 0x1000; mmc->max_seg_size = 0x1000;
mmc->max_req_size = mmc->max_seg_size * host->ring_size; mmc->max_req_size = mmc->max_seg_size * host->ring_size;
mmc->max_blk_count = mmc->max_req_size / 512; mmc->max_blk_count = mmc->max_req_size / 512;
#else } else {
mmc->max_segs = 64; mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
mmc->max_blk_count = 512; mmc->max_blk_count = 512;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_req_size = mmc->max_blk_size *
mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size; mmc->max_seg_size = mmc->max_req_size;
#endif /* CONFIG_MMC_DW_IDMAC */
} }
if (dw_mci_get_cd(mmc)) if (dw_mci_get_cd(mmc))
...@@ -2473,8 +2553,8 @@ static void dw_mci_init_dma(struct dw_mci *host) ...@@ -2473,8 +2553,8 @@ static void dw_mci_init_dma(struct dw_mci *host)
if (host->dma_ops->init && host->dma_ops->start && if (host->dma_ops->init && host->dma_ops->start &&
host->dma_ops->stop && host->dma_ops->cleanup) { host->dma_ops->stop && host->dma_ops->cleanup) {
if (host->dma_ops->init(host)) { if (host->dma_ops->init(host)) {
dev_err(host->dev, "%s: Unable to initialize " dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n",
"DMA Controller.\n", __func__); __func__);
goto no_dma; goto no_dma;
} }
} else { } else {
...@@ -2488,7 +2568,6 @@ static void dw_mci_init_dma(struct dw_mci *host) ...@@ -2488,7 +2568,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
no_dma: no_dma:
dev_info(host->dev, "Using PIO mode.\n"); dev_info(host->dev, "Using PIO mode.\n");
host->use_dma = 0; host->use_dma = 0;
return;
} }
static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
...@@ -2542,6 +2621,7 @@ static bool dw_mci_reset(struct dw_mci *host) ...@@ -2542,6 +2621,7 @@ static bool dw_mci_reset(struct dw_mci *host)
if (host->use_dma) { if (host->use_dma) {
unsigned long timeout = jiffies + msecs_to_jiffies(500); unsigned long timeout = jiffies + msecs_to_jiffies(500);
u32 status; u32 status;
do { do {
status = mci_readl(host, STATUS); status = mci_readl(host, STATUS);
if (!(status & SDMMC_STATUS_DMA_REQ)) if (!(status & SDMMC_STATUS_DMA_REQ))
...@@ -2551,8 +2631,8 @@ static bool dw_mci_reset(struct dw_mci *host) ...@@ -2551,8 +2631,8 @@ static bool dw_mci_reset(struct dw_mci *host)
if (status & SDMMC_STATUS_DMA_REQ) { if (status & SDMMC_STATUS_DMA_REQ) {
dev_err(host->dev, dev_err(host->dev,
"%s: Timeout waiting for dma_req to " "%s: Timeout waiting for dma_req to clear during reset\n",
"clear during reset\n", __func__); __func__);
goto ciu_out; goto ciu_out;
} }
...@@ -2563,8 +2643,8 @@ static bool dw_mci_reset(struct dw_mci *host) ...@@ -2563,8 +2643,8 @@ static bool dw_mci_reset(struct dw_mci *host)
} else { } else {
/* if the controller reset bit did clear, then set clock regs */ /* if the controller reset bit did clear, then set clock regs */
if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
dev_err(host->dev, "%s: fifo/dma reset bits didn't " dev_err(host->dev,
"clear but ciu was reset, doing clock update\n", "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n",
__func__); __func__);
goto ciu_out; goto ciu_out;
} }
...@@ -2598,6 +2678,28 @@ static void dw_mci_cmd11_timer(unsigned long arg) ...@@ -2598,6 +2678,28 @@ static void dw_mci_cmd11_timer(unsigned long arg)
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
} }
static void dw_mci_dto_timer(unsigned long arg)
{
struct dw_mci *host = (struct dw_mci *)arg;
switch (host->state) {
case STATE_SENDING_DATA:
case STATE_DATA_BUSY:
/*
* If DTO interrupt does NOT come in sending data state,
* we should notify the driver to terminate current transfer
* and report a data timeout to the core.
*/
host->data_status = SDMMC_INT_DRTO;
set_bit(EVENT_DATA_ERROR, &host->pending_events);
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
break;
default:
break;
}
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct dw_mci_of_quirks { static struct dw_mci_of_quirks {
char *quirk; char *quirk;
...@@ -2625,8 +2727,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) ...@@ -2625,8 +2727,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
/* find out number of slots supported */ /* find out number of slots supported */
if (of_property_read_u32(dev->of_node, "num-slots", if (of_property_read_u32(dev->of_node, "num-slots",
&pdata->num_slots)) { &pdata->num_slots)) {
dev_info(dev, "num-slots property not found, " dev_info(dev,
"assuming 1 slot is available\n"); "num-slots property not found, assuming 1 slot is available\n");
pdata->num_slots = 1; pdata->num_slots = 1;
} }
...@@ -2636,8 +2738,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) ...@@ -2636,8 +2738,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
pdata->quirks |= of_quirks[idx].id; pdata->quirks |= of_quirks[idx].id;
if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
dev_info(dev, "fifo-depth property not found, using " dev_info(dev,
"value of FIFOTH register as default\n"); "fifo-depth property not found, using value of FIFOTH register as default\n");
of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
...@@ -2650,8 +2752,10 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) ...@@ -2650,8 +2752,10 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (of_find_property(np, "supports-highspeed", NULL)) if (of_find_property(np, "supports-highspeed", NULL)) {
dev_info(dev, "supports-highspeed property is deprecated.\n");
pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
}
return pdata; return pdata;
} }
...@@ -2706,7 +2810,7 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2706,7 +2810,7 @@ int dw_mci_probe(struct dw_mci *host)
} }
} }
if (host->pdata->num_slots > 1) { if (host->pdata->num_slots < 1) {
dev_err(host->dev, dev_err(host->dev,
"Platform data must supply num_slots.\n"); "Platform data must supply num_slots.\n");
return -ENODEV; return -ENODEV;
...@@ -2774,6 +2878,10 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2774,6 +2878,10 @@ int dw_mci_probe(struct dw_mci *host)
host->quirks = host->pdata->quirks; host->quirks = host->pdata->quirks;
if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
setup_timer(&host->dto_timer,
dw_mci_dto_timer, (unsigned long)host);
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
spin_lock_init(&host->irq_lock); spin_lock_init(&host->irq_lock);
INIT_LIST_HEAD(&host->queue); INIT_LIST_HEAD(&host->queue);
...@@ -2874,11 +2982,11 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2874,11 +2982,11 @@ int dw_mci_probe(struct dw_mci *host)
mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
SDMMC_INT_TXDR | SDMMC_INT_RXDR | SDMMC_INT_TXDR | SDMMC_INT_RXDR |
DW_MCI_ERROR_FLAGS); DW_MCI_ERROR_FLAGS);
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ /* Enable mci interrupt */
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
dev_info(host->dev, "DW MMC controller at irq %d, " dev_info(host->dev,
"%d bit host data width, " "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n",
"%u deep fifo\n",
host->irq, width, fifo_size); host->irq, width, fifo_size);
/* We need at least one slot to succeed */ /* We need at least one slot to succeed */
...@@ -2893,8 +3001,9 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2893,8 +3001,9 @@ int dw_mci_probe(struct dw_mci *host)
if (init_slots) { if (init_slots) {
dev_info(host->dev, "%d slots initialized\n", init_slots); dev_info(host->dev, "%d slots initialized\n", init_slots);
} else { } else {
dev_dbg(host->dev, "attempted to initialize %d slots, " dev_dbg(host->dev,
"but failed on all\n", host->num_slots); "attempted to initialize %d slots, but failed on all\n",
host->num_slots);
goto err_dmaunmap; goto err_dmaunmap;
} }
...@@ -2992,6 +3101,7 @@ int dw_mci_resume(struct dw_mci *host) ...@@ -2992,6 +3101,7 @@ int dw_mci_resume(struct dw_mci *host)
for (i = 0; i < host->num_slots; i++) { for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i]; struct dw_mci_slot *slot = host->slot[i];
if (!slot) if (!slot)
continue; continue;
if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
......
...@@ -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);
......
...@@ -181,18 +181,9 @@ struct omap_hsmmc_host { ...@@ -181,18 +181,9 @@ struct omap_hsmmc_host {
struct mmc_data *data; struct mmc_data *data;
struct clk *fclk; struct clk *fclk;
struct clk *dbclk; struct clk *dbclk;
/*
* vcc == configured supply
* vcc_aux == optional
* - MMC1, supply for DAT4..DAT7
* - MMC2/MMC2, external level shifter voltage supply, for
* chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
*/
struct regulator *vcc;
struct regulator *vcc_aux;
struct regulator *pbias; struct regulator *pbias;
bool pbias_enabled;
void __iomem *base; void __iomem *base;
int vqmmc_enabled;
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 */
unsigned int dma_len; unsigned int dma_len;
...@@ -213,7 +204,6 @@ struct omap_hsmmc_host { ...@@ -213,7 +204,6 @@ struct omap_hsmmc_host {
int context_loss; int context_loss;
int protect_card; int protect_card;
int reqs_blocked; int reqs_blocked;
int use_reg;
int req_in_progress; int req_in_progress;
unsigned long clk_rate; unsigned long clk_rate;
unsigned int flags; unsigned int flags;
...@@ -254,32 +244,133 @@ static int omap_hsmmc_get_cover_state(struct device *dev) ...@@ -254,32 +244,133 @@ static int omap_hsmmc_get_cover_state(struct device *dev)
return mmc_gpio_get_cd(host->mmc); return mmc_gpio_get_cd(host->mmc);
} }
#ifdef CONFIG_REGULATOR static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
{
int ret;
struct omap_hsmmc_host *host = mmc_priv(mmc);
struct mmc_ios *ios = &mmc->ios;
if (mmc->supply.vmmc) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
if (ret)
return ret;
}
/* Enable interface voltage rail, if needed */
if (mmc->supply.vqmmc && !host->vqmmc_enabled) {
ret = regulator_enable(mmc->supply.vqmmc);
if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n");
goto err_vqmmc;
}
host->vqmmc_enabled = 1;
}
return 0;
err_vqmmc:
if (mmc->supply.vmmc)
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
return ret;
}
static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
{
int ret;
int status;
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (mmc->supply.vqmmc && host->vqmmc_enabled) {
ret = regulator_disable(mmc->supply.vqmmc);
if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n");
return ret;
}
host->vqmmc_enabled = 0;
}
if (mmc->supply.vmmc) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
if (ret)
goto err_set_ocr;
}
return 0;
err_set_ocr:
if (mmc->supply.vqmmc) {
status = regulator_enable(mmc->supply.vqmmc);
if (status)
dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n");
}
return ret;
}
static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
int vdd)
{
int ret;
if (!host->pbias)
return 0;
if (power_on) {
if (vdd <= VDD_165_195)
ret = regulator_set_voltage(host->pbias, VDD_1V8,
VDD_1V8);
else
ret = regulator_set_voltage(host->pbias, VDD_3V0,
VDD_3V0);
if (ret < 0) {
dev_err(host->dev, "pbias set voltage fail\n");
return ret;
}
if (!regulator_is_enabled(host->pbias)) {
ret = regulator_enable(host->pbias);
if (ret) {
dev_err(host->dev, "pbias reg enable fail\n");
return ret;
}
}
} else {
if (regulator_is_enabled(host->pbias)) {
ret = regulator_disable(host->pbias);
if (ret) {
dev_err(host->dev, "pbias reg disable fail\n");
return ret;
}
}
}
return 0;
}
static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
{ {
struct omap_hsmmc_host *host = struct omap_hsmmc_host *host =
platform_get_drvdata(to_platform_device(dev)); platform_get_drvdata(to_platform_device(dev));
struct mmc_host *mmc = host->mmc;
int ret = 0; int ret = 0;
if (mmc_pdata(host)->set_power)
return mmc_pdata(host)->set_power(dev, power_on, vdd);
/* /*
* If we don't see a Vcc regulator, assume it's a fixed * If we don't see a Vcc regulator, assume it's a fixed
* voltage always-on regulator. * voltage always-on regulator.
*/ */
if (!host->vcc) if (!mmc->supply.vmmc)
return 0; return 0;
if (mmc_pdata(host)->before_set_reg) if (mmc_pdata(host)->before_set_reg)
mmc_pdata(host)->before_set_reg(dev, power_on, vdd); mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
if (host->pbias) { ret = omap_hsmmc_set_pbias(host, false, 0);
if (host->pbias_enabled == 1) { if (ret)
ret = regulator_disable(host->pbias); return ret;
if (!ret)
host->pbias_enabled = 0;
}
regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0);
}
/* /*
* Assume Vcc regulator is used only to power the card ... OMAP * Assume Vcc regulator is used only to power the card ... OMAP
...@@ -295,129 +386,138 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) ...@@ -295,129 +386,138 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
* chips/cards need an interface voltage rail too. * chips/cards need an interface voltage rail too.
*/ */
if (power_on) { if (power_on) {
if (host->vcc) ret = omap_hsmmc_enable_supply(mmc);
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); if (ret)
/* Enable interface voltage rail, if needed */ return ret;
if (ret == 0 && host->vcc_aux) {
ret = regulator_enable(host->vcc_aux);
if (ret < 0 && host->vcc)
ret = mmc_regulator_set_ocr(host->mmc,
host->vcc, 0);
}
} else {
/* Shut down the rail */
if (host->vcc_aux)
ret = regulator_disable(host->vcc_aux);
if (host->vcc) {
/* Then proceed to shut down the local regulator */
ret = mmc_regulator_set_ocr(host->mmc,
host->vcc, 0);
}
}
if (host->pbias) {
if (vdd <= VDD_165_195)
ret = regulator_set_voltage(host->pbias, VDD_1V8,
VDD_1V8);
else
ret = regulator_set_voltage(host->pbias, VDD_3V0,
VDD_3V0);
if (ret < 0)
goto error_set_power;
if (host->pbias_enabled == 0) { ret = omap_hsmmc_set_pbias(host, true, vdd);
ret = regulator_enable(host->pbias); if (ret)
if (!ret) goto err_set_voltage;
host->pbias_enabled = 1; } else {
} ret = omap_hsmmc_disable_supply(mmc);
if (ret)
return ret;
} }
if (mmc_pdata(host)->after_set_reg) if (mmc_pdata(host)->after_set_reg)
mmc_pdata(host)->after_set_reg(dev, power_on, vdd); mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
error_set_power: return 0;
err_set_voltage:
omap_hsmmc_disable_supply(mmc);
return ret; return ret;
} }
static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) static int omap_hsmmc_disable_boot_regulator(struct regulator *reg)
{ {
struct regulator *reg; int ret;
int ocr_value = 0;
reg = devm_regulator_get(host->dev, "vmmc"); if (!reg)
if (IS_ERR(reg)) { return 0;
dev_err(host->dev, "unable to get vmmc regulator %ld\n",
PTR_ERR(reg)); if (regulator_is_enabled(reg)) {
return PTR_ERR(reg); ret = regulator_enable(reg);
} else { if (ret)
host->vcc = reg; return ret;
ocr_value = mmc_regulator_get_ocrmask(reg);
if (!mmc_pdata(host)->ocr_mask) { ret = regulator_disable(reg);
mmc_pdata(host)->ocr_mask = ocr_value; if (ret)
} else { return ret;
if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
dev_err(host->dev, "ocrmask %x is not supported\n",
mmc_pdata(host)->ocr_mask);
mmc_pdata(host)->ocr_mask = 0;
return -EINVAL;
}
}
} }
mmc_pdata(host)->set_power = omap_hsmmc_set_power;
/* Allow an aux regulator */ return 0;
reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); }
host->vcc_aux = IS_ERR(reg) ? NULL : reg;
reg = devm_regulator_get_optional(host->dev, "pbias"); static int omap_hsmmc_disable_boot_regulators(struct omap_hsmmc_host *host)
host->pbias = IS_ERR(reg) ? NULL : reg; {
struct mmc_host *mmc = host->mmc;
int ret;
/* For eMMC do not power off when not in sleep state */
if (mmc_pdata(host)->no_regulator_off_init)
return 0;
/* /*
* To disable boot_on regulator, enable regulator * disable regulators enabled during boot and get the usecount
* to increase usecount and then disable it. * right so that regulators can be enabled/disabled by checking
* the return value of regulator_is_enabled
*/ */
if ((host->vcc && regulator_is_enabled(host->vcc) > 0) || ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vmmc);
(host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { if (ret) {
int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; dev_err(host->dev, "fail to disable boot enabled vmmc reg\n");
return ret;
}
ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vqmmc);
if (ret) {
dev_err(host->dev,
"fail to disable boot enabled vmmc_aux reg\n");
return ret;
}
mmc_pdata(host)->set_power(host->dev, 1, vdd); ret = omap_hsmmc_disable_boot_regulator(host->pbias);
mmc_pdata(host)->set_power(host->dev, 0, 0); if (ret) {
dev_err(host->dev,
"failed to disable boot enabled pbias reg\n");
return ret;
} }
return 0; return 0;
} }
static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{ {
mmc_pdata(host)->set_power = NULL; int ocr_value = 0;
} int ret;
struct mmc_host *mmc = host->mmc;
static inline int omap_hsmmc_have_reg(void) if (mmc_pdata(host)->set_power)
{ return 0;
return 1;
}
#else mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc");
if (IS_ERR(mmc->supply.vmmc)) {
ret = PTR_ERR(mmc->supply.vmmc);
if (ret != -ENODEV)
return ret;
dev_dbg(host->dev, "unable to get vmmc regulator %ld\n",
PTR_ERR(mmc->supply.vmmc));
mmc->supply.vmmc = NULL;
} else {
ocr_value = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
if (ocr_value > 0)
mmc_pdata(host)->ocr_mask = ocr_value;
}
static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) /* Allow an aux regulator */
{ mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux");
return -EINVAL; if (IS_ERR(mmc->supply.vqmmc)) {
} ret = PTR_ERR(mmc->supply.vqmmc);
if (ret != -ENODEV)
return ret;
dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
PTR_ERR(mmc->supply.vqmmc));
mmc->supply.vqmmc = NULL;
}
static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) host->pbias = devm_regulator_get_optional(host->dev, "pbias");
{ if (IS_ERR(host->pbias)) {
} ret = PTR_ERR(host->pbias);
if (ret != -ENODEV)
return ret;
dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
PTR_ERR(host->pbias));
host->pbias = NULL;
}
/* For eMMC do not power off when not in sleep state */
if (mmc_pdata(host)->no_regulator_off_init)
return 0;
ret = omap_hsmmc_disable_boot_regulators(host);
if (ret)
return ret;
static inline int omap_hsmmc_have_reg(void)
{
return 0; return 0;
} }
#endif
static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id); static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
static int omap_hsmmc_gpio_init(struct mmc_host *mmc, static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
...@@ -1149,11 +1249,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) ...@@ -1149,11 +1249,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
/* Turn the power off */ /* Turn the power off */
ret = mmc_pdata(host)->set_power(host->dev, 0, 0); ret = omap_hsmmc_set_power(host->dev, 0, 0);
/* Turn the power ON with given VDD 1.8 or 3.0v */ /* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret) if (!ret)
ret = mmc_pdata(host)->set_power(host->dev, 1, vdd); ret = omap_hsmmc_set_power(host->dev, 1, vdd);
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) if (host->dbclk)
clk_prepare_enable(host->dbclk); clk_prepare_enable(host->dbclk);
...@@ -1552,10 +1652,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1552,10 +1652,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->power_mode != host->power_mode) { if (ios->power_mode != host->power_mode) {
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
mmc_pdata(host)->set_power(host->dev, 0, 0); omap_hsmmc_set_power(host->dev, 0, 0);
break; break;
case MMC_POWER_UP: case MMC_POWER_UP:
mmc_pdata(host)->set_power(host->dev, 1, ios->vdd); omap_hsmmc_set_power(host->dev, 1, ios->vdd);
break; break;
case MMC_POWER_ON: case MMC_POWER_ON:
do_send_init_stream = 1; do_send_init_stream = 1;
...@@ -1953,7 +2053,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1953,7 +2053,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->base = base + pdata->reg_offset; host->base = base + pdata->reg_offset;
host->power_mode = MMC_POWER_OFF; host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1; host->next_data.cookie = 1;
host->pbias_enabled = 0; host->vqmmc_enabled = 0;
ret = omap_hsmmc_gpio_init(mmc, host, pdata); ret = omap_hsmmc_gpio_init(mmc, host, pdata);
if (ret) if (ret)
...@@ -2078,12 +2178,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -2078,12 +2178,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq; goto err_irq;
} }
if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) { ret = omap_hsmmc_reg_get(host);
ret = omap_hsmmc_reg_get(host); if (ret)
if (ret) goto err_irq;
goto err_irq;
host->use_reg = 1;
}
mmc->ocr_avail = mmc_pdata(host)->ocr_mask; mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
...@@ -2125,8 +2222,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -2125,8 +2222,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
err_slot_name: err_slot_name:
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (host->use_reg)
omap_hsmmc_reg_put(host);
err_irq: err_irq:
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
if (host->tx_chan) if (host->tx_chan)
...@@ -2150,8 +2245,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) ...@@ -2150,8 +2245,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
mmc_remove_host(host->mmc); mmc_remove_host(host->mmc);
if (host->use_reg)
omap_hsmmc_reg_put(host);
if (host->tx_chan) if (host->tx_chan)
dma_release_channel(host->tx_chan); dma_release_channel(host->tx_chan);
......
...@@ -22,7 +22,9 @@ ...@@ -22,7 +22,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dma/pxa-dma.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -37,7 +39,6 @@ ...@@ -37,7 +39,6 @@
#include <asm/sizes.h> #include <asm/sizes.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/dma.h>
#include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/mmc-pxamci.h>
#include "pxamci.h" #include "pxamci.h"
...@@ -58,7 +59,6 @@ struct pxamci_host { ...@@ -58,7 +59,6 @@ struct pxamci_host {
struct clk *clk; struct clk *clk;
unsigned long clkrate; unsigned long clkrate;
int irq; int irq;
int dma;
unsigned int clkrt; unsigned int clkrt;
unsigned int cmdat; unsigned int cmdat;
unsigned int imask; unsigned int imask;
...@@ -69,8 +69,10 @@ struct pxamci_host { ...@@ -69,8 +69,10 @@ struct pxamci_host {
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_data *data; struct mmc_data *data;
struct dma_chan *dma_chan_rx;
struct dma_chan *dma_chan_tx;
dma_cookie_t dma_cookie;
dma_addr_t sg_dma; dma_addr_t sg_dma;
struct pxa_dma_desc *sg_cpu;
unsigned int dma_len; unsigned int dma_len;
unsigned int dma_dir; unsigned int dma_dir;
...@@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) ...@@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
static void pxamci_dma_irq(void *param);
static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
{ {
struct dma_async_tx_descriptor *tx;
enum dma_data_direction direction;
struct dma_slave_config config;
struct dma_chan *chan;
unsigned int nob = data->blocks; unsigned int nob = data->blocks;
unsigned long long clks; unsigned long long clks;
unsigned int timeout; unsigned int timeout;
bool dalgn = 0; int ret;
u32 dcmd;
int i;
host->data = data; host->data = data;
...@@ -195,54 +201,48 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) ...@@ -195,54 +201,48 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
writel((timeout + 255) / 256, host->base + MMC_RDTO); writel((timeout + 255) / 256, host->base + MMC_RDTO);
memset(&config, 0, sizeof(config));
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.src_addr = host->res->start + MMC_RXFIFO;
config.dst_addr = host->res->start + MMC_TXFIFO;
config.src_maxburst = 32;
config.dst_maxburst = 32;
if (data->flags & MMC_DATA_READ) { if (data->flags & MMC_DATA_READ) {
host->dma_dir = DMA_FROM_DEVICE; host->dma_dir = DMA_FROM_DEVICE;
dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; direction = DMA_DEV_TO_MEM;
DRCMR(host->dma_drcmrtx) = 0; chan = host->dma_chan_rx;
DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
} else { } else {
host->dma_dir = DMA_TO_DEVICE; host->dma_dir = DMA_TO_DEVICE;
dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; direction = DMA_MEM_TO_DEV;
DRCMR(host->dma_drcmrrx) = 0; chan = host->dma_chan_tx;
DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
} }
dcmd |= DCMD_BURST32 | DCMD_WIDTH1; config.direction = direction;
ret = dmaengine_slave_config(chan, &config);
if (ret < 0) {
dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
return;
}
host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
host->dma_dir); host->dma_dir);
for (i = 0; i < host->dma_len; i++) { tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
unsigned int length = sg_dma_len(&data->sg[i]); DMA_PREP_INTERRUPT);
host->sg_cpu[i].dcmd = dcmd | length; if (!tx) {
if (length & 31 && !(data->flags & MMC_DATA_READ)) dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; return;
/* Not aligned to 8-byte boundary? */
if (sg_dma_address(&data->sg[i]) & 0x7)
dalgn = 1;
if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
} else {
host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
}
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc);
} }
host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
wmb();
/* if (!(data->flags & MMC_DATA_READ)) {
* The PXA27x DMA controller encounters overhead when working with tx->callback = pxamci_dma_irq;
* unaligned (to 8-byte boundaries) data, so switch on byte alignment tx->callback_param = host;
* mode only if we have unaligned data. }
*/
if (dalgn) host->dma_cookie = dmaengine_submit(tx);
DALGN |= (1 << host->dma);
else
DALGN &= ~(1 << host->dma);
DDADR(host->dma) = host->sg_dma;
/* /*
* workaround for erratum #91: * workaround for erratum #91:
...@@ -251,7 +251,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) ...@@ -251,7 +251,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
* before starting DMA. * before starting DMA.
*/ */
if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
DCSR(host->dma) = DCSR_RUN; dma_async_issue_pending(chan);
} }
static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
...@@ -343,7 +343,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) ...@@ -343,7 +343,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
* enable DMA late * enable DMA late
*/ */
if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
DCSR(host->dma) = DCSR_RUN; dma_async_issue_pending(host->dma_chan_tx);
} else { } else {
pxamci_finish_request(host, host->mrq); pxamci_finish_request(host, host->mrq);
} }
...@@ -354,13 +354,17 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) ...@@ -354,13 +354,17 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
{ {
struct mmc_data *data = host->data; struct mmc_data *data = host->data;
struct dma_chan *chan;
if (!data) if (!data)
return 0; return 0;
DCSR(host->dma) = 0; if (data->flags & MMC_DATA_READ)
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, chan = host->dma_chan_rx;
host->dma_dir); else
chan = host->dma_chan_tx;
dma_unmap_sg(chan->device->dev,
data->sg, data->sg_len, host->dma_dir);
if (stat & STAT_READ_TIME_OUT) if (stat & STAT_READ_TIME_OUT)
data->error = -ETIMEDOUT; data->error = -ETIMEDOUT;
...@@ -552,20 +556,37 @@ static const struct mmc_host_ops pxamci_ops = { ...@@ -552,20 +556,37 @@ static const struct mmc_host_ops pxamci_ops = {
.enable_sdio_irq = pxamci_enable_sdio_irq, .enable_sdio_irq = pxamci_enable_sdio_irq,
}; };
static void pxamci_dma_irq(int dma, void *devid) static void pxamci_dma_irq(void *param)
{ {
struct pxamci_host *host = devid; struct pxamci_host *host = param;
int dcsr = DCSR(dma); struct dma_tx_state state;
DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; enum dma_status status;
struct dma_chan *chan;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
if (!host->data)
goto out_unlock;
if (dcsr & DCSR_ENDINTR) { if (host->data->flags & MMC_DATA_READ)
chan = host->dma_chan_rx;
else
chan = host->dma_chan_tx;
status = dmaengine_tx_status(chan, host->dma_cookie, &state);
if (likely(status == DMA_COMPLETE)) {
writel(BUF_PART_FULL, host->base + MMC_PRTBUF); writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
} else { } else {
pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
mmc_hostname(host->mmc), dma, dcsr); host->data->flags & MMC_DATA_READ ? "rx" : "tx");
host->data->error = -EIO; host->data->error = -EIO;
pxamci_data_done(host, 0); pxamci_data_done(host, 0);
} }
out_unlock:
spin_unlock_irqrestore(&host->lock, flags);
} }
static irqreturn_t pxamci_detect_irq(int irq, void *devid) static irqreturn_t pxamci_detect_irq(int irq, void *devid)
...@@ -625,7 +646,9 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -625,7 +646,9 @@ static int pxamci_probe(struct platform_device *pdev)
struct mmc_host *mmc; struct mmc_host *mmc;
struct pxamci_host *host = NULL; struct pxamci_host *host = NULL;
struct resource *r, *dmarx, *dmatx; struct resource *r, *dmarx, *dmatx;
struct pxad_param param_rx, param_tx;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
dma_cap_mask_t mask;
ret = pxamci_of_init(pdev); ret = pxamci_of_init(pdev);
if (ret) if (ret)
...@@ -671,7 +694,6 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -671,7 +694,6 @@ static int pxamci_probe(struct platform_device *pdev)
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->dma = -1;
host->pdata = pdev->dev.platform_data; host->pdata = pdev->dev.platform_data;
host->clkrt = CLKRT_OFF; host->clkrt = CLKRT_OFF;
...@@ -702,12 +724,6 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -702,12 +724,6 @@ static int pxamci_probe(struct platform_device *pdev)
MMC_CAP_SD_HIGHSPEED; MMC_CAP_SD_HIGHSPEED;
} }
host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
ret = -ENOMEM;
goto out;
}
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
host->res = r; host->res = r;
host->irq = irq; host->irq = irq;
...@@ -728,32 +744,45 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -728,32 +744,45 @@ static int pxamci_probe(struct platform_device *pdev)
writel(64, host->base + MMC_RESTO); writel(64, host->base + MMC_RESTO);
writel(host->imask, host->base + MMC_I_MASK); writel(host->imask, host->base + MMC_I_MASK);
host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
pxamci_dma_irq, host);
if (host->dma < 0) {
ret = -EBUSY;
goto out;
}
ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
if (ret) if (ret)
goto out; goto out;
platform_set_drvdata(pdev, mmc); platform_set_drvdata(pdev, mmc);
dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!pdev->dev.of_node) {
if (!dmarx) { dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
ret = -ENXIO; dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!dmarx || !dmatx) {
ret = -ENXIO;
goto out;
}
param_rx.prio = PXAD_PRIO_LOWEST;
param_rx.drcmr = dmarx->start;
param_tx.prio = PXAD_PRIO_LOWEST;
param_tx.drcmr = dmatx->start;
}
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma_chan_rx =
dma_request_slave_channel_compat(mask, pxad_filter_fn,
&param_rx, &pdev->dev, "rx");
if (host->dma_chan_rx == NULL) {
dev_err(&pdev->dev, "unable to request rx dma channel\n");
ret = -ENODEV;
goto out; goto out;
} }
host->dma_drcmrrx = dmarx->start;
dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); host->dma_chan_tx =
if (!dmatx) { dma_request_slave_channel_compat(mask, pxad_filter_fn,
ret = -ENXIO; &param_tx, &pdev->dev, "tx");
if (host->dma_chan_tx == NULL) {
dev_err(&pdev->dev, "unable to request tx dma channel\n");
ret = -ENODEV;
goto out; goto out;
} }
host->dma_drcmrtx = dmatx->start;
if (host->pdata) { if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect; gpio_cd = host->pdata->gpio_card_detect;
...@@ -814,12 +843,12 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -814,12 +843,12 @@ static int pxamci_probe(struct platform_device *pdev)
gpio_free(gpio_power); gpio_free(gpio_power);
out: out:
if (host) { if (host) {
if (host->dma >= 0) if (host->dma_chan_rx)
pxa_free_dma(host->dma); dma_release_channel(host->dma_chan_rx);
if (host->dma_chan_tx)
dma_release_channel(host->dma_chan_tx);
if (host->base) if (host->base)
iounmap(host->base); iounmap(host->base);
if (host->sg_cpu)
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->clk) if (host->clk)
clk_put(host->clk); clk_put(host->clk);
} }
...@@ -863,13 +892,12 @@ static int pxamci_remove(struct platform_device *pdev) ...@@ -863,13 +892,12 @@ static int pxamci_remove(struct platform_device *pdev)
END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
host->base + MMC_I_MASK); host->base + MMC_I_MASK);
DRCMR(host->dma_drcmrrx) = 0;
DRCMR(host->dma_drcmrtx) = 0;
free_irq(host->irq, host); free_irq(host->irq, host);
pxa_free_dma(host->dma); dmaengine_terminate_all(host->dma_chan_rx);
dmaengine_terminate_all(host->dma_chan_tx);
dma_release_channel(host->dma_chan_rx);
dma_release_channel(host->dma_chan_tx);
iounmap(host->base); iounmap(host->base);
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
clk_put(host->clk); clk_put(host->clk);
......
...@@ -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,15 +1193,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1189,15 +1193,25 @@ 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 /*
* Control register. * Set Programmable Clock Mode in the Clock
*/ * Control register.
clk = SDHCI_PROG_CLOCK_MODE; */
real_div = div; clk = SDHCI_PROG_CLOCK_MODE;
clk_mul = host->clk_mul; real_div = div;
div--; clk_mul = host->clk_mul;
} else { div--;
} 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,
data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
} else {
sg_count = host->next_data.sg_count;
host->next_data.sg_count = 0;
}
sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
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,7 +412,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) ...@@ -412,7 +412,8 @@ 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;
wake_up_process(host->sdio_irq_thread); if (host->sdio_irq_thread)
wake_up_process(host->sdio_irq_thread);
} }
void sdio_run_irqs(struct mmc_host *host); void sdio_run_irqs(struct mmc_host *host);
......
...@@ -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