Commit 5233c331 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MMC updates from Ulf Hansson:
 "It's been an busy period for mmc. Quite some changes in the mmc core,
  two new mmc host drivers, some existing drivers being extended to
  support new IP versions and lots of other updates.

  MMC core:
   - Delete eMMC packed command support
   - Introduce mmc_abort_tuning() to enable eMMC tuning to fail
     gracefully
   - Introduce mmc_can_retune() to see if a host can be retuned
   - Re-work and improve the sequence when sending a CMD6 for mmc
   - Enable CDM13 polling when switching to HS and HS DDR mode for mmc
   - Relax checking for CMD6 errors after switch to HS200
   - Re-factoring the code dealing with the mmc block queue
   - Recognize whether the eMMC card supports CMDQ
   - Fix 4K native sector check
   - Don't power off the card when starting the host
   - Increase MMC_IOC_MAX_BYTES to support bigger firmware binaries
   - Improve error handling and drop meaningless BUG_ONs()
   - Lots of clean-ups and changes to improve the quality of the code

  MMC host:
   - sdhci: Fix tuning sequence and clean-up the related code
   - sdhci: Add support to via DT override broken SDHCI cap register
     bits
   - sdhci-cadence: Add new driver for Cadence SD4HC SDHCI variant
   - sdhci-msm: Update clock management
   - sdhci-msm: Add support for eMMC HS400 mode
   - sdhci-msm: Deploy runtime/system PM support
   - sdhci-iproc: Extend driver support to newer IP versions
   - sdhci-pci: Add support for Intel GLK
   - sdhci-pci: Add support for Intel NI byt sdio
   - sdhci-acpi: Add support for 80860F14 UID 2 SDIO bus
   - sdhci: Lots of various small improvements and clean-ups
   - tmio: Add support for tuning
   - sh_mobile_sdhi: Add support for tuning
   - sh_mobile_sdhi: Extend driver to support SDHI IP on R7S72100 SoC
   - sh_mobile_sdhi: remove support for sh7372
   - davinci: Use mmc_of_parse() to enable generic mmc DT bindings
   - meson: Add new driver to support GX platforms
   - dw_mmc: Deploy generic runtime/system PM support
   - dw_mmc: Lots of various small improvements

  As a part of the mmc changes this time, I have also pulled in an
  immutable branch/tag (soc-device-match-tag1) hosted by Geert
  Uytterhoeven, to share the implementation of the new
  soc_device_match() interface. This is needed by these mmc related
  changes:

   - mmc: sdhci-of-esdhc: Get correct IP version for T4240-R1.0-R2.0
   - soc: fsl: add GUTS driver for QorIQ platforms"

* tag 'mmc-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (136 commits)
  mmc: sdhci-cadence: add Cadence SD4HC support
  mmc: sdhci: export sdhci_execute_tuning()
  mmc: sdhci: Tidy tuning loop
  mmc: sdhci: Simplify tuning block size logic
  mmc: sdhci: Factor out tuning helper functions
  mmc: sdhci: Use mmc_abort_tuning()
  mmc: mmc: Introduce mmc_abort_tuning()
  mmc: sdhci: Always allow tuning to fall back to fixed sampling
  mmc: sdhci: Fix tuning reset after exhausting the maximum number of loops
  mmc: sdhci: Fix recovery from tuning timeout
  Revert "mmc: sdhci: Reset cmd and data circuits after tuning failure"
  mmc: mmc: Relax checking for switch errors after HS200 switch
  mmc: sdhci-acpi: support 80860F14 UID 2 SDIO bus
  mmc: sdhci-of-at91: remove bogus MMC_SDHCI_IO_ACCESSORS select
  mmc: sdhci-pci: Use ACPI to get max frequency for Intel NI byt sdio
  mmc: sdhci-pci: Add PCI ID for Intel NI byt sdio
  mmc: sdhci-s3c: add spin_unlock_irq() before calling clk_round_rate
  mmc: dw_mmc: display the clock message only one time when card is polling
  mmc: dw_mmc: add the debug message for polling and non-removable
  mmc: dw_mmc: check the "present" variable before checking flags
  ...
parents 58f253d2 ff6af28f
Amlogic SD / eMMC controller for S905/GXBB family SoCs
The MMC 5.1 compliant host controller on Amlogic provides the
interface for SD, eMMC and SDIO devices.
This file documents the properties in addition to those available in
the MMC core bindings, documented by mmc.txt.
Required properties:
- compatible : contains one of:
- "amlogic,meson-gx-mmc"
- "amlogic,meson-gxbb-mmc"
- "amlogic,meson-gxl-mmc"
- "amlogic,meson-gxm-mmc"
- clocks : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
- clock-names: Should contain the following:
"core" - Main peripheral bus clock
"clkin0" - Parent clock of internal mux
"clkin1" - Other parent clock of internal mux
The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the
clock rate requested by the MMC core.
Example:
sd_emmc_a: mmc@70000 {
compatible = "amlogic,meson-gxbb-mmc";
reg = <0x0 0x70000 0x0 0x2000>;
interrupts = < GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
pinctrl-0 = <&emmc_pins>;
};
...@@ -7,6 +7,15 @@ Required properties: ...@@ -7,6 +7,15 @@ Required properties:
- compatible : Should be one of the following - compatible : Should be one of the following
"brcm,bcm2835-sdhci" "brcm,bcm2835-sdhci"
"brcm,sdhci-iproc-cygnus" "brcm,sdhci-iproc-cygnus"
"brcm,sdhci-iproc"
Use brcm2835-sdhci for Rasperry PI.
Use sdhci-iproc-cygnus for Broadcom SDHCI Controllers
restricted to 32bit host accesses to SDHCI registers.
Use sdhci-iproc for Broadcom SDHCI Controllers that allow standard
8, 16, 32-bit host access to SDHCI register.
- clocks : The clock feeding the SDHCI controller. - clocks : The clock feeding the SDHCI controller.
......
...@@ -8,11 +8,14 @@ Required properties: ...@@ -8,11 +8,14 @@ Required properties:
- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a - compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
fallback. Examples with <soctype> are: fallback. Examples with <soctype> are:
- "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
- "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
- "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
- "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
- clocks: reference to the functional clock - clocks: reference to the functional clock
......
* Cadence SD/SDIO/eMMC Host Controller
Required properties:
- compatible: should be "cdns,sd4hc".
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: phandle to the input clock.
Optional properties:
For eMMC configuration, supported speed modes are not indicated by the SDHCI
Capabilities Register. Instead, the following properties should be specified
if supported. See mmc.txt for details.
- mmc-ddr-1_8v
- mmc-ddr-1_2v
- mmc-hs200-1_8v
- mmc-hs200-1_2v
- mmc-hs400-1_8v
- mmc-hs400-1_2v
Example:
emmc: sdhci@5a000000 {
compatible = "cdns,sd4hc";
reg = <0x5a000000 0x400>;
interrupts = <0 78 4>;
clocks = <&clk 4>;
bus-width = <8>;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
};
...@@ -17,6 +17,7 @@ Required properties: ...@@ -17,6 +17,7 @@ Required properties:
"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required) "iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
"core" - SDC MMC clock (MCLK) (required) "core" - SDC MMC clock (MCLK) (required)
"bus" - SDCC bus voter clock (optional) "bus" - SDCC bus voter clock (optional)
"xo" - TCXO clock (optional)
Example: Example:
......
The properties specific for SD host controllers. For properties shared by MMC
host controllers refer to the mmc[1] bindings.
[1] Documentation/devicetree/bindings/mmc/mmc.txt
Optional properties:
- sdhci-caps-mask: The sdhci capabilities register is incorrect. This 64bit
property corresponds to the bits in the sdhci capabilty register. If the bit
is on in the mask then the bit is incorrect in the register and should be
turned off, before applying sdhci-caps.
- sdhci-caps: The sdhci capabilities register is incorrect. This 64bit
property corresponds to the bits in the sdhci capability register. If the
bit is on in the property then the bit should be turned on.
...@@ -59,8 +59,9 @@ Optional properties: ...@@ -59,8 +59,9 @@ Optional properties:
is specified and the ciu clock is specified then we'll try to set the ciu is specified and the ciu clock is specified then we'll try to set the ciu
clock to this at probe time. clock to this at probe time.
* clock-freq-min-max: Minimum and Maximum clock frequency for card output * clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output
clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default. clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default.
(Use the "max-frequency" instead of "clock-freq-min-max".)
* num-slots: specifies the number of slots supported by the controller. * num-slots: specifies the number of slots supported by the controller.
The number of physical slots actually used could be equal or less than the The number of physical slots actually used could be equal or less than the
...@@ -74,11 +75,6 @@ Optional properties: ...@@ -74,11 +75,6 @@ Optional properties:
* card-detect-delay: Delay in milli-seconds before detecting card after card * card-detect-delay: Delay in milli-seconds before detecting card after card
insert event. The default value is 0. insert event. The default value is 0.
* supports-highspeed (DEPRECATED): Enables support for high speed cards (up to 50MHz)
(use "cap-mmc-highspeed" or "cap-sd-highspeed" instead)
* broken-cd: as documented in mmc core bindings.
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is * vmmc-supply: The phandle to the regulator to use for vmmc. If this is
specified we'll defer probe until we can find this regulator. specified we'll defer probe until we can find this regulator.
......
...@@ -11,8 +11,8 @@ optional bindings can be used. ...@@ -11,8 +11,8 @@ optional bindings can be used.
Required properties: Required properties:
- compatible: "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit - compatible: "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
"renesas,sdhi-sh7372" - SDHI IP on SH7372 SoC
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
......
...@@ -25,6 +25,9 @@ Recommended properties: ...@@ -25,6 +25,9 @@ Recommended properties:
- fsl,liodn-bits : Indicates the number of defined bits in the LIODN - fsl,liodn-bits : Indicates the number of defined bits in the LIODN
registers, for those SOCs that have a PAMU device. registers, for those SOCs that have a PAMU device.
- little-endian : Indicates that the global utilities block is little
endian. The default is big endian.
Examples: Examples:
global-utilities@e0000 { /* global utilities block */ global-utilities@e0000 { /* global utilities block */
compatible = "fsl,mpc8548-guts"; compatible = "fsl,mpc8548-guts";
......
...@@ -1052,6 +1052,7 @@ F: arch/arm/mach-meson/ ...@@ -1052,6 +1052,7 @@ F: arch/arm/mach-meson/
F: arch/arm/boot/dts/meson* F: arch/arm/boot/dts/meson*
F: arch/arm64/boot/dts/amlogic/ F: arch/arm64/boot/dts/amlogic/
F: drivers/pinctrl/meson/ F: drivers/pinctrl/meson/
F: drivers/mmc/host/meson*
N: meson N: meson
ARM/Annapurna Labs ALPINE ARCHITECTURE ARM/Annapurna Labs ALPINE ARCHITECTURE
...@@ -5068,9 +5069,18 @@ S: Maintained ...@@ -5068,9 +5069,18 @@ S: Maintained
F: drivers/net/ethernet/freescale/fman F: drivers/net/ethernet/freescale/fman
F: Documentation/devicetree/bindings/powerpc/fsl/fman.txt F: Documentation/devicetree/bindings/powerpc/fsl/fman.txt
FREESCALE SOC DRIVERS
M: Scott Wood <oss@buserror.net>
L: linuxppc-dev@lists.ozlabs.org
L: linux-arm-kernel@lists.infradead.org
S: Maintained
F: drivers/soc/fsl/
F: include/linux/fsl/
FREESCALE QUICC ENGINE LIBRARY FREESCALE QUICC ENGINE LIBRARY
M: Qiang Zhao <qiang.zhao@nxp.com>
L: linuxppc-dev@lists.ozlabs.org L: linuxppc-dev@lists.ozlabs.org
S: Orphan S: Maintained
F: drivers/soc/fsl/qe/ F: drivers/soc/fsl/qe/
F: include/soc/fsl/*qe*.h F: include/soc/fsl/*qe*.h
F: include/soc/fsl/*ucc*.h F: include/soc/fsl/*ucc*.h
......
...@@ -216,6 +216,12 @@ clockgen: clocking@1300000 { ...@@ -216,6 +216,12 @@ clockgen: clocking@1300000 {
clocks = <&sysclk>; clocks = <&sysclk>;
}; };
dcfg: dcfg@1e00000 {
compatible = "fsl,ls2080a-dcfg", "syscon";
reg = <0x0 0x1e00000 0x0 0x10000>;
little-endian;
};
serial0: serial@21c0500 { serial0: serial@21c0500 {
compatible = "fsl,ns16550", "ns16550a"; compatible = "fsl,ns16550", "ns16550a";
reg = <0x0 0x21c0500 0x0 0x100>; reg = <0x0 0x21c0500 0x0 0x100>;
......
...@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE ...@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE
config SOC_BUS config SOC_BUS
bool bool
select GLOB
source "drivers/base/regmap/Kconfig" source "drivers/base/regmap/Kconfig"
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/glob.h>
static DEFINE_IDA(soc_ida); static DEFINE_IDA(soc_ida);
...@@ -113,6 +114,12 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr ...@@ -113,6 +114,12 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
struct soc_device *soc_dev; struct soc_device *soc_dev;
int ret; int ret;
if (!soc_bus_type.p) {
ret = bus_register(&soc_bus_type);
if (ret)
goto out1;
}
soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL); soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
if (!soc_dev) { if (!soc_dev) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -156,6 +163,78 @@ void soc_device_unregister(struct soc_device *soc_dev) ...@@ -156,6 +163,78 @@ void soc_device_unregister(struct soc_device *soc_dev)
static int __init soc_bus_register(void) static int __init soc_bus_register(void)
{ {
if (soc_bus_type.p)
return 0;
return bus_register(&soc_bus_type); return bus_register(&soc_bus_type);
} }
core_initcall(soc_bus_register); core_initcall(soc_bus_register);
static int soc_device_match_one(struct device *dev, void *arg)
{
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
const struct soc_device_attribute *match = arg;
if (match->machine &&
(!soc_dev->attr->machine ||
!glob_match(match->machine, soc_dev->attr->machine)))
return 0;
if (match->family &&
(!soc_dev->attr->family ||
!glob_match(match->family, soc_dev->attr->family)))
return 0;
if (match->revision &&
(!soc_dev->attr->revision ||
!glob_match(match->revision, soc_dev->attr->revision)))
return 0;
if (match->soc_id &&
(!soc_dev->attr->soc_id ||
!glob_match(match->soc_id, soc_dev->attr->soc_id)))
return 0;
return 1;
}
/*
* soc_device_match - identify the SoC in the machine
* @matches: zero-terminated array of possible matches
*
* returns the first matching entry of the argument array, or NULL
* if none of them match.
*
* This function is meant as a helper in place of of_match_node()
* in cases where either no device tree is available or the information
* in a device node is insufficient to identify a particular variant
* by its compatible strings or other properties. For new devices,
* the DT binding should always provide unique compatible strings
* that allow the use of of_match_node() instead.
*
* The calling function can use the .data entry of the
* soc_device_attribute to pass a structure or function pointer for
* each entry.
*/
const struct soc_device_attribute *soc_device_match(
const struct soc_device_attribute *matches)
{
int ret = 0;
if (!matches)
return NULL;
while (!ret) {
if (!(matches->machine || matches->family ||
matches->revision || matches->soc_id))
break;
ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
soc_device_match_one);
if (!ret)
matches++;
else
return matches;
}
return NULL;
}
EXPORT_SYMBOL_GPL(soc_device_match);
This diff is collapsed.
...@@ -214,7 +214,8 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test, ...@@ -214,7 +214,8 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len, struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
unsigned dev_addr, unsigned blocks, unsigned blksz, int write) unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
{ {
BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop); if (WARN_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop))
return;
if (blocks > 1) { if (blocks > 1) {
mrq->cmd->opcode = write ? mrq->cmd->opcode = write ?
...@@ -694,7 +695,8 @@ static int mmc_test_cleanup(struct mmc_test_card *test) ...@@ -694,7 +695,8 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test, static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, int write) struct mmc_request *mrq, int write)
{ {
BUG_ON(!mrq || !mrq->cmd || !mrq->data); if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
return;
if (mrq->data->blocks > 1) { if (mrq->data->blocks > 1) {
mrq->cmd->opcode = write ? mrq->cmd->opcode = write ?
...@@ -714,7 +716,8 @@ static int mmc_test_check_result(struct mmc_test_card *test, ...@@ -714,7 +716,8 @@ static int mmc_test_check_result(struct mmc_test_card *test,
{ {
int ret; int ret;
BUG_ON(!mrq || !mrq->cmd || !mrq->data); if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
return -EINVAL;
ret = 0; ret = 0;
...@@ -736,15 +739,28 @@ static int mmc_test_check_result(struct mmc_test_card *test, ...@@ -736,15 +739,28 @@ static int mmc_test_check_result(struct mmc_test_card *test,
return ret; return ret;
} }
static int mmc_test_check_result_async(struct mmc_card *card, static enum mmc_blk_status mmc_test_check_result_async(struct mmc_card *card,
struct mmc_async_req *areq) struct mmc_async_req *areq)
{ {
struct mmc_test_async_req *test_async = struct mmc_test_async_req *test_async =
container_of(areq, struct mmc_test_async_req, areq); container_of(areq, struct mmc_test_async_req, areq);
int ret;
mmc_test_wait_busy(test_async->test); mmc_test_wait_busy(test_async->test);
return mmc_test_check_result(test_async->test, areq->mrq); /*
* FIXME: this would earlier just casts a regular error code,
* either of the kernel type -ERRORCODE or the local test framework
* RESULT_* errorcode, into an enum mmc_blk_status and return as
* result check. Instead, convert it to some reasonable type by just
* returning either MMC_BLK_SUCCESS or MMC_BLK_CMD_ERR.
* If possible, a reasonable error code should be returned.
*/
ret = mmc_test_check_result(test_async->test, areq->mrq);
if (ret)
return MMC_BLK_CMD_ERR;
return MMC_BLK_SUCCESS;
} }
/* /*
...@@ -755,7 +771,8 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test, ...@@ -755,7 +771,8 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
{ {
int ret; int ret;
BUG_ON(!mrq || !mrq->cmd || !mrq->data); if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
return -EINVAL;
ret = 0; ret = 0;
...@@ -817,8 +834,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, ...@@ -817,8 +834,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
struct mmc_async_req *done_areq; struct mmc_async_req *done_areq;
struct mmc_async_req *cur_areq = &test_areq[0].areq; struct mmc_async_req *cur_areq = &test_areq[0].areq;
struct mmc_async_req *other_areq = &test_areq[1].areq; struct mmc_async_req *other_areq = &test_areq[1].areq;
enum mmc_blk_status status;
int i; int i;
int ret; int ret = RESULT_OK;
test_areq[0].test = test; test_areq[0].test = test;
test_areq[1].test = test; test_areq[1].test = test;
...@@ -834,10 +852,12 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, ...@@ -834,10 +852,12 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr, mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
blocks, blksz, write); blocks, blksz, write);
done_areq = mmc_start_req(test->card->host, cur_areq, &ret); done_areq = mmc_start_req(test->card->host, cur_areq, &status);
if (ret || (!done_areq && i > 0)) if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) {
ret = RESULT_FAIL;
goto err; goto err;
}
if (done_areq) { if (done_areq) {
if (done_areq->mrq == &mrq2) if (done_areq->mrq == &mrq2)
...@@ -851,7 +871,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, ...@@ -851,7 +871,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
dev_addr += blocks; dev_addr += blocks;
} }
done_areq = mmc_start_req(test->card->host, NULL, &ret); done_areq = mmc_start_req(test->card->host, NULL, &status);
if (status != MMC_BLK_SUCCESS)
ret = RESULT_FAIL;
return ret; return ret;
err: err:
...@@ -2351,6 +2373,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, ...@@ -2351,6 +2373,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
struct mmc_request *mrq; struct mmc_request *mrq;
unsigned long timeout; unsigned long timeout;
bool expired = false; bool expired = false;
enum mmc_blk_status blkstat = MMC_BLK_SUCCESS;
int ret = 0, cmd_ret; int ret = 0, cmd_ret;
u32 status = 0; u32 status = 0;
int count = 0; int count = 0;
...@@ -2378,9 +2401,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, ...@@ -2378,9 +2401,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
/* Start ongoing data request */ /* Start ongoing data request */
if (use_areq) { if (use_areq) {
mmc_start_req(host, &test_areq.areq, &ret); mmc_start_req(host, &test_areq.areq, &blkstat);
if (ret) if (blkstat != MMC_BLK_SUCCESS) {
ret = RESULT_FAIL;
goto out_free; goto out_free;
}
} else { } else {
mmc_wait_for_req(host, mrq); mmc_wait_for_req(host, mrq);
} }
...@@ -2413,10 +2438,13 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, ...@@ -2413,10 +2438,13 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
} while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN); } while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN);
/* Wait for data request to complete */ /* Wait for data request to complete */
if (use_areq) if (use_areq) {
mmc_start_req(host, NULL, &ret); mmc_start_req(host, NULL, &blkstat);
else if (blkstat != MMC_BLK_SUCCESS)
ret = RESULT_FAIL;
} else {
mmc_wait_for_req_done(test->card->host, mrq); mmc_wait_for_req_done(test->card->host, mrq);
}
/* /*
* For cap_cmd_during_tfr request, upper layer must send stop if * For cap_cmd_during_tfr request, upper layer must send stop if
......
This diff is collapsed.
...@@ -11,6 +11,7 @@ static inline bool mmc_req_is_special(struct request *req) ...@@ -11,6 +11,7 @@ static inline bool mmc_req_is_special(struct request *req)
struct request; struct request;
struct task_struct; struct task_struct;
struct mmc_blk_data;
struct mmc_blk_request { struct mmc_blk_request {
struct mmc_request mrq; struct mmc_request mrq;
...@@ -21,23 +22,6 @@ struct mmc_blk_request { ...@@ -21,23 +22,6 @@ struct mmc_blk_request {
int retune_retry_done; int retune_retry_done;
}; };
enum mmc_packed_type {
MMC_PACKED_NONE = 0,
MMC_PACKED_WRITE,
};
#define mmc_packed_cmd(type) ((type) != MMC_PACKED_NONE)
#define mmc_packed_wr(type) ((type) == MMC_PACKED_WRITE)
struct mmc_packed {
struct list_head list;
__le32 cmd_hdr[1024];
unsigned int blocks;
u8 nr_entries;
u8 retries;
s16 idx_failure;
};
struct mmc_queue_req { struct mmc_queue_req {
struct request *req; struct request *req;
struct mmc_blk_request brq; struct mmc_blk_request brq;
...@@ -46,8 +30,6 @@ struct mmc_queue_req { ...@@ -46,8 +30,6 @@ struct mmc_queue_req {
struct scatterlist *bounce_sg; struct scatterlist *bounce_sg;
unsigned int bounce_sg_len; unsigned int bounce_sg_len;
struct mmc_async_req mmc_active; struct mmc_async_req mmc_active;
enum mmc_packed_type cmd_type;
struct mmc_packed *packed;
}; };
struct mmc_queue { struct mmc_queue {
...@@ -57,11 +39,13 @@ struct mmc_queue { ...@@ -57,11 +39,13 @@ struct mmc_queue {
unsigned int flags; unsigned int flags;
#define MMC_QUEUE_SUSPENDED (1 << 0) #define MMC_QUEUE_SUSPENDED (1 << 0)
#define MMC_QUEUE_NEW_REQUEST (1 << 1) #define MMC_QUEUE_NEW_REQUEST (1 << 1)
void *data; bool asleep;
struct mmc_blk_data *blkdata;
struct request_queue *queue; struct request_queue *queue;
struct mmc_queue_req mqrq[2]; struct mmc_queue_req *mqrq;
struct mmc_queue_req *mqrq_cur; struct mmc_queue_req *mqrq_cur;
struct mmc_queue_req *mqrq_prev; struct mmc_queue_req *mqrq_prev;
int qdepth;
}; };
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
...@@ -75,9 +59,6 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *, ...@@ -75,9 +59,6 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
extern void mmc_queue_bounce_pre(struct mmc_queue_req *); extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
extern void mmc_queue_bounce_post(struct mmc_queue_req *); extern void mmc_queue_bounce_post(struct mmc_queue_req *);
extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
extern void mmc_packed_clean(struct mmc_queue *);
extern int mmc_access_rpmb(struct mmc_queue *); extern int mmc_access_rpmb(struct mmc_queue *);
#endif #endif
...@@ -135,8 +135,6 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) ...@@ -135,8 +135,6 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
{ {
struct sdio_func *func; struct sdio_func *func;
BUG_ON(sdio_uart_table[port->index] != port);
spin_lock(&sdio_uart_table_lock); spin_lock(&sdio_uart_table_lock);
sdio_uart_table[port->index] = NULL; sdio_uart_table[port->index] = NULL;
spin_unlock(&sdio_uart_table_lock); spin_unlock(&sdio_uart_table_lock);
......
...@@ -306,16 +306,16 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -306,16 +306,16 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->sbc->mrq = mrq; mrq->sbc->mrq = mrq;
} }
if (mrq->data) { if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size); if (mrq->data->blksz > host->max_blk_size ||
BUG_ON(mrq->data->blocks > host->max_blk_count); mrq->data->blocks > host->max_blk_count ||
BUG_ON(mrq->data->blocks * mrq->data->blksz > mrq->data->blocks * mrq->data->blksz > host->max_req_size)
host->max_req_size); return -EINVAL;
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
sz = 0; sz = 0;
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length; sz += sg->length;
BUG_ON(sz != mrq->data->blocks * mrq->data->blksz); if (sz != mrq->data->blocks * mrq->data->blksz)
return -EINVAL;
#endif #endif
mrq->cmd->data = mrq->data; mrq->cmd->data = mrq->data;
...@@ -349,8 +349,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -349,8 +349,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
int timeout; int timeout;
bool use_busy_signal; bool use_busy_signal;
BUG_ON(!card);
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card)) if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
return; return;
...@@ -380,7 +378,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -380,7 +378,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
mmc_retune_hold(card->host); mmc_retune_hold(card->host);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, timeout, EXT_CSD_BKOPS_START, 1, timeout, 0,
use_busy_signal, true, false); use_busy_signal, true, false);
if (err) { if (err) {
pr_warn("%s: Error %d starting bkops\n", pr_warn("%s: Error %d starting bkops\n",
...@@ -497,32 +495,28 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) ...@@ -497,32 +495,28 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
* *
* Returns enum mmc_blk_status after checking errors. * Returns enum mmc_blk_status after checking errors.
*/ */
static int mmc_wait_for_data_req_done(struct mmc_host *host, static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
struct mmc_request *mrq, struct mmc_request *mrq,
struct mmc_async_req *next_req) struct mmc_async_req *next_req)
{ {
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info; struct mmc_context_info *context_info = &host->context_info;
int err; enum mmc_blk_status status;
unsigned long flags;
while (1) { while (1) {
wait_event_interruptible(context_info->wait, wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv || (context_info->is_done_rcv ||
context_info->is_new_req)); context_info->is_new_req));
spin_lock_irqsave(&context_info->lock, flags);
context_info->is_waiting_last_req = false; context_info->is_waiting_last_req = false;
spin_unlock_irqrestore(&context_info->lock, flags);
if (context_info->is_done_rcv) { if (context_info->is_done_rcv) {
context_info->is_done_rcv = false; context_info->is_done_rcv = false;
context_info->is_new_req = false;
cmd = mrq->cmd; cmd = mrq->cmd;
if (!cmd->error || !cmd->retries || if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) { mmc_card_removed(host->card)) {
err = host->areq->err_check(host->card, status = host->areq->err_check(host->card,
host->areq); host->areq);
break; /* return err */ break; /* return status */
} else { } else {
mmc_retune_recheck(host); mmc_retune_recheck(host);
pr_info("%s: req failed (CMD%u): %d, retrying...\n", pr_info("%s: req failed (CMD%u): %d, retrying...\n",
...@@ -534,13 +528,12 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host, ...@@ -534,13 +528,12 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
continue; /* wait for done/new event again */ continue; /* wait for done/new event again */
} }
} else if (context_info->is_new_req) { } else if (context_info->is_new_req) {
context_info->is_new_req = false;
if (!next_req) if (!next_req)
return MMC_BLK_NEW_REQUEST; return MMC_BLK_NEW_REQUEST;
} }
} }
mmc_retune_release(host); mmc_retune_release(host);
return err; return status;
} }
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
...@@ -611,18 +604,15 @@ EXPORT_SYMBOL(mmc_is_req_done); ...@@ -611,18 +604,15 @@ EXPORT_SYMBOL(mmc_is_req_done);
* mmc_pre_req - Prepare for a new request * mmc_pre_req - Prepare for a new request
* @host: MMC host to prepare command * @host: MMC host to prepare command
* @mrq: MMC request to prepare for * @mrq: MMC request to prepare for
* @is_first_req: true if there is no previous started request
* that may run in parellel to this call, otherwise false
* *
* mmc_pre_req() is called in prior to mmc_start_req() to let * mmc_pre_req() is called in prior to mmc_start_req() to let
* host prepare for the new request. Preparation of a request may be * host prepare for the new request. Preparation of a request may be
* performed while another request is running on the host. * performed while another request is running on the host.
*/ */
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
bool is_first_req)
{ {
if (host->ops->pre_req) if (host->ops->pre_req)
host->ops->pre_req(host, mrq, is_first_req); host->ops->pre_req(host, mrq);
} }
/** /**
...@@ -658,21 +648,22 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, ...@@ -658,21 +648,22 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
* is returned without waiting. NULL is not an error condition. * is returned without waiting. NULL is not an error condition.
*/ */
struct mmc_async_req *mmc_start_req(struct mmc_host *host, struct mmc_async_req *mmc_start_req(struct mmc_host *host,
struct mmc_async_req *areq, int *error) struct mmc_async_req *areq,
enum mmc_blk_status *ret_stat)
{ {
int err = 0; enum mmc_blk_status status = MMC_BLK_SUCCESS;
int start_err = 0; int start_err = 0;
struct mmc_async_req *data = host->areq; struct mmc_async_req *data = host->areq;
/* Prepare a new request */ /* Prepare a new request */
if (areq) if (areq)
mmc_pre_req(host, areq->mrq, !host->areq); mmc_pre_req(host, areq->mrq);
if (host->areq) { if (host->areq) {
err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
if (err == MMC_BLK_NEW_REQUEST) { if (status == MMC_BLK_NEW_REQUEST) {
if (error) if (ret_stat)
*error = err; *ret_stat = status;
/* /*
* The previous request was not completed, * The previous request was not completed,
* nothing to return * nothing to return
...@@ -695,27 +686,27 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, ...@@ -695,27 +686,27 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
/* prepare the request again */ /* prepare the request again */
if (areq) if (areq)
mmc_pre_req(host, areq->mrq, !host->areq); mmc_pre_req(host, areq->mrq);
} }
} }
if (!err && areq) if (status == MMC_BLK_SUCCESS && areq)
start_err = __mmc_start_data_req(host, areq->mrq); start_err = __mmc_start_data_req(host, areq->mrq);
if (host->areq) if (host->areq)
mmc_post_req(host, host->areq->mrq, 0); mmc_post_req(host, host->areq->mrq, 0);
/* Cancel a prepared request if it was not started. */ /* Cancel a prepared request if it was not started. */
if ((err || start_err) && areq) if ((status != MMC_BLK_SUCCESS || start_err) && areq)
mmc_post_req(host, areq->mrq, -EINVAL); mmc_post_req(host, areq->mrq, -EINVAL);
if (err) if (status != MMC_BLK_SUCCESS)
host->areq = NULL; host->areq = NULL;
else else
host->areq = areq; host->areq = areq;
if (error) if (ret_stat)
*error = err; *ret_stat = status;
return data; return data;
} }
EXPORT_SYMBOL(mmc_start_req); EXPORT_SYMBOL(mmc_start_req);
...@@ -754,8 +745,6 @@ int mmc_interrupt_hpi(struct mmc_card *card) ...@@ -754,8 +745,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
u32 status; u32 status;
unsigned long prg_wait; unsigned long prg_wait;
BUG_ON(!card);
if (!card->ext_csd.hpi_en) { if (!card->ext_csd.hpi_en) {
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
return 1; return 1;
...@@ -850,7 +839,6 @@ int mmc_stop_bkops(struct mmc_card *card) ...@@ -850,7 +839,6 @@ int mmc_stop_bkops(struct mmc_card *card)
{ {
int err = 0; int err = 0;
BUG_ON(!card);
err = mmc_interrupt_hpi(card); err = mmc_interrupt_hpi(card);
/* /*
...@@ -1666,8 +1654,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) ...@@ -1666,8 +1654,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
int err = 0; int err = 0;
u32 clock; u32 clock;
BUG_ON(!host);
/* /*
* Send CMD11 only if the request is to switch the card to * Send CMD11 only if the request is to switch the card to
* 1.8V signalling. * 1.8V signalling.
...@@ -1884,9 +1870,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr) ...@@ -1884,9 +1870,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
*/ */
static void __mmc_release_bus(struct mmc_host *host) static void __mmc_release_bus(struct mmc_host *host)
{ {
BUG_ON(!host); WARN_ON(!host->bus_dead);
BUG_ON(host->bus_refs);
BUG_ON(!host->bus_dead);
host->bus_ops = NULL; host->bus_ops = NULL;
} }
...@@ -1926,15 +1910,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) ...@@ -1926,15 +1910,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{ {
unsigned long flags; unsigned long flags;
BUG_ON(!host);
BUG_ON(!ops);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->bus_ops); WARN_ON(host->bus_ops);
BUG_ON(host->bus_refs); WARN_ON(host->bus_refs);
host->bus_ops = ops; host->bus_ops = ops;
host->bus_refs = 1; host->bus_refs = 1;
...@@ -1950,8 +1931,6 @@ void mmc_detach_bus(struct mmc_host *host) ...@@ -1950,8 +1931,6 @@ void mmc_detach_bus(struct mmc_host *host)
{ {
unsigned long flags; unsigned long flags;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops); WARN_ON(!host->bus_ops);
...@@ -2824,12 +2803,11 @@ void mmc_start_host(struct mmc_host *host) ...@@ -2824,12 +2803,11 @@ void mmc_start_host(struct mmc_host *host)
host->rescan_disable = 0; host->rescan_disable = 0;
host->ios.power_mode = MMC_POWER_UNDEFINED; host->ios.power_mode = MMC_POWER_UNDEFINED;
mmc_claim_host(host); if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP) mmc_claim_host(host);
mmc_power_off(host);
else
mmc_power_up(host, host->ocr_avail); mmc_power_up(host, host->ocr_avail);
mmc_release_host(host); mmc_release_host(host);
}
mmc_gpiod_request_cd_irq(host); mmc_gpiod_request_cd_irq(host);
_mmc_detect_change(host, 0, false); _mmc_detect_change(host, 0, false);
...@@ -2865,8 +2843,6 @@ void mmc_stop_host(struct mmc_host *host) ...@@ -2865,8 +2843,6 @@ void mmc_stop_host(struct mmc_host *host)
} }
mmc_bus_put(host); mmc_bus_put(host);
BUG_ON(host->card);
mmc_claim_host(host); mmc_claim_host(host);
mmc_power_off(host); mmc_power_off(host);
mmc_release_host(host); mmc_release_host(host);
...@@ -3019,7 +2995,6 @@ void mmc_unregister_pm_notifier(struct mmc_host *host) ...@@ -3019,7 +2995,6 @@ void mmc_unregister_pm_notifier(struct mmc_host *host)
*/ */
void mmc_init_context_info(struct mmc_host *host) void mmc_init_context_info(struct mmc_host *host)
{ {
spin_lock_init(&host->context_info.lock);
host->context_info.is_new_req = false; host->context_info.is_new_req = false;
host->context_info.is_done_rcv = false; host->context_info.is_done_rcv = false;
host->context_info.is_waiting_last_req = false; host->context_info.is_waiting_last_req = false;
......
...@@ -321,7 +321,11 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) ...@@ -321,7 +321,11 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
for (i = 0; i < 512; i++) for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]); n += sprintf(buf + n, "%02x", ext_csd[i]);
n += sprintf(buf + n, "\n"); n += sprintf(buf + n, "\n");
BUG_ON(n != EXT_CSD_STR_LEN);
if (n != EXT_CSD_STR_LEN) {
err = -EINVAL;
goto out_free;
}
filp->private_data = buf; filp->private_data = buf;
kfree(ext_csd); kfree(ext_csd);
......
...@@ -618,6 +618,24 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -618,6 +618,24 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
} }
/* eMMC v5.1 or later */
if (card->ext_csd.rev >= 8) {
card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT] &
EXT_CSD_CMDQ_SUPPORTED;
card->ext_csd.cmdq_depth = (ext_csd[EXT_CSD_CMDQ_DEPTH] &
EXT_CSD_CMDQ_DEPTH_MASK) + 1;
/* Exclude inefficiently small queue depths */
if (card->ext_csd.cmdq_depth <= 2) {
card->ext_csd.cmdq_support = false;
card->ext_csd.cmdq_depth = 0;
}
if (card->ext_csd.cmdq_support) {
pr_debug("%s: Command Queue supported depth %u\n",
mmc_hostname(card->host),
card->ext_csd.cmdq_depth);
}
}
out: out:
return err; return err;
} }
...@@ -1003,19 +1021,6 @@ static int mmc_select_bus_width(struct mmc_card *card) ...@@ -1003,19 +1021,6 @@ static int mmc_select_bus_width(struct mmc_card *card)
return err; return err;
} }
/* Caller must hold re-tuning */
static int mmc_switch_status(struct mmc_card *card)
{
u32 status;
int err;
err = mmc_send_status(card, &status);
if (err)
return err;
return mmc_switch_status_error(card->host, status);
}
/* /*
* Switch to the high-speed mode * Switch to the high-speed mode
*/ */
...@@ -1025,13 +1030,8 @@ static int mmc_select_hs(struct mmc_card *card) ...@@ -1025,13 +1030,8 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
true, false, true); true, true, true);
if (!err) {
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card);
}
if (err) if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n", pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err); mmc_hostname(card->host), err);
...@@ -1058,10 +1058,12 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ...@@ -1058,10 +1058,12 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH,
ext_csd_bits, ext_csd_bits,
card->ext_csd.generic_cmd6_time); card->ext_csd.generic_cmd6_time,
MMC_TIMING_MMC_DDR52,
true, true, true);
if (err) { if (err) {
pr_err("%s: switch to bus width %d ddr failed\n", pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width); mmc_hostname(host), 1 << bus_width);
...@@ -1104,9 +1106,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ...@@ -1104,9 +1106,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
if (err) if (err)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
if (!err)
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
return err; return err;
} }
...@@ -1128,7 +1127,7 @@ static int mmc_select_hs400(struct mmc_card *card) ...@@ -1128,7 +1127,7 @@ static int mmc_select_hs400(struct mmc_card *card)
val = EXT_CSD_TIMING_HS; val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val, EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) { if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
...@@ -1163,7 +1162,7 @@ static int mmc_select_hs400(struct mmc_card *card) ...@@ -1163,7 +1162,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT; card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val, EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) { if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n", pr_err("%s: switch to hs400 failed, err:%d\n",
...@@ -1206,7 +1205,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) ...@@ -1206,7 +1205,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS400 to HS DDR */ /* Switch HS400 to HS DDR */
val = EXT_CSD_TIMING_HS; val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, val, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) if (err)
goto out_err; goto out_err;
...@@ -1220,7 +1219,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) ...@@ -1220,7 +1219,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS DDR to HS */ /* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time, EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
true, false, true); 0, true, false, true);
if (err) if (err)
goto out_err; goto out_err;
...@@ -1234,14 +1233,19 @@ int mmc_hs400_to_hs200(struct mmc_card *card) ...@@ -1234,14 +1233,19 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS200 | val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT; card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, val, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) if (err)
goto out_err; goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_HS200); mmc_set_timing(host, MMC_TIMING_MMC_HS200);
err = mmc_switch_status(card); /*
* For HS200, CRC errors are not a reliable way to know the switch
* failed. If there really is a problem, we would expect tuning will
* fail and the result ends up the same.
*/
err = __mmc_switch_status(card, false);
if (err) if (err)
goto out_err; goto out_err;
...@@ -1281,16 +1285,23 @@ static int mmc_select_hs400es(struct mmc_card *card) ...@@ -1281,16 +1285,23 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err; goto out_err;
/* Switch card to HS mode */ /* Switch card to HS mode */
err = mmc_select_hs(card); err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
if (err) EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to hs for hs400es failed, err:%d\n",
mmc_hostname(host), err);
goto out_err; goto out_err;
}
mmc_set_clock(host, card->ext_csd.hs_max_dtr); mmc_set_timing(host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card); err = mmc_switch_status(card);
if (err) if (err)
goto out_err; goto out_err;
mmc_set_clock(host, card->ext_csd.hs_max_dtr);
/* Switch card to DDR with strobe bit */ /* Switch card to DDR with strobe bit */
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE; val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
...@@ -1308,7 +1319,7 @@ static int mmc_select_hs400es(struct mmc_card *card) ...@@ -1308,7 +1319,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT; card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val, EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) { if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n", pr_err("%s: switch to hs400es failed, err:%d\n",
...@@ -1390,14 +1401,20 @@ static int mmc_select_hs200(struct mmc_card *card) ...@@ -1390,14 +1401,20 @@ static int mmc_select_hs200(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT; card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val, EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time, 0,
true, false, true); true, false, true);
if (err) if (err)
goto err; goto err;
old_timing = host->ios.timing; old_timing = host->ios.timing;
mmc_set_timing(host, MMC_TIMING_MMC_HS200); mmc_set_timing(host, MMC_TIMING_MMC_HS200);
err = mmc_switch_status(card); /*
* For HS200, CRC errors are not a reliable way to know the
* switch failed. If there really is a problem, we would expect
* tuning will fail and the result ends up the same.
*/
err = __mmc_switch_status(card, false);
/* /*
* mmc_select_timing() assumes timing has not changed if * mmc_select_timing() assumes timing has not changed if
* it is a switch error. * it is a switch error.
...@@ -1480,7 +1497,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1480,7 +1497,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4]; u32 cid[4];
u32 rocr; u32 rocr;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
/* Set correct bus mode for MMC before attempting init */ /* Set correct bus mode for MMC before attempting init */
...@@ -1854,7 +1870,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) ...@@ -1854,7 +1870,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION, EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout, true, false, false); notify_type, timeout, 0, true, false, false);
if (err) if (err)
pr_err("%s: Power Off Notification timed out, %u\n", pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout); mmc_hostname(card->host), timeout);
...@@ -1870,9 +1886,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) ...@@ -1870,9 +1886,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
*/ */
static void mmc_remove(struct mmc_host *host) static void mmc_remove(struct mmc_host *host)
{ {
BUG_ON(!host);
BUG_ON(!host->card);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
} }
...@@ -1892,9 +1905,6 @@ static void mmc_detect(struct mmc_host *host) ...@@ -1892,9 +1905,6 @@ static void mmc_detect(struct mmc_host *host)
{ {
int err; int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_get_card(host->card); mmc_get_card(host->card);
/* /*
...@@ -1920,9 +1930,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) ...@@ -1920,9 +1930,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT : unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
EXT_CSD_POWER_OFF_LONG; EXT_CSD_POWER_OFF_LONG;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_suspended(host->card)) if (mmc_card_suspended(host->card))
...@@ -1979,9 +1986,6 @@ static int _mmc_resume(struct mmc_host *host) ...@@ -1979,9 +1986,6 @@ static int _mmc_resume(struct mmc_host *host)
{ {
int err = 0; int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (!mmc_card_suspended(host->card)) if (!mmc_card_suspended(host->card))
...@@ -2114,7 +2118,6 @@ int mmc_attach_mmc(struct mmc_host *host) ...@@ -2114,7 +2118,6 @@ int mmc_attach_mmc(struct mmc_host *host)
int err; int err;
u32 ocr, rocr; u32 ocr, rocr;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
/* Set correct bus mode for MMC before attempting attach */ /* Set correct bus mode for MMC before attempting attach */
......
...@@ -54,21 +54,15 @@ static const u8 tuning_blk_pattern_8bit[] = { ...@@ -54,21 +54,15 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
}; };
static inline int __mmc_send_status(struct mmc_card *card, u32 *status, int mmc_send_status(struct mmc_card *card, u32 *status)
bool ignore_crc)
{ {
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SEND_STATUS; cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host)) if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16; cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
if (ignore_crc)
cmd.flags &= ~MMC_RSP_CRC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err) if (err)
...@@ -83,17 +77,10 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status, ...@@ -83,17 +77,10 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
return 0; return 0;
} }
int mmc_send_status(struct mmc_card *card, u32 *status)
{
return __mmc_send_status(card, status, false);
}
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host);
cmd.opcode = MMC_SELECT_CARD; cmd.opcode = MMC_SELECT_CARD;
if (card) { if (card) {
...@@ -109,7 +96,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) ...@@ -109,7 +96,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int mmc_select_card(struct mmc_card *card) int mmc_select_card(struct mmc_card *card)
{ {
BUG_ON(!card);
return _mmc_select_card(card->host, card); return _mmc_select_card(card->host, card);
} }
...@@ -181,8 +167,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -181,8 +167,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
int i, err = 0; int i, err = 0;
BUG_ON(!host);
cmd.opcode = MMC_SEND_OP_COND; cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
...@@ -221,9 +205,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) ...@@ -221,9 +205,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cid);
cmd.opcode = MMC_ALL_SEND_CID; cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0; cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
...@@ -241,9 +222,6 @@ int mmc_set_relative_addr(struct mmc_card *card) ...@@ -241,9 +222,6 @@ int mmc_set_relative_addr(struct mmc_card *card)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16; cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
...@@ -257,9 +235,6 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) ...@@ -257,9 +235,6 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cxd);
cmd.opcode = opcode; cmd.opcode = opcode;
cmd.arg = arg; cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
...@@ -440,7 +415,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) ...@@ -440,7 +415,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
return err; return err;
} }
int mmc_switch_status_error(struct mmc_host *host, u32 status) static int mmc_switch_status_error(struct mmc_host *host, u32 status)
{ {
if (mmc_host_is_spi(host)) { if (mmc_host_is_spi(host)) {
if (status & R1_SPI_ILLEGAL_COMMAND) if (status & R1_SPI_ILLEGAL_COMMAND)
...@@ -455,6 +430,88 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status) ...@@ -455,6 +430,88 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
return 0; return 0;
} }
/* Caller must hold re-tuning */
int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
{
u32 status;
int err;
err = mmc_send_status(card, &status);
if (!crc_err_fatal && err == -EILSEQ)
return 0;
if (err)
return err;
return mmc_switch_status_error(card->host, status);
}
int mmc_switch_status(struct mmc_card *card)
{
return __mmc_switch_status(card, true);
}
static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
bool send_status, bool retry_crc_err)
{
struct mmc_host *host = card->host;
int err;
unsigned long timeout;
u32 status = 0;
bool expired = false;
bool busy = false;
/* We have an unspecified cmd timeout, use the fallback value. */
if (!timeout_ms)
timeout_ms = MMC_OPS_TIMEOUT_MS;
/*
* In cases when not allowed to poll by using CMD13 or because we aren't
* capable of polling by using ->card_busy(), then rely on waiting the
* stated timeout to be sufficient.
*/
if (!send_status && !host->ops->card_busy) {
mmc_delay(timeout_ms);
return 0;
}
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
/*
* Due to the possibility of being preempted while polling,
* check the expiration time first.
*/
expired = time_after(jiffies, timeout);
if (host->ops->card_busy) {
busy = host->ops->card_busy(host);
} else {
err = mmc_send_status(card, &status);
if (retry_crc_err && err == -EILSEQ) {
busy = true;
} else if (err) {
return err;
} else {
err = mmc_switch_status_error(host, status);
if (err)
return err;
busy = R1_CURRENT_STATE(status) == R1_STATE_PRG;
}
}
/* Timeout if the device still remains busy. */
if (expired && busy) {
pr_err("%s: Card stuck being busy! %s\n",
mmc_hostname(host), __func__);
return -ETIMEDOUT;
}
} while (busy);
if (host->ops->card_busy && send_status)
return mmc_switch_status(card);
return 0;
}
/** /**
* __mmc_switch - modify EXT_CSD register * __mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer * @card: the MMC card associated with the data transfer
...@@ -463,24 +520,22 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status) ...@@ -463,24 +520,22 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
* @value: value to program into EXT_CSD register * @value: value to program into EXT_CSD register
* @timeout_ms: timeout (ms) for operation performed by register write, * @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout * timeout of zero implies maximum possible timeout
* @timing: new timing to change to
* @use_busy_signal: use the busy signal as response type * @use_busy_signal: use the busy signal as response type
* @send_status: send status cmd to poll for busy * @send_status: send status cmd to poll for busy
* @ignore_crc: ignore CRC errors when sending status cmd to poll for busy * @retry_crc_err: retry when CRC errors when polling with CMD13 for busy
* *
* Modifies the EXT_CSD register for selected card. * Modifies the EXT_CSD register for selected card.
*/ */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal, bool send_status, unsigned int timeout_ms, unsigned char timing,
bool ignore_crc) bool use_busy_signal, bool send_status, bool retry_crc_err)
{ {
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
unsigned long timeout;
u32 status = 0;
bool use_r1b_resp = use_busy_signal; bool use_r1b_resp = use_busy_signal;
bool expired = false; unsigned char old_timing = host->ios.timing;
bool busy = false;
mmc_retune_hold(host); mmc_retune_hold(host);
...@@ -522,62 +577,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -522,62 +577,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (!use_busy_signal) if (!use_busy_signal)
goto out; goto out;
/* /* Switch to new timing before poll and check switch status. */
* CRC errors shall only be ignored in cases were CMD13 is used to poll if (timing)
* to detect busy completion. mmc_set_timing(host, timing);
*/
if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
ignore_crc = false;
/* We have an unspecified cmd timeout, use the fallback value. */
if (!timeout_ms)
timeout_ms = MMC_OPS_TIMEOUT_MS;
/* Must check status to be sure of no errors. */
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
/*
* Due to the possibility of being preempted after
* sending the status command, check the expiration
* time first.
*/
expired = time_after(jiffies, timeout);
if (send_status) {
err = __mmc_send_status(card, &status, ignore_crc);
if (err)
goto out;
}
if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
break;
if (host->ops->card_busy) {
if (!host->ops->card_busy(host))
break;
busy = true;
}
if (mmc_host_is_spi(host))
break;
/* /*If SPI or used HW busy detection above, then we don't need to poll. */
* We are not allowed to issue a status command and the host if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
* does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only mmc_host_is_spi(host)) {
* rely on waiting for the stated timeout to be sufficient. if (send_status)
*/ err = mmc_switch_status(card);
if (!send_status && !host->ops->card_busy) { goto out_tim;
mmc_delay(timeout_ms); }
goto out;
}
/* Timeout if the device never leaves the program state. */ /* Let's try to poll to find out when the command is completed. */
if (expired && err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
(R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(host), __func__);
err = -ETIMEDOUT;
goto out;
}
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
err = mmc_switch_status_error(host, status); out_tim:
if (err && timing)
mmc_set_timing(host, old_timing);
out: out:
mmc_retune_release(host); mmc_retune_release(host);
...@@ -587,8 +604,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -587,8 +604,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms) unsigned int timeout_ms)
{ {
return __mmc_switch(card, set, index, value, timeout_ms, true, true, return __mmc_switch(card, set, index, value, timeout_ms, 0,
false); true, true, false);
} }
EXPORT_SYMBOL_GPL(mmc_switch); EXPORT_SYMBOL_GPL(mmc_switch);
...@@ -661,6 +678,31 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error) ...@@ -661,6 +678,31 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
} }
EXPORT_SYMBOL_GPL(mmc_send_tuning); EXPORT_SYMBOL_GPL(mmc_send_tuning);
int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
{
struct mmc_command cmd = {0};
/*
* eMMC specification specifies that CMD12 can be used to stop a tuning
* command, but SD specification does not, so do nothing unless it is
* eMMC.
*/
if (opcode != MMC_SEND_TUNING_BLOCK_HS200)
return 0;
cmd.opcode = MMC_STOP_TRANSMISSION;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
/*
* For drivers that override R1 to R1b, set an arbitrary timeout based
* on the tuning timeout i.e. 150ms.
*/
cmd.busy_timeout = 150;
return mmc_wait_for_cmd(host, &cmd, 0);
}
EXPORT_SYMBOL_GPL(mmc_abort_tuning);
static int static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len) u8 len)
......
...@@ -27,10 +27,11 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc); ...@@ -27,10 +27,11 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_can_ext_csd(struct mmc_card *card); int mmc_can_ext_csd(struct mmc_card *card);
int mmc_switch_status_error(struct mmc_host *host, u32 status); int mmc_switch_status(struct mmc_card *card);
int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal, bool send_status, unsigned int timeout_ms, unsigned char timing,
bool ignore_crc); bool use_busy_signal, bool send_status, bool retry_crc_err);
#endif #endif
...@@ -927,7 +927,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -927,7 +927,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4]; u32 cid[4];
u32 rocr = 0; u32 rocr = 0;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_sd_get_cid(host, ocr, cid, &rocr); err = mmc_sd_get_cid(host, ocr, cid, &rocr);
...@@ -1043,9 +1042,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -1043,9 +1042,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
*/ */
static void mmc_sd_remove(struct mmc_host *host) static void mmc_sd_remove(struct mmc_host *host)
{ {
BUG_ON(!host);
BUG_ON(!host->card);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
} }
...@@ -1065,9 +1061,6 @@ static void mmc_sd_detect(struct mmc_host *host) ...@@ -1065,9 +1061,6 @@ static void mmc_sd_detect(struct mmc_host *host)
{ {
int err; int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_get_card(host->card); mmc_get_card(host->card);
/* /*
...@@ -1091,9 +1084,6 @@ static int _mmc_sd_suspend(struct mmc_host *host) ...@@ -1091,9 +1084,6 @@ static int _mmc_sd_suspend(struct mmc_host *host)
{ {
int err = 0; int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_suspended(host->card)) if (mmc_card_suspended(host->card))
...@@ -1136,9 +1126,6 @@ static int _mmc_sd_resume(struct mmc_host *host) ...@@ -1136,9 +1126,6 @@ static int _mmc_sd_resume(struct mmc_host *host)
{ {
int err = 0; int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (!mmc_card_suspended(host->card)) if (!mmc_card_suspended(host->card))
...@@ -1221,7 +1208,6 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1221,7 +1208,6 @@ int mmc_attach_sd(struct mmc_host *host)
int err; int err;
u32 ocr, rocr; u32 ocr, rocr;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_send_app_op_cond(host, 0, &ocr); err = mmc_send_app_op_cond(host, 0, &ocr);
......
...@@ -27,8 +27,8 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) ...@@ -27,8 +27,8 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host); if (WARN_ON(card && card->host != host))
BUG_ON(card && (card->host != host)); return -EINVAL;
cmd.opcode = MMC_APP_CMD; cmd.opcode = MMC_APP_CMD;
...@@ -72,8 +72,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, ...@@ -72,8 +72,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
int i, err; int i, err;
BUG_ON(!cmd); if (retries < 0)
BUG_ON(retries < 0); retries = MMC_CMD_RETRIES;
err = -EIO; err = -EIO;
...@@ -122,9 +122,6 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) ...@@ -122,9 +122,6 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
...@@ -147,8 +144,6 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -147,8 +144,6 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
int i, err = 0; int i, err = 0;
BUG_ON(!host);
cmd.opcode = SD_APP_OP_COND; cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host)) if (mmc_host_is_spi(host))
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
...@@ -224,9 +219,6 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) ...@@ -224,9 +219,6 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!rca);
cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0; cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
...@@ -249,10 +241,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) ...@@ -249,10 +241,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
struct scatterlist sg; struct scatterlist sg;
void *data_buf; void *data_buf;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!scr);
/* NOTE: caller guarantees scr is heap-allocated */ /* NOTE: caller guarantees scr is heap-allocated */
err = mmc_app_cmd(card->host, card); err = mmc_app_cmd(card->host, card);
...@@ -307,9 +295,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, ...@@ -307,9 +295,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
struct mmc_data data = {0}; struct mmc_data data = {0};
struct scatterlist sg; struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
/* NOTE: caller guarantees resp is heap-allocated */ /* NOTE: caller guarantees resp is heap-allocated */
mode = !!mode; mode = !!mode;
...@@ -352,10 +337,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr) ...@@ -352,10 +337,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
struct mmc_data data = {0}; struct mmc_data data = {0};
struct scatterlist sg; struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!ssr);
/* NOTE: caller guarantees ssr is heap-allocated */ /* NOTE: caller guarantees ssr is heap-allocated */
err = mmc_app_cmd(card->host, card); err = mmc_app_cmd(card->host, card);
......
...@@ -63,7 +63,8 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) ...@@ -63,7 +63,8 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
int ret; int ret;
struct sdio_func *func; struct sdio_func *func;
BUG_ON(fn > SDIO_MAX_FUNCS); if (WARN_ON(fn > SDIO_MAX_FUNCS))
return -EINVAL;
func = sdio_alloc_func(card); func = sdio_alloc_func(card);
if (IS_ERR(func)) if (IS_ERR(func))
...@@ -555,7 +556,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -555,7 +556,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
u32 rocr = 0; u32 rocr = 0;
u32 ocr_card = ocr; u32 ocr_card = ocr;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
/* to query card if 1.8V signalling is supported */ /* to query card if 1.8V signalling is supported */
...@@ -791,9 +791,6 @@ static void mmc_sdio_remove(struct mmc_host *host) ...@@ -791,9 +791,6 @@ static void mmc_sdio_remove(struct mmc_host *host)
{ {
int i; int i;
BUG_ON(!host);
BUG_ON(!host->card);
for (i = 0;i < host->card->sdio_funcs;i++) { for (i = 0;i < host->card->sdio_funcs;i++) {
if (host->card->sdio_func[i]) { if (host->card->sdio_func[i]) {
sdio_remove_func(host->card->sdio_func[i]); sdio_remove_func(host->card->sdio_func[i]);
...@@ -820,9 +817,6 @@ static void mmc_sdio_detect(struct mmc_host *host) ...@@ -820,9 +817,6 @@ static void mmc_sdio_detect(struct mmc_host *host)
{ {
int err; int err;
BUG_ON(!host);
BUG_ON(!host->card);
/* Make sure card is powered before detecting it */ /* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) { if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev); err = pm_runtime_get_sync(&host->card->dev);
...@@ -916,9 +910,6 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -916,9 +910,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
{ {
int err = 0; int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
/* Basic card reinitialization. */ /* Basic card reinitialization. */
mmc_claim_host(host); mmc_claim_host(host);
...@@ -970,9 +961,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) ...@@ -970,9 +961,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
{ {
int ret; int ret;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
/* /*
...@@ -1063,7 +1051,6 @@ int mmc_attach_sdio(struct mmc_host *host) ...@@ -1063,7 +1051,6 @@ int mmc_attach_sdio(struct mmc_host *host)
u32 ocr, rocr; u32 ocr, rocr;
struct mmc_card *card; struct mmc_card *card;
BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_send_io_op_cond(host, 0, &ocr); err = mmc_send_io_op_cond(host, 0, &ocr);
......
...@@ -262,7 +262,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) ...@@ -262,7 +262,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
else else
prev = &card->tuples; prev = &card->tuples;
BUG_ON(*prev); if (*prev)
return -EINVAL;
do { do {
unsigned char tpl_code, tpl_link; unsigned char tpl_code, tpl_link;
......
...@@ -214,7 +214,9 @@ static int sdio_card_irq_put(struct mmc_card *card) ...@@ -214,7 +214,9 @@ static int sdio_card_irq_put(struct mmc_card *card)
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
BUG_ON(host->sdio_irqs < 1);
if (host->sdio_irqs < 1)
return -EINVAL;
if (!--host->sdio_irqs) { if (!--host->sdio_irqs) {
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
...@@ -261,8 +263,8 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) ...@@ -261,8 +263,8 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
int ret; int ret;
unsigned char reg; unsigned char reg;
BUG_ON(!func); if (!func)
BUG_ON(!func->card); return -EINVAL;
pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func)); pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
...@@ -304,8 +306,8 @@ int sdio_release_irq(struct sdio_func *func) ...@@ -304,8 +306,8 @@ int sdio_release_irq(struct sdio_func *func)
int ret; int ret;
unsigned char reg; unsigned char reg;
BUG_ON(!func); if (!func)
BUG_ON(!func->card); return -EINVAL;
pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func)); pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
......
...@@ -258,6 +258,14 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, ...@@ -258,6 +258,14 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
} }
EXPORT_SYMBOL(mmc_gpiod_request_cd); EXPORT_SYMBOL(mmc_gpiod_request_cd);
bool mmc_can_gpio_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
return ctx->cd_gpio ? true : false;
}
EXPORT_SYMBOL(mmc_can_gpio_cd);
/** /**
* mmc_gpiod_request_ro - request a gpio descriptor for write protection * mmc_gpiod_request_ro - request a gpio descriptor for write protection
* @host: mmc host * @host: mmc host
......
...@@ -135,7 +135,6 @@ config MMC_SDHCI_OF_AT91 ...@@ -135,7 +135,6 @@ config MMC_SDHCI_OF_AT91
tristate "SDHCI OF support for the Atmel SDMMC controller" tristate "SDHCI OF support for the Atmel SDMMC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on OF depends on OF
select MMC_SDHCI_IO_ACCESSORS
help help
This selects the Atmel SDMMC driver This selects the Atmel SDMMC driver
...@@ -144,6 +143,7 @@ config MMC_SDHCI_OF_ESDHC ...@@ -144,6 +143,7 @@ config MMC_SDHCI_OF_ESDHC
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select FSL_GUTS
help help
This selects the Freescale eSDHC controller support. This selects the Freescale eSDHC controller support.
...@@ -165,6 +165,17 @@ config MMC_SDHCI_OF_HLWD ...@@ -165,6 +165,17 @@ config MMC_SDHCI_OF_HLWD
If unsure, say N. If unsure, say N.
config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM
depends on OF
help
This selects the Cadence SD/SDIO/eMMC driver.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_CNS3XXX config MMC_SDHCI_CNS3XXX
tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX depends on ARCH_CNS3XXX
...@@ -322,6 +333,16 @@ config MMC_SDHCI_IPROC ...@@ -322,6 +333,16 @@ config MMC_SDHCI_IPROC
If unsure, say N. If unsure, say N.
config MMC_MESON_GX
tristate "Amlogic S905/GX* SD/MMC Host Controller support"
depends on ARCH_MESON && MMC
help
This selects support for the Amlogic SD/MMC Host Controller
found on the S905/GX* family of SoCs. This controller is
MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
If you have a controller with this interface, say Y here.
config MMC_MOXART config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support" tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC depends on ARCH_MOXART && MMC
......
...@@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o ...@@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o
obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
...@@ -62,6 +63,7 @@ obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o ...@@ -62,6 +63,7 @@ obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o 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
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/platform_data/mmc-davinci.h> #include <linux/platform_data/mmc-davinci.h>
...@@ -1029,9 +1030,10 @@ static int mmc_davinci_get_cd(struct mmc_host *mmc) ...@@ -1029,9 +1030,10 @@ static int mmc_davinci_get_cd(struct mmc_host *mmc)
struct platform_device *pdev = to_platform_device(mmc->parent); struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *config = pdev->dev.platform_data; struct davinci_mmc_config *config = pdev->dev.platform_data;
if (!config || !config->get_cd) if (config && config->get_cd)
return -ENOSYS; return config->get_cd(pdev->id);
return config->get_cd(pdev->id);
return mmc_gpio_get_cd(mmc);
} }
static int mmc_davinci_get_ro(struct mmc_host *mmc) static int mmc_davinci_get_ro(struct mmc_host *mmc)
...@@ -1039,9 +1041,10 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) ...@@ -1039,9 +1041,10 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc)
struct platform_device *pdev = to_platform_device(mmc->parent); struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *config = pdev->dev.platform_data; struct davinci_mmc_config *config = pdev->dev.platform_data;
if (!config || !config->get_ro) if (config && config->get_ro)
return -ENOSYS; return config->get_ro(pdev->id);
return config->get_ro(pdev->id);
return mmc_gpio_get_ro(mmc);
} }
static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
...@@ -1159,49 +1162,53 @@ static const struct of_device_id davinci_mmc_dt_ids[] = { ...@@ -1159,49 +1162,53 @@ static const struct of_device_id davinci_mmc_dt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, davinci_mmc_dt_ids); MODULE_DEVICE_TABLE(of, davinci_mmc_dt_ids);
static struct davinci_mmc_config static int mmc_davinci_parse_pdata(struct mmc_host *mmc)
*mmc_parse_pdata(struct platform_device *pdev)
{ {
struct device_node *np; struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *pdata = pdev->dev.platform_data; struct davinci_mmc_config *pdata = pdev->dev.platform_data;
const struct of_device_id *match = struct mmc_davinci_host *host;
of_match_device(davinci_mmc_dt_ids, &pdev->dev); int ret;
u32 data;
np = pdev->dev.of_node;
if (!np)
return pdata;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev, "Failed to allocate memory for struct davinci_mmc_config\n");
goto nodata;
}
if (match) if (!pdata)
pdev->id_entry = match->data; return -EINVAL;
if (of_property_read_u32(np, "max-frequency", &pdata->max_freq)) host = mmc_priv(mmc);
dev_info(&pdev->dev, "'max-frequency' property not specified, defaulting to 25MHz\n"); if (!host)
return -EINVAL;
of_property_read_u32(np, "bus-width", &data); if (pdata && pdata->nr_sg)
switch (data) { host->nr_sg = pdata->nr_sg - 1;
case 1:
case 4: if (pdata && (pdata->wires == 4 || pdata->wires == 0))
case 8: mmc->caps |= MMC_CAP_4_BIT_DATA;
pdata->wires = data;
break; if (pdata && (pdata->wires == 8))
default: mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
pdata->wires = 1;
dev_info(&pdev->dev, "Unsupported buswidth, defaulting to 1 bit\n"); mmc->f_min = 312500;
} mmc->f_max = 25000000;
nodata: if (pdata && pdata->max_freq)
return pdata; mmc->f_max = pdata->max_freq;
if (pdata && pdata->caps)
mmc->caps |= pdata->caps;
/* Register a cd gpio, if there is not one, enable polling */
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
return ret;
else if (ret)
mmc->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
return ret;
return 0;
} }
static int __init davinci_mmcsd_probe(struct platform_device *pdev) static int __init davinci_mmcsd_probe(struct platform_device *pdev)
{ {
struct davinci_mmc_config *pdata = NULL; const struct of_device_id *match;
struct mmc_davinci_host *host = NULL; struct mmc_davinci_host *host = NULL;
struct mmc_host *mmc = NULL; struct mmc_host *mmc = NULL;
struct resource *r, *mem = NULL; struct resource *r, *mem = NULL;
...@@ -1209,12 +1216,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1209,12 +1216,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
size_t mem_size; size_t mem_size;
const struct platform_device_id *id_entry; const struct platform_device_id *id_entry;
pdata = mmc_parse_pdata(pdev);
if (pdata == NULL) {
dev_err(&pdev->dev, "Couldn't get platform data\n");
return -ENOENT;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) if (!r)
return -ENODEV; return -ENODEV;
...@@ -1253,14 +1254,28 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1253,14 +1254,28 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->mmc_input_clk = clk_get_rate(host->clk); host->mmc_input_clk = clk_get_rate(host->clk);
init_mmcsd_host(host); match = of_match_device(davinci_mmc_dt_ids, &pdev->dev);
if (match) {
if (pdata->nr_sg) pdev->id_entry = match->data;
host->nr_sg = pdata->nr_sg - 1; ret = mmc_of_parse(mmc);
if (ret) {
dev_err(&pdev->dev,
"could not parse of data: %d\n", ret);
goto parse_fail;
}
} else {
ret = mmc_davinci_parse_pdata(mmc);
if (ret) {
dev_err(&pdev->dev,
"could not parse platform data: %d\n", ret);
goto parse_fail;
} }
if (host->nr_sg > MAX_NR_SG || !host->nr_sg) if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
host->nr_sg = MAX_NR_SG; host->nr_sg = MAX_NR_SG;
init_mmcsd_host(host);
host->use_dma = use_dma; host->use_dma = use_dma;
host->mmc_irq = irq; host->mmc_irq = irq;
host->sdio_irq = platform_get_irq(pdev, 1); host->sdio_irq = platform_get_irq(pdev, 1);
...@@ -1273,27 +1288,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1273,27 +1288,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->use_dma = 0; host->use_dma = 0;
} }
/* REVISIT: someday, support IRQ-driven card detection. */
mmc->caps |= MMC_CAP_NEEDS_POLL;
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
if (pdata && (pdata->wires == 4 || pdata->wires == 0))
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (pdata && (pdata->wires == 8))
mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
id_entry = platform_get_device_id(pdev); id_entry = platform_get_device_id(pdev);
if (id_entry) if (id_entry)
host->version = id_entry->driver_data; host->version = id_entry->driver_data;
mmc->ops = &mmc_davinci_ops; mmc->ops = &mmc_davinci_ops;
mmc->f_min = 312500;
mmc->f_max = 25000000;
if (pdata && pdata->max_freq)
mmc->f_max = pdata->max_freq;
if (pdata && pdata->caps)
mmc->caps |= pdata->caps;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
/* With no iommu coalescing pages, each phys_seg is a hw_seg. /* With no iommu coalescing pages, each phys_seg is a hw_seg.
...@@ -1354,6 +1355,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1354,6 +1355,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
mmc_davinci_cpufreq_deregister(host); mmc_davinci_cpufreq_deregister(host);
cpu_freq_fail: cpu_freq_fail:
davinci_release_dma_channels(host); davinci_release_dma_channels(host);
parse_fail:
dma_probe_defer: dma_probe_defer:
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
clk_prepare_enable_fail: clk_prepare_enable_fail:
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "dw_mmc.h" #include "dw_mmc.h"
...@@ -161,20 +162,13 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) ...@@ -161,20 +162,13 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags); set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM
static int dw_mci_exynos_suspend(struct device *dev) static int dw_mci_exynos_runtime_resume(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
return dw_mci_suspend(host);
}
static int dw_mci_exynos_resume(struct device *dev)
{ {
struct dw_mci *host = dev_get_drvdata(dev); struct dw_mci *host = dev_get_drvdata(dev);
dw_mci_exynos_config_smu(host); dw_mci_exynos_config_smu(host);
return dw_mci_resume(host); return dw_mci_runtime_resume(dev);
} }
/** /**
...@@ -211,10 +205,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) ...@@ -211,10 +205,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
return 0; return 0;
} }
#else #else
#define dw_mci_exynos_suspend NULL
#define dw_mci_exynos_resume NULL
#define dw_mci_exynos_resume_noirq NULL #define dw_mci_exynos_resume_noirq NULL
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{ {
...@@ -524,14 +516,42 @@ static int dw_mci_exynos_probe(struct platform_device *pdev) ...@@ -524,14 +516,42 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
{ {
const struct dw_mci_drv_data *drv_data; const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match; const struct of_device_id *match;
int ret;
match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
drv_data = match->data; drv_data = match->data;
return dw_mci_pltfm_register(pdev, drv_data);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = dw_mci_pltfm_register(pdev, drv_data);
if (ret) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return ret;
}
return 0;
}
static int dw_mci_exynos_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return dw_mci_pltfm_remove(pdev);
} }
static const struct dev_pm_ops dw_mci_exynos_pmops = { static const struct dev_pm_ops dw_mci_exynos_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
dw_mci_exynos_runtime_resume,
NULL)
.resume_noirq = dw_mci_exynos_resume_noirq, .resume_noirq = dw_mci_exynos_resume_noirq,
.thaw_noirq = dw_mci_exynos_resume_noirq, .thaw_noirq = dw_mci_exynos_resume_noirq,
.restore_noirq = dw_mci_exynos_resume_noirq, .restore_noirq = dw_mci_exynos_resume_noirq,
...@@ -539,7 +559,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = { ...@@ -539,7 +559,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = {
static struct platform_driver dw_mci_exynos_pltfm_driver = { static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe, .probe = dw_mci_exynos_probe,
.remove = dw_mci_pltfm_remove, .remove = dw_mci_exynos_remove,
.driver = { .driver = {
.name = "dwmmc_exynos", .name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match, .of_match_table = dw_mci_exynos_match,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
...@@ -162,35 +163,13 @@ static int dw_mci_k3_probe(struct platform_device *pdev) ...@@ -162,35 +163,13 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data); return dw_mci_pltfm_register(pdev, drv_data);
} }
#ifdef CONFIG_PM_SLEEP static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = {
static int dw_mci_k3_suspend(struct device *dev) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
{ pm_runtime_force_resume)
struct dw_mci *host = dev_get_drvdata(dev); SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
int ret; dw_mci_runtime_resume,
NULL)
ret = dw_mci_suspend(host); };
if (!ret)
clk_disable_unprepare(host->ciu_clk);
return ret;
}
static int dw_mci_k3_resume(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(host->ciu_clk);
if (ret) {
dev_err(host->dev, "failed to enable ciu clock\n");
return ret;
}
return dw_mci_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
static struct platform_driver dw_mci_k3_pltfm_driver = { static struct platform_driver dw_mci_k3_pltfm_driver = {
.probe = dw_mci_k3_probe, .probe = dw_mci_k3_probe,
...@@ -198,7 +177,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = { ...@@ -198,7 +177,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = {
.driver = { .driver = {
.name = "dwmmc_k3", .name = "dwmmc_k3",
.of_match_table = dw_mci_k3_match, .of_match_table = dw_mci_k3_match,
.pm = &dw_mci_k3_pmops, .pm = &dw_mci_k3_dev_pm_ops,
}, },
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
...@@ -79,25 +80,13 @@ static void dw_mci_pci_remove(struct pci_dev *pdev) ...@@ -79,25 +80,13 @@ static void dw_mci_pci_remove(struct pci_dev *pdev)
dw_mci_remove(host); dw_mci_remove(host);
} }
#ifdef CONFIG_PM_SLEEP static const struct dev_pm_ops dw_mci_pci_dev_pm_ops = {
static int dw_mci_pci_suspend(struct device *dev) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
{ pm_runtime_force_resume)
struct pci_dev *pdev = to_pci_dev(dev); SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
struct dw_mci *host = pci_get_drvdata(pdev); dw_mci_runtime_resume,
NULL)
return dw_mci_suspend(host); };
}
static int dw_mci_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_mci *host = pci_get_drvdata(pdev);
return dw_mci_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
static const struct pci_device_id dw_mci_pci_id[] = { static const struct pci_device_id dw_mci_pci_id[] = {
{ PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) }, { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
...@@ -111,7 +100,7 @@ static struct pci_driver dw_mci_pci_driver = { ...@@ -111,7 +100,7 @@ static struct pci_driver dw_mci_pci_driver = {
.probe = dw_mci_pci_probe, .probe = dw_mci_pci_probe,
.remove = dw_mci_pci_remove, .remove = dw_mci_pci_remove,
.driver = { .driver = {
.pm = &dw_mci_pci_pmops .pm = &dw_mci_pci_dev_pm_ops,
}, },
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
...@@ -58,26 +59,13 @@ int dw_mci_pltfm_register(struct platform_device *pdev, ...@@ -58,26 +59,13 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
} }
EXPORT_SYMBOL_GPL(dw_mci_pltfm_register); EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
#ifdef CONFIG_PM_SLEEP const struct dev_pm_ops dw_mci_pltfm_pmops = {
/* SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
* TODO: we should probably disable the clock to the card in the suspend path. pm_runtime_force_resume)
*/ SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
static int dw_mci_pltfm_suspend(struct device *dev) dw_mci_runtime_resume,
{ NULL)
struct dw_mci *host = dev_get_drvdata(dev); };
return dw_mci_suspend(host);
}
static int dw_mci_pltfm_resume(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
return dw_mci_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
static const struct of_device_id dw_mci_pltfm_match[] = { static const struct of_device_id dw_mci_pltfm_match[] = {
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h> #include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "dw_mmc.h" #include "dw_mmc.h"
...@@ -325,6 +327,7 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) ...@@ -325,6 +327,7 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev)
{ {
const struct dw_mci_drv_data *drv_data; const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match; const struct of_device_id *match;
int ret;
if (!pdev->dev.of_node) if (!pdev->dev.of_node)
return -ENODEV; return -ENODEV;
...@@ -332,16 +335,49 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) ...@@ -332,16 +335,49 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev)
match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node);
drv_data = match->data; drv_data = match->data;
return dw_mci_pltfm_register(pdev, drv_data); pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
ret = dw_mci_pltfm_register(pdev, drv_data);
if (ret) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return ret;
}
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
} }
static int dw_mci_rockchip_remove(struct platform_device *pdev)
{
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return dw_mci_pltfm_remove(pdev);
}
static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
dw_mci_runtime_resume,
NULL)
};
static struct platform_driver dw_mci_rockchip_pltfm_driver = { static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.probe = dw_mci_rockchip_probe, .probe = dw_mci_rockchip_probe,
.remove = dw_mci_pltfm_remove, .remove = dw_mci_rockchip_remove,
.driver = { .driver = {
.name = "dwmmc_rockchip", .name = "dwmmc_rockchip",
.of_match_table = dw_mci_rockchip_match, .of_match_table = dw_mci_rockchip_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_rockchip_dev_pm_ops,
}, },
}; };
......
This diff is collapsed.
...@@ -234,9 +234,9 @@ ...@@ -234,9 +234,9 @@
extern int dw_mci_probe(struct dw_mci *host); extern int dw_mci_probe(struct dw_mci *host);
extern void dw_mci_remove(struct dw_mci *host); extern void dw_mci_remove(struct dw_mci *host);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM
extern int dw_mci_suspend(struct dw_mci *host); extern int dw_mci_runtime_suspend(struct device *device);
extern int dw_mci_resume(struct dw_mci *host); extern int dw_mci_runtime_resume(struct device *device);
#endif #endif
/** /**
...@@ -272,6 +272,7 @@ struct dw_mci_slot { ...@@ -272,6 +272,7 @@ struct dw_mci_slot {
#define DW_MMC_CARD_NEED_INIT 1 #define DW_MMC_CARD_NEED_INIT 1
#define DW_MMC_CARD_NO_LOW_PWR 2 #define DW_MMC_CARD_NO_LOW_PWR 2
#define DW_MMC_CARD_NO_USE_HOLD 3 #define DW_MMC_CARD_NO_USE_HOLD 3
#define DW_MMC_CARD_NEEDS_POLL 4
int id; int id;
int sdio_id; int sdio_id;
}; };
......
...@@ -320,8 +320,7 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host, ...@@ -320,8 +320,7 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
} }
static void jz4740_mmc_pre_request(struct mmc_host *mmc, static void jz4740_mmc_pre_request(struct mmc_host *mmc,
struct mmc_request *mrq, struct mmc_request *mrq)
bool is_first_req)
{ {
struct jz4740_mmc_host *host = mmc_priv(mmc); struct jz4740_mmc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
......
This diff is collapsed.
...@@ -71,7 +71,12 @@ static unsigned int fmax = 515633; ...@@ -71,7 +71,12 @@ static unsigned int fmax = 515633;
* @f_max: maximum clk frequency supported by the controller. * @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated * @signal_direction: input/out direction of bus signals can be indicated
* @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
* @busy_detect: true if busy detection on dat0 is supported * @busy_detect: true if the variant supports busy detection on DAT0.
* @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
* @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
* indicating that the card is busy
* @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
* getting busy end detection interrupts
* @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
* @explicit_mclk_control: enable explicit mclk control in driver. * @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic. * @qcom_fifo: enables qcom specific fifo pio read logic.
...@@ -98,6 +103,9 @@ struct variant_data { ...@@ -98,6 +103,9 @@ struct variant_data {
bool signal_direction; bool signal_direction;
bool pwrreg_clkgate; bool pwrreg_clkgate;
bool busy_detect; bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower; bool pwrreg_nopower;
bool explicit_mclk_control; bool explicit_mclk_control;
bool qcom_fifo; bool qcom_fifo;
...@@ -137,7 +145,7 @@ static struct variant_data variant_u300 = { ...@@ -137,7 +145,7 @@ static struct variant_data variant_u300 = {
.clkreg_enable = MCI_ST_U300_HWFCEN, .clkreg_enable = MCI_ST_U300_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 16, .datalength_bits = 16,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON, .pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000, .f_max = 100000000,
...@@ -152,7 +160,7 @@ static struct variant_data variant_nomadik = { ...@@ -152,7 +160,7 @@ static struct variant_data variant_nomadik = {
.clkreg = MCI_CLK_ENABLE, .clkreg = MCI_CLK_ENABLE,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON, .pwrreg_powerup = MCI_PWR_ON,
...@@ -170,7 +178,7 @@ static struct variant_data variant_ux500 = { ...@@ -170,7 +178,7 @@ static struct variant_data variant_ux500 = {
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON, .pwrreg_powerup = MCI_PWR_ON,
...@@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = { ...@@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = {
.signal_direction = true, .signal_direction = true,
.pwrreg_clkgate = true, .pwrreg_clkgate = true,
.busy_detect = true, .busy_detect = true,
.busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE,
.busy_detect_flag = MCI_ST_CARDBUSY,
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true, .pwrreg_nopower = true,
}; };
...@@ -188,9 +199,9 @@ static struct variant_data variant_ux500v2 = { ...@@ -188,9 +199,9 @@ static struct variant_data variant_ux500v2 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN, .clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datactrl_mask_ddrmode = MCI_ST_DPSM_DDRMODE, .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.blksz_datactrl16 = true, .blksz_datactrl16 = true,
...@@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = { ...@@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = {
.signal_direction = true, .signal_direction = true,
.pwrreg_clkgate = true, .pwrreg_clkgate = true,
.busy_detect = true, .busy_detect = true,
.busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE,
.busy_detect_flag = MCI_ST_CARDBUSY,
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true, .pwrreg_nopower = true,
}; };
...@@ -210,7 +224,7 @@ static struct variant_data variant_qcom = { ...@@ -210,7 +224,7 @@ static struct variant_data variant_qcom = {
MCI_QCOM_CLK_SELECT_IN_FBCLK, MCI_QCOM_CLK_SELECT_IN_FBCLK,
.clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8, .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
.datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE, .datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
.data_cmd_enable = MCI_QCOM_CSPM_DATCMD, .data_cmd_enable = MCI_CPSM_QCOM_DATCMD,
.blksz_datactrl4 = true, .blksz_datactrl4 = true,
.datalength_bits = 24, .datalength_bits = 24,
.pwrreg_powerup = MCI_PWR_UP, .pwrreg_powerup = MCI_PWR_UP,
...@@ -220,6 +234,7 @@ static struct variant_data variant_qcom = { ...@@ -220,6 +234,7 @@ static struct variant_data variant_qcom = {
.qcom_dml = true, .qcom_dml = true,
}; };
/* Busy detection for the ST Micro variant */
static int mmci_card_busy(struct mmc_host *mmc) static int mmci_card_busy(struct mmc_host *mmc)
{ {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
...@@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc) ...@@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc)
int busy = 0; int busy = 0;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY) if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag)
busy = 1; busy = 1;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
...@@ -294,8 +309,8 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) ...@@ -294,8 +309,8 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
*/ */
static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
{ {
/* Keep ST Micro busy mode if enabled */ /* Keep busy mode in DPSM if enabled */
datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE; datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
if (host->datactrl_reg != datactrl) { if (host->datactrl_reg != datactrl) {
host->datactrl_reg = datactrl; host->datactrl_reg = datactrl;
...@@ -684,8 +699,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) ...@@ -684,8 +699,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
next->dma_chan = NULL; next->dma_chan = NULL;
} }
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
bool is_first_req)
{ {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
...@@ -973,37 +987,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -973,37 +987,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status) unsigned int status)
{ {
void __iomem *base = host->base; void __iomem *base = host->base;
bool sbc, busy_resp; bool sbc;
if (!cmd) if (!cmd)
return; return;
sbc = (cmd == host->mrq->sbc); sbc = (cmd == host->mrq->sbc);
busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY);
if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT| /*
MCI_CMDSENT|MCI_CMDRESPEND))) * We need to be one of these interrupts to be considered worth
* handling. Note that we tag on any latent IRQs postponed
* due to waiting for busy status.
*/
if (!((status|host->busy_status) &
(MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND)))
return; return;
/* Check if we need to wait for busy completion. */ /*
if (host->busy_status && (status & MCI_ST_CARDBUSY)) * ST Micro variant: handle busy detection.
return; */
if (host->variant->busy_detect) {
bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
/* Enable busy completion if needed and supported. */ /* We are busy with a command, return */
if (!host->busy_status && busy_resp && if (host->busy_status &&
!(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && (status & host->variant->busy_detect_flag))
(readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) { return;
writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
base + MMCIMASK0); /*
host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND); * We were not busy, but we now got a busy response on
return; * something that was not an error, and we double-check
} * that the special busy status bit is still set before
* proceeding.
*/
if (!host->busy_status && busy_resp &&
!(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
(readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
/* Unmask the busy IRQ */
writel(readl(base + MMCIMASK0) |
host->variant->busy_detect_mask,
base + MMCIMASK0);
/*
* Now cache the last response status code (until
* the busy bit goes low), and return.
*/
host->busy_status =
status & (MCI_CMDSENT|MCI_CMDRESPEND);
return;
}
/* At busy completion, mask the IRQ and complete the request. */ /*
if (host->busy_status) { * At this point we are not busy with a command, we have
writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND, * not received a new busy request, mask the busy IRQ and
base + MMCIMASK0); * fall through to process the IRQ.
host->busy_status = 0; */
if (host->busy_status) {
writel(readl(base + MMCIMASK0) &
~host->variant->busy_detect_mask,
base + MMCIMASK0);
host->busy_status = 0;
}
} }
host->cmd = NULL; host->cmd = NULL;
...@@ -1257,9 +1300,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) ...@@ -1257,9 +1300,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
mmci_data_irq(host, host->data, status); mmci_data_irq(host, host->data, status);
} }
/* Don't poll for busy completion in irq context. */ /*
if (host->busy_status) * Don't poll for busy completion in irq context.
status &= ~MCI_ST_CARDBUSY; */
if (host->variant->busy_detect && host->busy_status)
status &= ~host->variant->busy_detect_flag;
ret = 1; ret = 1;
} while (status); } while (status);
...@@ -1612,9 +1657,18 @@ static int mmci_probe(struct amba_device *dev, ...@@ -1612,9 +1657,18 @@ static int mmci_probe(struct amba_device *dev,
/* We support these capabilities. */ /* We support these capabilities. */
mmc->caps |= MMC_CAP_CMD23; mmc->caps |= MMC_CAP_CMD23;
/*
* Enable busy detection.
*/
if (variant->busy_detect) { if (variant->busy_detect) {
mmci_ops.card_busy = mmci_card_busy; mmci_ops.card_busy = mmci_card_busy;
mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE); /*
* Not all variants have a flag to enable busy detection
* in the DPSM, but if they do, set it here.
*/
if (variant->busy_dpsm_flag)
mmci_write_datactrlreg(host,
host->variant->busy_dpsm_flag);
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
mmc->max_busy_timeout = 0; mmc->max_busy_timeout = 0;
} }
......
...@@ -51,25 +51,27 @@ ...@@ -51,25 +51,27 @@
#define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15)) #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15))
#define MMCIARGUMENT 0x008 #define MMCIARGUMENT 0x008
#define MMCICOMMAND 0x00c
#define MCI_CPSM_RESPONSE (1 << 6)
#define MCI_CPSM_LONGRSP (1 << 7)
#define MCI_CPSM_INTERRUPT (1 << 8)
#define MCI_CPSM_PENDING (1 << 9)
#define MCI_CPSM_ENABLE (1 << 10)
/* Argument flag extenstions in the ST Micro versions */
#define MCI_ST_SDIO_SUSP (1 << 11)
#define MCI_ST_ENCMD_COMPL (1 << 12)
#define MCI_ST_NIEN (1 << 13)
#define MCI_ST_CE_ATACMD (1 << 14)
/* Modified on Qualcomm Integrations */ /* The command register controls the Command Path State Machine (CPSM) */
#define MCI_QCOM_CSPM_DATCMD BIT(12) #define MMCICOMMAND 0x00c
#define MCI_QCOM_CSPM_MCIABORT BIT(13) #define MCI_CPSM_RESPONSE BIT(6)
#define MCI_QCOM_CSPM_CCSENABLE BIT(14) #define MCI_CPSM_LONGRSP BIT(7)
#define MCI_QCOM_CSPM_CCSDISABLE BIT(15) #define MCI_CPSM_INTERRUPT BIT(8)
#define MCI_QCOM_CSPM_AUTO_CMD19 BIT(16) #define MCI_CPSM_PENDING BIT(9)
#define MCI_QCOM_CSPM_AUTO_CMD21 BIT(21) #define MCI_CPSM_ENABLE BIT(10)
/* Command register flag extenstions in the ST Micro versions */
#define MCI_CPSM_ST_SDIO_SUSP BIT(11)
#define MCI_CPSM_ST_ENCMD_COMPL BIT(12)
#define MCI_CPSM_ST_NIEN BIT(13)
#define MCI_CPSM_ST_CE_ATACMD BIT(14)
/* Command register flag extensions in the Qualcomm versions */
#define MCI_CPSM_QCOM_PROGENA BIT(11)
#define MCI_CPSM_QCOM_DATCMD BIT(12)
#define MCI_CPSM_QCOM_MCIABORT BIT(13)
#define MCI_CPSM_QCOM_CCSENABLE BIT(14)
#define MCI_CPSM_QCOM_CCSDISABLE BIT(15)
#define MCI_CPSM_QCOM_AUTO_CMD19 BIT(16)
#define MCI_CPSM_QCOM_AUTO_CMD21 BIT(21)
#define MMCIRESPCMD 0x010 #define MMCIRESPCMD 0x010
#define MMCIRESPONSE0 0x014 #define MMCIRESPONSE0 0x014
...@@ -78,22 +80,27 @@ ...@@ -78,22 +80,27 @@
#define MMCIRESPONSE3 0x020 #define MMCIRESPONSE3 0x020
#define MMCIDATATIMER 0x024 #define MMCIDATATIMER 0x024
#define MMCIDATALENGTH 0x028 #define MMCIDATALENGTH 0x028
/* The data control register controls the Data Path State Machine (DPSM) */
#define MMCIDATACTRL 0x02c #define MMCIDATACTRL 0x02c
#define MCI_DPSM_ENABLE (1 << 0) #define MCI_DPSM_ENABLE BIT(0)
#define MCI_DPSM_DIRECTION (1 << 1) #define MCI_DPSM_DIRECTION BIT(1)
#define MCI_DPSM_MODE (1 << 2) #define MCI_DPSM_MODE BIT(2)
#define MCI_DPSM_DMAENABLE (1 << 3) #define MCI_DPSM_DMAENABLE BIT(3)
#define MCI_DPSM_BLOCKSIZE (1 << 4) #define MCI_DPSM_BLOCKSIZE BIT(4)
/* Control register extensions in the ST Micro U300 and Ux500 versions */ /* Control register extensions in the ST Micro U300 and Ux500 versions */
#define MCI_ST_DPSM_RWSTART (1 << 8) #define MCI_DPSM_ST_RWSTART BIT(8)
#define MCI_ST_DPSM_RWSTOP (1 << 9) #define MCI_DPSM_ST_RWSTOP BIT(9)
#define MCI_ST_DPSM_RWMOD (1 << 10) #define MCI_DPSM_ST_RWMOD BIT(10)
#define MCI_ST_DPSM_SDIOEN (1 << 11) #define MCI_DPSM_ST_SDIOEN BIT(11)
/* Control register extensions in the ST Micro Ux500 versions */ /* Control register extensions in the ST Micro Ux500 versions */
#define MCI_ST_DPSM_DMAREQCTL (1 << 12) #define MCI_DPSM_ST_DMAREQCTL BIT(12)
#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13) #define MCI_DPSM_ST_DBOOTMODEEN BIT(13)
#define MCI_ST_DPSM_BUSYMODE (1 << 14) #define MCI_DPSM_ST_BUSYMODE BIT(14)
#define MCI_ST_DPSM_DDRMODE (1 << 15) #define MCI_DPSM_ST_DDRMODE BIT(15)
/* Control register extensions in the Qualcomm versions */
#define MCI_DPSM_QCOM_DATA_PEND BIT(17)
#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
#define MMCIDATACNT 0x030 #define MMCIDATACNT 0x030
#define MMCISTATUS 0x034 #define MMCISTATUS 0x034
...@@ -167,7 +174,7 @@ ...@@ -167,7 +174,7 @@
/* Extended status bits for the ST Micro variants */ /* Extended status bits for the ST Micro variants */
#define MCI_ST_SDIOITMASK (1 << 22) #define MCI_ST_SDIOITMASK (1 << 22)
#define MCI_ST_CEATAENDMASK (1 << 23) #define MCI_ST_CEATAENDMASK (1 << 23)
#define MCI_ST_BUSYEND (1 << 24) #define MCI_ST_BUSYENDMASK (1 << 24)
#define MMCIMASK1 0x040 #define MMCIMASK1 0x040
#define MMCIFIFOCNT 0x048 #define MMCIFIFOCNT 0x048
......
...@@ -927,8 +927,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -927,8 +927,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
msdc_start_command(host, mrq, mrq->cmd); msdc_start_command(host, mrq, mrq->cmd);
} }
static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
bool is_first_req)
{ {
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
...@@ -1713,6 +1712,7 @@ static const struct of_device_id msdc_of_ids[] = { ...@@ -1713,6 +1712,7 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", }, { .compatible = "mediatek,mt8135-mmc", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, msdc_of_ids);
static struct platform_driver mt_msdc_driver = { static struct platform_driver mt_msdc_driver = {
.probe = msdc_drv_probe, .probe = msdc_drv_probe,
......
...@@ -1565,8 +1565,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, ...@@ -1565,8 +1565,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
} }
} }
static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
bool is_first_req)
{ {
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
......
...@@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host, ...@@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
return using_cookie; return using_cookie;
} }
static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
bool is_first_req)
{ {
struct realtek_pci_sdmmc *host = mmc_priv(mmc); struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
......
...@@ -1374,6 +1374,8 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) ...@@ -1374,6 +1374,8 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
mutex_init(&host->host_mutex); mutex_init(&host->host_mutex);
rtsx_usb_init_host(host); rtsx_usb_init_host(host);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
#ifdef RTSX_USB_USE_LEDS_CLASS #ifdef RTSX_USB_USE_LEDS_CLASS
...@@ -1428,6 +1430,7 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev) ...@@ -1428,6 +1430,7 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
mmc_free_host(mmc); mmc_free_host(mmc);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev), dev_dbg(&(pdev->dev),
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <mach/dma.h> #include <mach/dma.h>
#include <mach/gpio-samsung.h> #include <mach/gpio-samsung.h>
#include <linux/platform_data/dma-s3c24xx.h>
#include <linux/platform_data/mmc-s3cmci.h> #include <linux/platform_data/mmc-s3cmci.h>
#include "s3cmci.h" #include "s3cmci.h"
...@@ -1682,19 +1681,13 @@ static int s3cmci_probe(struct platform_device *pdev) ...@@ -1682,19 +1681,13 @@ static int s3cmci_probe(struct platform_device *pdev)
gpio_direction_input(host->pdata->gpio_wprotect); gpio_direction_input(host->pdata->gpio_wprotect);
} }
/* depending on the dma state, get a dma channel to use. */ /* Depending on the dma state, get a DMA channel to use. */
if (s3cmci_host_usedma(host)) { if (s3cmci_host_usedma(host)) {
dma_cap_mask_t mask; host->dma = dma_request_chan(&pdev->dev, "rx-tx");
ret = PTR_ERR_OR_ZERO(host->dma);
dma_cap_zero(mask); if (ret) {
dma_cap_set(DMA_SLAVE, mask);
host->dma = dma_request_slave_channel_compat(mask,
s3c24xx_dma_filter, (void *)DMACH_SDI, &pdev->dev, "rx-tx");
if (!host->dma) {
dev_err(&pdev->dev, "cannot get DMA channel.\n"); dev_err(&pdev->dev, "cannot get DMA channel.\n");
ret = -EBUSY;
goto probe_free_gpio_wp; goto probe_free_gpio_wp;
} }
} }
......
...@@ -328,6 +328,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { ...@@ -328,6 +328,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "80865ACC", NULL, &sdhci_acpi_slot_int_emmc }, { "80865ACC", NULL, &sdhci_acpi_slot_int_emmc },
{ "80865AD0", NULL, &sdhci_acpi_slot_int_sdio }, { "80865AD0", NULL, &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
{ "80860F14" , "2" , &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, { "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
{ "80860F16" , NULL, &sdhci_acpi_slot_int_sd }, { "80860F16" , NULL, &sdhci_acpi_slot_int_sd },
{ "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio },
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -100,6 +100,7 @@ static const struct of_device_id sdhci_at91_dt_match[] = { ...@@ -100,6 +100,7 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
{ .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 }, { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 },
{} {}
}; };
MODULE_DEVICE_TABLE(of, sdhci_at91_dt_match);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int sdhci_at91_runtime_suspend(struct device *dev) static int sdhci_at91_runtime_suspend(struct device *dev)
......
This diff is collapsed.
This diff is collapsed.
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca #define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca
#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc #define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc
#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0 #define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0
#define PCI_DEVICE_ID_INTEL_GLK_SD 0x31ca
#define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc
#define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0
/* /*
* PCI registers * PCI registers
......
...@@ -106,7 +106,7 @@ extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); ...@@ -106,7 +106,7 @@ extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host) static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
{ {
return (void *)host->private; return host->private;
} }
extern const struct dev_pm_ops sdhci_pltfm_pmops; extern const struct dev_pm_ops sdhci_pltfm_pmops;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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