提交 5233c331 编写于 作者: L 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
  ...
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:
- compatible : Should be one of the following
"brcm,bcm2835-sdhci"
"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.
......
......@@ -8,11 +8,14 @@ Required properties:
- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
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-r8a7778" for the MMCIF found in r8a7778 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
- "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 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
......
* 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:
"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
"core" - SDC MMC clock (MCLK) (required)
"bus" - SDCC bus voter clock (optional)
"xo" - TCXO clock (optional)
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:
is specified and the ciu clock is specified then we'll try to set the ciu
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.
(Use the "max-frequency" instead of "clock-freq-min-max".)
* 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
......@@ -74,11 +75,6 @@ Optional properties:
* card-detect-delay: Delay in milli-seconds before detecting card after card
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
specified we'll defer probe until we can find this regulator.
......
......@@ -11,8 +11,8 @@ optional bindings can be used.
Required properties:
- 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-r7s72100" - SDHI IP on R7S72100 SoC
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
......
......@@ -25,6 +25,9 @@ Recommended properties:
- fsl,liodn-bits : Indicates the number of defined bits in the LIODN
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:
global-utilities@e0000 { /* global utilities block */
compatible = "fsl,mpc8548-guts";
......
......@@ -1052,6 +1052,7 @@ F: arch/arm/mach-meson/
F: arch/arm/boot/dts/meson*
F: arch/arm64/boot/dts/amlogic/
F: drivers/pinctrl/meson/
F: drivers/mmc/host/meson*
N: meson
ARM/Annapurna Labs ALPINE ARCHITECTURE
......@@ -5068,9 +5069,18 @@ S: Maintained
F: drivers/net/ethernet/freescale/fman
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
M: Qiang Zhao <qiang.zhao@nxp.com>
L: linuxppc-dev@lists.ozlabs.org
S: Orphan
S: Maintained
F: drivers/soc/fsl/qe/
F: include/soc/fsl/*qe*.h
F: include/soc/fsl/*ucc*.h
......
......@@ -216,6 +216,12 @@
clocks = <&sysclk>;
};
dcfg: dcfg@1e00000 {
compatible = "fsl,ls2080a-dcfg", "syscon";
reg = <0x0 0x1e00000 0x0 0x10000>;
little-endian;
};
serial0: serial@21c0500 {
compatible = "fsl,ns16550", "ns16550a";
reg = <0x0 0x21c0500 0x0 0x100>;
......
......@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE
config SOC_BUS
bool
select GLOB
source "drivers/base/regmap/Kconfig"
......
......@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
#include <linux/glob.h>
static DEFINE_IDA(soc_ida);
......@@ -113,6 +114,12 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
struct soc_device *soc_dev;
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);
if (!soc_dev) {
ret = -ENOMEM;
......@@ -156,6 +163,78 @@ void soc_device_unregister(struct soc_device *soc_dev)
static int __init soc_bus_register(void)
{
if (soc_bus_type.p)
return 0;
return bus_register(&soc_bus_type);
}
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);
此差异已折叠。
......@@ -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,
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) {
mrq->cmd->opcode = write ?
......@@ -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,
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) {
mrq->cmd->opcode = write ?
......@@ -714,7 +716,8 @@ static int mmc_test_check_result(struct mmc_test_card *test,
{
int ret;
BUG_ON(!mrq || !mrq->cmd || !mrq->data);
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
return -EINVAL;
ret = 0;
......@@ -736,15 +739,28 @@ static int mmc_test_check_result(struct mmc_test_card *test,
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_test_async_req *test_async =
container_of(areq, struct mmc_test_async_req, areq);
int ret;
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,
{
int ret;
BUG_ON(!mrq || !mrq->cmd || !mrq->data);
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
return -EINVAL;
ret = 0;
......@@ -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 *cur_areq = &test_areq[0].areq;
struct mmc_async_req *other_areq = &test_areq[1].areq;
enum mmc_blk_status status;
int i;
int ret;
int ret = RESULT_OK;
test_areq[0].test = test;
test_areq[1].test = test;
......@@ -834,10 +852,12 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
for (i = 0; i < count; i++) {
mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
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;
}
if (done_areq) {
if (done_areq->mrq == &mrq2)
......@@ -851,7 +871,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
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;
err:
......@@ -2351,6 +2373,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
struct mmc_request *mrq;
unsigned long timeout;
bool expired = false;
enum mmc_blk_status blkstat = MMC_BLK_SUCCESS;
int ret = 0, cmd_ret;
u32 status = 0;
int count = 0;
......@@ -2378,9 +2401,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
/* Start ongoing data request */
if (use_areq) {
mmc_start_req(host, &test_areq.areq, &ret);
if (ret)
mmc_start_req(host, &test_areq.areq, &blkstat);
if (blkstat != MMC_BLK_SUCCESS) {
ret = RESULT_FAIL;
goto out_free;
}
} else {
mmc_wait_for_req(host, mrq);
}
......@@ -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);
/* Wait for data request to complete */
if (use_areq)
mmc_start_req(host, NULL, &ret);
else
if (use_areq) {
mmc_start_req(host, NULL, &blkstat);
if (blkstat != MMC_BLK_SUCCESS)
ret = RESULT_FAIL;
} else {
mmc_wait_for_req_done(test->card->host, mrq);
}
/*
* For cap_cmd_during_tfr request, upper layer must send stop if
......
......@@ -53,6 +53,7 @@ static int mmc_queue_thread(void *d)
{
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
struct mmc_context_info *cntx = &mq->card->host->context_info;
current->flags |= PF_MEMALLOC;
......@@ -63,6 +64,19 @@ static int mmc_queue_thread(void *d)
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
req = blk_fetch_request(q);
mq->asleep = false;
cntx->is_waiting_last_req = false;
cntx->is_new_req = false;
if (!req) {
/*
* Dispatch queue is empty so set flags for
* mmc_request_fn() to wake us up.
*/
if (mq->mqrq_prev->req)
cntx->is_waiting_last_req = true;
else
mq->asleep = true;
}
mq->mqrq_cur->req = req;
spin_unlock_irq(q->queue_lock);
......@@ -115,7 +129,6 @@ static void mmc_request_fn(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata;
struct request *req;
unsigned long flags;
struct mmc_context_info *cntx;
if (!mq) {
......@@ -127,19 +140,13 @@ static void mmc_request_fn(struct request_queue *q)
}
cntx = &mq->card->host->context_info;
if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
/*
* New MMC request arrived when MMC thread may be
* blocked on the previous request to be complete
* with no current request fetched
*/
spin_lock_irqsave(&cntx->lock, flags);
if (cntx->is_waiting_last_req) {
cntx->is_new_req = true;
wake_up_interruptible(&cntx->wait);
}
spin_unlock_irqrestore(&cntx->lock, flags);
} else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
if (cntx->is_waiting_last_req) {
cntx->is_new_req = true;
wake_up_interruptible(&cntx->wait);
}
if (mq->asleep)
wake_up_process(mq->thread);
}
......@@ -179,6 +186,82 @@ static void mmc_queue_setup_discard(struct request_queue *q,
queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
}
#ifdef CONFIG_MMC_BLOCK_BOUNCE
static bool mmc_queue_alloc_bounce_bufs(struct mmc_queue *mq,
unsigned int bouncesz)
{
int i;
for (i = 0; i < mq->qdepth; i++) {
mq->mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
if (!mq->mqrq[i].bounce_buf)
goto out_err;
}
return true;
out_err:
while (--i >= 0) {
kfree(mq->mqrq[i].bounce_buf);
mq->mqrq[i].bounce_buf = NULL;
}
pr_warn("%s: unable to allocate bounce buffers\n",
mmc_card_name(mq->card));
return false;
}
static int mmc_queue_alloc_bounce_sgs(struct mmc_queue *mq,
unsigned int bouncesz)
{
int i, ret;
for (i = 0; i < mq->qdepth; i++) {
mq->mqrq[i].sg = mmc_alloc_sg(1, &ret);
if (ret)
return ret;
mq->mqrq[i].bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret);
if (ret)
return ret;
}
return 0;
}
#endif
static int mmc_queue_alloc_sgs(struct mmc_queue *mq, int max_segs)
{
int i, ret;
for (i = 0; i < mq->qdepth; i++) {
mq->mqrq[i].sg = mmc_alloc_sg(max_segs, &ret);
if (ret)
return ret;
}
return 0;
}
static void mmc_queue_req_free_bufs(struct mmc_queue_req *mqrq)
{
kfree(mqrq->bounce_sg);
mqrq->bounce_sg = NULL;
kfree(mqrq->sg);
mqrq->sg = NULL;
kfree(mqrq->bounce_buf);
mqrq->bounce_buf = NULL;
}
static void mmc_queue_reqs_free_bufs(struct mmc_queue *mq)
{
int i;
for (i = 0; i < mq->qdepth; i++)
mmc_queue_req_free_bufs(&mq->mqrq[i]);
}
/**
* mmc_init_queue - initialise a queue structure.
* @mq: mmc queue
......@@ -193,9 +276,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
{
struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
int ret;
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
bool bounce = false;
int ret = -ENOMEM;
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
......@@ -205,8 +287,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (!mq->queue)
return -ENOMEM;
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->qdepth = 2;
mq->mqrq = kcalloc(mq->qdepth, sizeof(struct mmc_queue_req),
GFP_KERNEL);
if (!mq->mqrq)
goto blk_cleanup;
mq->mqrq_cur = &mq->mqrq[0];
mq->mqrq_prev = &mq->mqrq[1];
mq->queue->queuedata = mq;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
......@@ -228,63 +315,29 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (bouncesz > (host->max_blk_count * 512))
bouncesz = host->max_blk_count * 512;
if (bouncesz > 512) {
mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
if (!mqrq_cur->bounce_buf) {
pr_warn("%s: unable to allocate bounce cur buffer\n",
mmc_card_name(card));
} else {
mqrq_prev->bounce_buf =
kmalloc(bouncesz, GFP_KERNEL);
if (!mqrq_prev->bounce_buf) {
pr_warn("%s: unable to allocate bounce prev buffer\n",
mmc_card_name(card));
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
}
}
}
if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
if (bouncesz > 512 &&
mmc_queue_alloc_bounce_bufs(mq, bouncesz)) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
blk_queue_max_segments(mq->queue, bouncesz / 512);
blk_queue_max_segment_size(mq->queue, bouncesz);
mqrq_cur->sg = mmc_alloc_sg(1, &ret);
if (ret)
goto cleanup_queue;
mqrq_cur->bounce_sg =
mmc_alloc_sg(bouncesz / 512, &ret);
if (ret)
goto cleanup_queue;
mqrq_prev->sg = mmc_alloc_sg(1, &ret);
if (ret)
goto cleanup_queue;
mqrq_prev->bounce_sg =
mmc_alloc_sg(bouncesz / 512, &ret);
ret = mmc_queue_alloc_bounce_sgs(mq, bouncesz);
if (ret)
goto cleanup_queue;
bounce = true;
}
}
#endif
if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
if (!bounce) {
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
if (ret)
goto cleanup_queue;
mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
ret = mmc_queue_alloc_sgs(mq, host->max_segs);
if (ret)
goto cleanup_queue;
}
......@@ -296,27 +349,16 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (IS_ERR(mq->thread)) {
ret = PTR_ERR(mq->thread);
goto free_bounce_sg;
goto cleanup_queue;
}
return 0;
free_bounce_sg:
kfree(mqrq_cur->bounce_sg);
mqrq_cur->bounce_sg = NULL;
kfree(mqrq_prev->bounce_sg);
mqrq_prev->bounce_sg = NULL;
cleanup_queue:
kfree(mqrq_cur->sg);
mqrq_cur->sg = NULL;
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
kfree(mqrq_prev->sg);
mqrq_prev->sg = NULL;
kfree(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;
mmc_queue_reqs_free_bufs(mq);
kfree(mq->mqrq);
mq->mqrq = NULL;
blk_cleanup:
blk_cleanup_queue(mq->queue);
return ret;
}
......@@ -325,8 +367,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
/* Make sure the queue isn't suspended, as that will deadlock */
mmc_queue_resume(mq);
......@@ -340,71 +380,14 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
kfree(mqrq_cur->bounce_sg);
mqrq_cur->bounce_sg = NULL;
kfree(mqrq_cur->sg);
mqrq_cur->sg = NULL;
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
kfree(mqrq_prev->bounce_sg);
mqrq_prev->bounce_sg = NULL;
kfree(mqrq_prev->sg);
mqrq_prev->sg = NULL;
kfree(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;
mmc_queue_reqs_free_bufs(mq);
kfree(mq->mqrq);
mq->mqrq = NULL;
mq->card = NULL;
}
EXPORT_SYMBOL(mmc_cleanup_queue);
int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
{
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
int ret = 0;
mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
if (!mqrq_cur->packed) {
pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
mmc_card_name(card));
ret = -ENOMEM;
goto out;
}
mqrq_prev->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
if (!mqrq_prev->packed) {
pr_warn("%s: unable to allocate packed cmd for mqrq_prev\n",
mmc_card_name(card));
kfree(mqrq_cur->packed);
mqrq_cur->packed = NULL;
ret = -ENOMEM;
goto out;
}
INIT_LIST_HEAD(&mqrq_cur->packed->list);
INIT_LIST_HEAD(&mqrq_prev->packed->list);
out:
return ret;
}
void mmc_packed_clean(struct mmc_queue *mq)
{
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
kfree(mqrq_cur->packed);
mqrq_cur->packed = NULL;
kfree(mqrq_prev->packed);
mqrq_prev->packed = NULL;
}
/**
* mmc_queue_suspend - suspend a MMC request queue
* @mq: MMC queue to suspend
......@@ -449,41 +432,6 @@ void mmc_queue_resume(struct mmc_queue *mq)
}
}
static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
struct mmc_packed *packed,
struct scatterlist *sg,
enum mmc_packed_type cmd_type)
{
struct scatterlist *__sg = sg;
unsigned int sg_len = 0;
struct request *req;
if (mmc_packed_wr(cmd_type)) {
unsigned int hdr_sz = mmc_large_sector(mq->card) ? 4096 : 512;
unsigned int max_seg_sz = queue_max_segment_size(mq->queue);
unsigned int len, remain, offset = 0;
u8 *buf = (u8 *)packed->cmd_hdr;
remain = hdr_sz;
do {
len = min(remain, max_seg_sz);
sg_set_buf(__sg, buf + offset, len);
offset += len;
remain -= len;
sg_unmark_end(__sg++);
sg_len++;
} while (remain);
}
list_for_each_entry(req, &packed->list, queuelist) {
sg_len += blk_rq_map_sg(mq->queue, req, __sg);
__sg = sg + (sg_len - 1);
sg_unmark_end(__sg++);
}
sg_mark_end(sg + (sg_len - 1));
return sg_len;
}
/*
* Prepare the sg list(s) to be handed of to the host driver
*/
......@@ -492,26 +440,12 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
unsigned int sg_len;
size_t buflen;
struct scatterlist *sg;
enum mmc_packed_type cmd_type;
int i;
cmd_type = mqrq->cmd_type;
if (!mqrq->bounce_buf) {
if (mmc_packed_cmd(cmd_type))
return mmc_queue_packed_map_sg(mq, mqrq->packed,
mqrq->sg, cmd_type);
else
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
}
BUG_ON(!mqrq->bounce_sg);
if (!mqrq->bounce_buf)
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
if (mmc_packed_cmd(cmd_type))
sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
mqrq->bounce_sg, cmd_type);
else
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
mqrq->bounce_sg_len = sg_len;
......
......@@ -11,6 +11,7 @@ static inline bool mmc_req_is_special(struct request *req)
struct request;
struct task_struct;
struct mmc_blk_data;
struct mmc_blk_request {
struct mmc_request mrq;
......@@ -21,23 +22,6 @@ struct mmc_blk_request {
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 request *req;
struct mmc_blk_request brq;
......@@ -46,8 +30,6 @@ struct mmc_queue_req {
struct scatterlist *bounce_sg;
unsigned int bounce_sg_len;
struct mmc_async_req mmc_active;
enum mmc_packed_type cmd_type;
struct mmc_packed *packed;
};
struct mmc_queue {
......@@ -57,11 +39,13 @@ struct mmc_queue {
unsigned int flags;
#define MMC_QUEUE_SUSPENDED (1 << 0)
#define MMC_QUEUE_NEW_REQUEST (1 << 1)
void *data;
bool asleep;
struct mmc_blk_data *blkdata;
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_prev;
int qdepth;
};
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 *,
extern void mmc_queue_bounce_pre(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 *);
#endif
......@@ -135,8 +135,6 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
{
struct sdio_func *func;
BUG_ON(sdio_uart_table[port->index] != port);
spin_lock(&sdio_uart_table_lock);
sdio_uart_table[port->index] = NULL;
spin_unlock(&sdio_uart_table_lock);
......
......@@ -306,16 +306,16 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->sbc->mrq = mrq;
}
if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count);
BUG_ON(mrq->data->blocks * mrq->data->blksz >
host->max_req_size);
if (mrq->data->blksz > host->max_blk_size ||
mrq->data->blocks > host->max_blk_count ||
mrq->data->blocks * mrq->data->blksz > host->max_req_size)
return -EINVAL;
#ifdef CONFIG_MMC_DEBUG
sz = 0;
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length;
BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
if (sz != mrq->data->blocks * mrq->data->blksz)
return -EINVAL;
#endif
mrq->cmd->data = mrq->data;
......@@ -349,8 +349,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
int timeout;
bool use_busy_signal;
BUG_ON(!card);
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
return;
......@@ -380,7 +378,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
mmc_retune_hold(card->host);
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);
if (err) {
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)
*
* 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_async_req *next_req)
{
struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info;
int err;
unsigned long flags;
enum mmc_blk_status status;
while (1) {
wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv ||
context_info->is_new_req));
spin_lock_irqsave(&context_info->lock, flags);
context_info->is_waiting_last_req = false;
spin_unlock_irqrestore(&context_info->lock, flags);
if (context_info->is_done_rcv) {
context_info->is_done_rcv = false;
context_info->is_new_req = false;
cmd = mrq->cmd;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
err = host->areq->err_check(host->card,
host->areq);
break; /* return err */
status = host->areq->err_check(host->card,
host->areq);
break; /* return status */
} else {
mmc_retune_recheck(host);
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,
continue; /* wait for done/new event again */
}
} else if (context_info->is_new_req) {
context_info->is_new_req = false;
if (!next_req)
return MMC_BLK_NEW_REQUEST;
}
}
mmc_retune_release(host);
return err;
return status;
}
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
......@@ -611,18 +604,15 @@ EXPORT_SYMBOL(mmc_is_req_done);
* mmc_pre_req - Prepare for a new request
* @host: MMC host to prepare command
* @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
* host prepare for the new request. Preparation of a request may be
* performed while another request is running on the host.
*/
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req)
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
{
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,
* 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 *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;
struct mmc_async_req *data = host->areq;
/* Prepare a new request */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);
mmc_pre_req(host, areq->mrq);
if (host->areq) {
err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
if (err == MMC_BLK_NEW_REQUEST) {
if (error)
*error = err;
status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
if (status == MMC_BLK_NEW_REQUEST) {
if (ret_stat)
*ret_stat = status;
/*
* The previous request was not completed,
* nothing to return
......@@ -695,27 +686,27 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
/* prepare the request again */
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);
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
/* 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);
if (err)
if (status != MMC_BLK_SUCCESS)
host->areq = NULL;
else
host->areq = areq;
if (error)
*error = err;
if (ret_stat)
*ret_stat = status;
return data;
}
EXPORT_SYMBOL(mmc_start_req);
......@@ -754,8 +745,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
u32 status;
unsigned long prg_wait;
BUG_ON(!card);
if (!card->ext_csd.hpi_en) {
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
return 1;
......@@ -850,7 +839,6 @@ int mmc_stop_bkops(struct mmc_card *card)
{
int err = 0;
BUG_ON(!card);
err = mmc_interrupt_hpi(card);
/*
......@@ -1666,8 +1654,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
int err = 0;
u32 clock;
BUG_ON(!host);
/*
* Send CMD11 only if the request is to switch the card to
* 1.8V signalling.
......@@ -1884,9 +1870,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
*/
static void __mmc_release_bus(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(host->bus_refs);
BUG_ON(!host->bus_dead);
WARN_ON(!host->bus_dead);
host->bus_ops = NULL;
}
......@@ -1926,15 +1910,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
BUG_ON(!host);
BUG_ON(!ops);
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->bus_ops);
BUG_ON(host->bus_refs);
WARN_ON(host->bus_ops);
WARN_ON(host->bus_refs);
host->bus_ops = ops;
host->bus_refs = 1;
......@@ -1950,8 +1931,6 @@ void mmc_detach_bus(struct mmc_host *host)
{
unsigned long flags;
BUG_ON(!host);
WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops);
......@@ -2824,12 +2803,11 @@ void mmc_start_host(struct mmc_host *host)
host->rescan_disable = 0;
host->ios.power_mode = MMC_POWER_UNDEFINED;
mmc_claim_host(host);
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host);
else
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
mmc_claim_host(host);
mmc_power_up(host, host->ocr_avail);
mmc_release_host(host);
mmc_release_host(host);
}
mmc_gpiod_request_cd_irq(host);
_mmc_detect_change(host, 0, false);
......@@ -2865,8 +2843,6 @@ void mmc_stop_host(struct mmc_host *host)
}
mmc_bus_put(host);
BUG_ON(host->card);
mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
......@@ -3019,7 +2995,6 @@ void mmc_unregister_pm_notifier(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_done_rcv = 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)
for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]);
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;
kfree(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_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:
return err;
}
......@@ -1003,19 +1021,6 @@ static int mmc_select_bus_width(struct mmc_card *card)
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
*/
......@@ -1025,13 +1030,8 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time,
true, false, true);
if (!err) {
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card);
}
card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
true, true, true);
if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err);
......@@ -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_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits,
card->ext_csd.generic_cmd6_time);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits,
card->ext_csd.generic_cmd6_time,
MMC_TIMING_MMC_DDR52,
true, true, true);
if (err) {
pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
......@@ -1104,9 +1106,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
if (err)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
if (!err)
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
return err;
}
......@@ -1128,7 +1127,7 @@ static int mmc_select_hs400(struct mmc_card *card)
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
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)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
......@@ -1206,7 +1205,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS400 to HS DDR */
val = EXT_CSD_TIMING_HS;
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);
if (err)
goto out_err;
......@@ -1220,7 +1219,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
true, false, true);
0, true, false, true);
if (err)
goto out_err;
......@@ -1234,14 +1233,19 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
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);
if (err)
goto out_err;
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)
goto out_err;
......@@ -1281,16 +1285,23 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
/* Switch card to HS mode */
err = mmc_select_hs(card);
if (err)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
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;
}
mmc_set_clock(host, card->ext_csd.hs_max_dtr);
mmc_set_timing(host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card);
if (err)
goto out_err;
mmc_set_clock(host, card->ext_csd.hs_max_dtr);
/* Switch card to DDR with strobe bit */
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
......@@ -1308,7 +1319,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n",
......@@ -1390,14 +1401,20 @@ static int mmc_select_hs200(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err)
goto err;
old_timing = host->ios.timing;
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
* it is a switch error.
......@@ -1480,7 +1497,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4];
u32 rocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
/* 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)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout, true, false, false);
notify_type, timeout, 0, true, false, false);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
......@@ -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)
{
BUG_ON(!host);
BUG_ON(!host->card);
mmc_remove_card(host->card);
host->card = NULL;
}
......@@ -1892,9 +1905,6 @@ static void mmc_detect(struct mmc_host *host)
{
int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_get_card(host->card);
/*
......@@ -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 :
EXT_CSD_POWER_OFF_LONG;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (mmc_card_suspended(host->card))
......@@ -1979,9 +1986,6 @@ static int _mmc_resume(struct mmc_host *host)
{
int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (!mmc_card_suspended(host->card))
......@@ -2114,7 +2118,6 @@ int mmc_attach_mmc(struct mmc_host *host)
int err;
u32 ocr, rocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
/* Set correct bus mode for MMC before attempting attach */
......
......@@ -54,21 +54,15 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};
static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
bool ignore_crc)
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
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);
if (err)
......@@ -83,17 +77,10 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
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)
{
struct mmc_command cmd = {0};
BUG_ON(!host);
cmd.opcode = MMC_SELECT_CARD;
if (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)
{
BUG_ON(!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)
struct mmc_command cmd = {0};
int i, err = 0;
BUG_ON(!host);
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
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)
int err;
struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cid);
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
......@@ -241,9 +222,6 @@ int mmc_set_relative_addr(struct mmc_card *card)
{
struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
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)
int err;
struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cxd);
cmd.opcode = opcode;
cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
......@@ -440,7 +415,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
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 (status & R1_SPI_ILLEGAL_COMMAND)
......@@ -455,6 +430,88 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
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
* @card: the MMC card associated with the data transfer
......@@ -463,24 +520,22 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
* @value: value to program into EXT_CSD register
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
* @timing: new timing to change to
* @use_busy_signal: use the busy signal as response type
* @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.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal, bool send_status,
bool ignore_crc)
unsigned int timeout_ms, unsigned char timing,
bool use_busy_signal, bool send_status, bool retry_crc_err)
{
struct mmc_host *host = card->host;
int err;
struct mmc_command cmd = {0};
unsigned long timeout;
u32 status = 0;
bool use_r1b_resp = use_busy_signal;
bool expired = false;
bool busy = false;
unsigned char old_timing = host->ios.timing;
mmc_retune_hold(host);
......@@ -522,62 +577,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (!use_busy_signal)
goto out;
/*
* CRC errors shall only be ignored in cases were CMD13 is used to poll
* to detect busy completion.
*/
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;
/* Switch to new timing before poll and check switch status. */
if (timing)
mmc_set_timing(host, timing);
/*
* We are not allowed to issue a status command and the host
* does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
* rely on waiting for the stated timeout to be sufficient.
*/
if (!send_status && !host->ops->card_busy) {
mmc_delay(timeout_ms);
goto out;
}
/*If SPI or used HW busy detection above, then we don't need to poll. */
if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
mmc_host_is_spi(host)) {
if (send_status)
err = mmc_switch_status(card);
goto out_tim;
}
/* Timeout if the device never leaves the program state. */
if (expired &&
(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);
/* Let's try to poll to find out when the command is completed. */
err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
err = mmc_switch_status_error(host, status);
out_tim:
if (err && timing)
mmc_set_timing(host, old_timing);
out:
mmc_retune_release(host);
......@@ -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,
unsigned int timeout_ms)
{
return __mmc_switch(card, set, index, value, timeout_ms, true, true,
false);
return __mmc_switch(card, set, index, value, timeout_ms, 0,
true, true, false);
}
EXPORT_SYMBOL_GPL(mmc_switch);
......@@ -661,6 +678,31 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
}
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
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
......
......@@ -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_send_hpi_cmd(struct mmc_card *card, u32 *status);
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,
unsigned int timeout_ms, bool use_busy_signal, bool send_status,
bool ignore_crc);
unsigned int timeout_ms, unsigned char timing,
bool use_busy_signal, bool send_status, bool retry_crc_err);
#endif
......@@ -927,7 +927,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4];
u32 rocr = 0;
BUG_ON(!host);
WARN_ON(!host->claimed);
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,
*/
static void mmc_sd_remove(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(!host->card);
mmc_remove_card(host->card);
host->card = NULL;
}
......@@ -1065,9 +1061,6 @@ static void mmc_sd_detect(struct mmc_host *host)
{
int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_get_card(host->card);
/*
......@@ -1091,9 +1084,6 @@ static int _mmc_sd_suspend(struct mmc_host *host)
{
int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (mmc_card_suspended(host->card))
......@@ -1136,9 +1126,6 @@ static int _mmc_sd_resume(struct mmc_host *host)
{
int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (!mmc_card_suspended(host->card))
......@@ -1221,7 +1208,6 @@ int mmc_attach_sd(struct mmc_host *host)
int err;
u32 ocr, rocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
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)
int err;
struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(card && (card->host != host));
if (WARN_ON(card && card->host != host))
return -EINVAL;
cmd.opcode = MMC_APP_CMD;
......@@ -72,8 +72,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
int i, err;
BUG_ON(!cmd);
BUG_ON(retries < 0);
if (retries < 0)
retries = MMC_CMD_RETRIES;
err = -EIO;
......@@ -122,9 +122,6 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = SD_APP_SET_BUS_WIDTH;
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)
struct mmc_command cmd = {0};
int i, err = 0;
BUG_ON(!host);
cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host))
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)
int err;
struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!rca);
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
......@@ -249,10 +241,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
struct scatterlist sg;
void *data_buf;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!scr);
/* NOTE: caller guarantees scr is heap-allocated */
err = mmc_app_cmd(card->host, card);
......@@ -307,9 +295,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
struct mmc_data data = {0};
struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
/* NOTE: caller guarantees resp is heap-allocated */
mode = !!mode;
......@@ -352,10 +337,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
struct mmc_data data = {0};
struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!ssr);
/* NOTE: caller guarantees ssr is heap-allocated */
err = mmc_app_cmd(card->host, card);
......
......@@ -63,7 +63,8 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
int ret;
struct sdio_func *func;
BUG_ON(fn > SDIO_MAX_FUNCS);
if (WARN_ON(fn > SDIO_MAX_FUNCS))
return -EINVAL;
func = sdio_alloc_func(card);
if (IS_ERR(func))
......@@ -555,7 +556,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
u32 rocr = 0;
u32 ocr_card = ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
/* to query card if 1.8V signalling is supported */
......@@ -791,9 +791,6 @@ static void mmc_sdio_remove(struct mmc_host *host)
{
int i;
BUG_ON(!host);
BUG_ON(!host->card);
for (i = 0;i < host->card->sdio_funcs;i++) {
if (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)
{
int err;
BUG_ON(!host);
BUG_ON(!host->card);
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev);
......@@ -916,9 +910,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
{
int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
/* Basic card reinitialization. */
mmc_claim_host(host);
......@@ -970,9 +961,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
{
int ret;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
/*
......@@ -1063,7 +1051,6 @@ int mmc_attach_sdio(struct mmc_host *host)
u32 ocr, rocr;
struct mmc_card *card;
BUG_ON(!host);
WARN_ON(!host->claimed);
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)
else
prev = &card->tuples;
BUG_ON(*prev);
if (*prev)
return -EINVAL;
do {
unsigned char tpl_code, tpl_link;
......
......@@ -214,7 +214,9 @@ static int sdio_card_irq_put(struct mmc_card *card)
struct mmc_host *host = card->host;
WARN_ON(!host->claimed);
BUG_ON(host->sdio_irqs < 1);
if (host->sdio_irqs < 1)
return -EINVAL;
if (!--host->sdio_irqs) {
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)
int ret;
unsigned char reg;
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return -EINVAL;
pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
......@@ -304,8 +306,8 @@ int sdio_release_irq(struct sdio_func *func)
int ret;
unsigned char reg;
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return -EINVAL;
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,
}
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
* @host: mmc host
......
......@@ -135,7 +135,6 @@ config MMC_SDHCI_OF_AT91
tristate "SDHCI OF support for the Atmel SDMMC controller"
depends on MMC_SDHCI_PLTFM
depends on OF
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Atmel SDMMC driver
......@@ -144,6 +143,7 @@ config MMC_SDHCI_OF_ESDHC
depends on MMC_SDHCI_PLTFM
depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
select MMC_SDHCI_IO_ACCESSORS
select FSL_GUTS
help
This selects the Freescale eSDHC controller support.
......@@ -165,6 +165,17 @@ config MMC_SDHCI_OF_HLWD
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
tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX
......@@ -322,6 +333,16 @@ config MMC_SDHCI_IPROC
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
tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC
......
......@@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.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_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.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_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_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
......
......@@ -35,6 +35,7 @@
#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/platform_data/mmc-davinci.h>
......@@ -1029,9 +1030,10 @@ static int mmc_davinci_get_cd(struct mmc_host *mmc)
struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *config = pdev->dev.platform_data;
if (!config || !config->get_cd)
return -ENOSYS;
return config->get_cd(pdev->id);
if (config && config->get_cd)
return config->get_cd(pdev->id);
return mmc_gpio_get_cd(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)
struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *config = pdev->dev.platform_data;
if (!config || !config->get_ro)
return -ENOSYS;
return config->get_ro(pdev->id);
if (config && config->get_ro)
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)
......@@ -1159,49 +1162,53 @@ static const struct of_device_id davinci_mmc_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, davinci_mmc_dt_ids);
static struct davinci_mmc_config
*mmc_parse_pdata(struct platform_device *pdev)
static int mmc_davinci_parse_pdata(struct mmc_host *mmc)
{
struct device_node *np;
struct platform_device *pdev = to_platform_device(mmc->parent);
struct davinci_mmc_config *pdata = pdev->dev.platform_data;
const struct of_device_id *match =
of_match_device(davinci_mmc_dt_ids, &pdev->dev);
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;
}
struct mmc_davinci_host *host;
int ret;
if (match)
pdev->id_entry = match->data;
if (!pdata)
return -EINVAL;
if (of_property_read_u32(np, "max-frequency", &pdata->max_freq))
dev_info(&pdev->dev, "'max-frequency' property not specified, defaulting to 25MHz\n");
host = mmc_priv(mmc);
if (!host)
return -EINVAL;
of_property_read_u32(np, "bus-width", &data);
switch (data) {
case 1:
case 4:
case 8:
pdata->wires = data;
break;
default:
pdata->wires = 1;
dev_info(&pdev->dev, "Unsupported buswidth, defaulting to 1 bit\n");
}
nodata:
return pdata;
if (pdata && pdata->nr_sg)
host->nr_sg = pdata->nr_sg - 1;
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);
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;
/* 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)
{
struct davinci_mmc_config *pdata = NULL;
const struct of_device_id *match;
struct mmc_davinci_host *host = NULL;
struct mmc_host *mmc = NULL;
struct resource *r, *mem = NULL;
......@@ -1209,12 +1216,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
size_t mem_size;
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);
if (!r)
return -ENODEV;
......@@ -1253,14 +1254,28 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->mmc_input_clk = clk_get_rate(host->clk);
init_mmcsd_host(host);
if (pdata->nr_sg)
host->nr_sg = pdata->nr_sg - 1;
match = of_match_device(davinci_mmc_dt_ids, &pdev->dev);
if (match) {
pdev->id_entry = match->data;
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)
host->nr_sg = MAX_NR_SG;
init_mmcsd_host(host);
host->use_dma = use_dma;
host->mmc_irq = irq;
host->sdio_irq = platform_get_irq(pdev, 1);
......@@ -1273,27 +1288,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->use_dma = 0;
}
/* REVISIT: someday, support IRQ-driven card detection. */
mmc->caps |= MMC_CAP_NEEDS_POLL;
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);
if (id_entry)
host->version = id_entry->driver_data;
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;
/* 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)
mmc_davinci_cpufreq_deregister(host);
cpu_freq_fail:
davinci_release_dma_channels(host);
parse_fail:
dma_probe_defer:
clk_disable_unprepare(host->clk);
clk_prepare_enable_fail:
......
......@@ -17,6 +17,7 @@
#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include "dw_mmc.h"
......@@ -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);
}
#ifdef CONFIG_PM_SLEEP
static int dw_mci_exynos_suspend(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)
#ifdef CONFIG_PM
static int dw_mci_exynos_runtime_resume(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
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)
return 0;
}
#else
#define dw_mci_exynos_suspend NULL
#define dw_mci_exynos_resume 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)
{
......@@ -524,14 +516,42 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match;
int ret;
match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
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 = {
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,
.thaw_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 = {
static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe,
.remove = dw_mci_pltfm_remove,
.remove = dw_mci_exynos_remove,
.driver = {
.name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match,
......
......@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
......@@ -162,35 +163,13 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data);
}
#ifdef CONFIG_PM_SLEEP
static int dw_mci_k3_suspend(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
int ret;
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 const struct dev_pm_ops dw_mci_k3_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_k3_pltfm_driver = {
.probe = dw_mci_k3_probe,
......@@ -198,7 +177,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = {
.driver = {
.name = "dwmmc_k3",
.of_match_table = dw_mci_k3_match,
.pm = &dw_mci_k3_pmops,
.pm = &dw_mci_k3_dev_pm_ops,
},
};
......
......@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
......@@ -79,25 +80,13 @@ static void dw_mci_pci_remove(struct pci_dev *pdev)
dw_mci_remove(host);
}
#ifdef CONFIG_PM_SLEEP
static int dw_mci_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_mci *host = pci_get_drvdata(pdev);
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 dev_pm_ops dw_mci_pci_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 const struct pci_device_id dw_mci_pci_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 = {
.probe = dw_mci_pci_probe,
.remove = dw_mci_pci_remove,
.driver = {
.pm = &dw_mci_pci_pmops
.pm = &dw_mci_pci_dev_pm_ops,
},
};
......
......@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
......@@ -58,26 +59,13 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
#ifdef CONFIG_PM_SLEEP
/*
* TODO: we should probably disable the clock to the card in the suspend path.
*/
static int dw_mci_pltfm_suspend(struct device *dev)
{
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);
const struct dev_pm_ops dw_mci_pltfm_pmops = {
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)
};
EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
static const struct of_device_id dw_mci_pltfm_match[] = {
......
......@@ -13,6 +13,8 @@
#include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include "dw_mmc.h"
......@@ -325,6 +327,7 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match;
int ret;
if (!pdev->dev.of_node)
return -ENODEV;
......@@ -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);
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 = {
.probe = dw_mci_rockchip_probe,
.remove = dw_mci_pltfm_remove,
.remove = dw_mci_rockchip_remove,
.driver = {
.name = "dwmmc_rockchip",
.of_match_table = dw_mci_rockchip_match,
.pm = &dw_mci_pltfm_pmops,
.pm = &dw_mci_rockchip_dev_pm_ops,
},
};
......
......@@ -54,7 +54,7 @@
#define DW_MCI_DMA_THRESHOLD 16
#define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */
#define DW_MCI_FREQ_MIN 400000 /* unit: HZ */
#define DW_MCI_FREQ_MIN 100000 /* unit: HZ */
#define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
......@@ -165,12 +165,14 @@ static const struct file_operations dw_mci_req_fops = {
static int dw_mci_regs_show(struct seq_file *s, void *v)
{
seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
struct dw_mci *host = s->private;
seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS));
seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS));
seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD));
seq_printf(s, "CTRL:\t0x%08x\n", mci_readl(host, CTRL));
seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK));
seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA));
return 0;
}
......@@ -234,7 +236,6 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg);
static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
u32 cmdr;
......@@ -289,10 +290,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
if (cmd->flags & MMC_RSP_CRC)
cmdr |= SDMMC_CMD_RESP_CRC;
data = cmd->data;
if (data) {
if (cmd->data) {
cmdr |= SDMMC_CMD_DAT_EXP;
if (data->flags & MMC_DATA_WRITE)
if (cmd->data->flags & MMC_DATA_WRITE)
cmdr |= SDMMC_CMD_DAT_WR;
}
......@@ -335,6 +335,9 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
cmdr = stop->opcode | SDMMC_CMD_STOP |
SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags))
cmdr |= SDMMC_CMD_USE_HOLD_REG;
return cmdr;
}
......@@ -380,7 +383,7 @@ static void dw_mci_start_command(struct dw_mci *host,
static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
{
struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
struct mmc_command *stop = &host->stop_abort;
dw_mci_start_command(host, stop, host->stop_cmdr);
}
......@@ -409,12 +412,13 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
if (data)
if (!data->host_cookie)
dma_unmap_sg(host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
if (data && data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
data->host_cookie = COOKIE_UNMAPPED;
}
}
static void dw_mci_idmac_reset(struct dw_mci *host)
......@@ -612,7 +616,7 @@ static inline int dw_mci_prepare_desc64(struct dw_mci *host,
return 0;
err_own_bit:
/* restore the descriptor chain as it's polluted */
dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n");
dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n");
memset(host->sg_cpu, 0, DESC_RING_BUF_SZ);
dw_mci_idmac_init(host);
return -EINVAL;
......@@ -688,7 +692,7 @@ static inline int dw_mci_prepare_desc32(struct dw_mci *host,
return 0;
err_own_bit:
/* restore the descriptor chain as it's polluted */
dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n");
dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n");
memset(host->sg_cpu, 0, DESC_RING_BUF_SZ);
dw_mci_idmac_init(host);
return -EINVAL;
......@@ -845,13 +849,13 @@ static const struct dw_mci_dma_ops dw_mci_edmac_ops = {
static int dw_mci_pre_dma_transfer(struct dw_mci *host,
struct mmc_data *data,
bool next)
int cookie)
{
struct scatterlist *sg;
unsigned int i, sg_len;
if (!next && data->host_cookie)
return data->host_cookie;
if (data->host_cookie == COOKIE_PRE_MAPPED)
return data->sg_len;
/*
* We don't do DMA on "complex" transfers, i.e. with
......@@ -876,15 +880,13 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
if (sg_len == 0)
return -EINVAL;
if (next)
data->host_cookie = sg_len;
data->host_cookie = cookie;
return sg_len;
}
static void dw_mci_pre_req(struct mmc_host *mmc,
struct mmc_request *mrq,
bool is_first_req)
struct mmc_request *mrq)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
......@@ -892,13 +894,12 @@ static void dw_mci_pre_req(struct mmc_host *mmc,
if (!slot->host->use_dma || !data)
return;
if (data->host_cookie) {
data->host_cookie = 0;
return;
}
/* This data might be unmapped at this time */
data->host_cookie = COOKIE_UNMAPPED;
if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
data->host_cookie = 0;
if (dw_mci_pre_dma_transfer(slot->host, mrq->data,
COOKIE_PRE_MAPPED) < 0)
data->host_cookie = COOKIE_UNMAPPED;
}
static void dw_mci_post_req(struct mmc_host *mmc,
......@@ -911,12 +912,12 @@ static void dw_mci_post_req(struct mmc_host *mmc,
if (!slot->host->use_dma || !data)
return;
if (data->host_cookie)
if (data->host_cookie != COOKIE_UNMAPPED)
dma_unmap_sg(slot->host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
data->host_cookie = 0;
data->host_cookie = COOKIE_UNMAPPED;
}
static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
......@@ -1022,7 +1023,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
if (!host->use_dma)
return -ENODEV;
sg_len = dw_mci_pre_dma_transfer(host, data, 0);
sg_len = dw_mci_pre_dma_transfer(host, data, COOKIE_MAPPED);
if (sg_len < 0) {
host->dma_ops->stop(host);
return sg_len;
......@@ -1175,13 +1176,24 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
if (clock != slot->__clk_old || force_clkinit)
if ((clock != slot->__clk_old &&
!test_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags)) ||
force_clkinit) {
dev_info(&slot->mmc->class_dev,
"Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
slot->id, host->bus_hz, clock,
div ? ((host->bus_hz / div) >> 1) :
host->bus_hz, div);
/*
* If card is polling, display the message only
* one time at boot time.
*/
if (slot->mmc->caps & MMC_CAP_NEEDS_POLL &&
slot->mmc->f_min == clock)
set_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags);
}
/* disable clock */
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
......@@ -1273,10 +1285,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
spin_unlock_irqrestore(&host->irq_lock, irqflags);
}
if (mrq->stop)
host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
else
host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
}
static void dw_mci_start_request(struct dw_mci *host,
......@@ -1527,22 +1536,34 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int gpio_cd = mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc))
if (((mmc->caps & MMC_CAP_NEEDS_POLL)
|| !mmc_card_is_removable(mmc))) {
present = 1;
else if (gpio_cd >= 0)
if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
if (mmc->caps & MMC_CAP_NEEDS_POLL) {
dev_info(&mmc->class_dev,
"card is polling.\n");
} else {
dev_info(&mmc->class_dev,
"card is non-removable.\n");
}
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
}
return present;
} else if (gpio_cd >= 0)
present = gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
spin_lock_bh(&host->lock);
if (present) {
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags))
dev_dbg(&mmc->class_dev, "card is present\n");
} else {
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else if (!present &&
!test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags))
dev_dbg(&mmc->class_dev, "card is not present\n");
}
spin_unlock_bh(&host->lock);
return present;
......@@ -1889,8 +1910,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) {
dw_mci_stop_dma(host);
if (data->stop ||
!(host->data_status & (SDMMC_INT_DRTO |
if (!(host->data_status & (SDMMC_INT_DRTO |
SDMMC_INT_EBE)))
send_stop_abort(host, data);
state = STATE_DATA_ERROR;
......@@ -1926,8 +1946,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) {
dw_mci_stop_dma(host);
if (data->stop ||
!(host->data_status & (SDMMC_INT_DRTO |
if (!(host->data_status & (SDMMC_INT_DRTO |
SDMMC_INT_EBE)))
send_stop_abort(host, data);
state = STATE_DATA_ERROR;
......@@ -2003,7 +2022,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
host->cmd = NULL;
host->data = NULL;
if (mrq->stop)
if (!mrq->sbc && mrq->stop)
dw_mci_command_complete(host, mrq->stop);
else
host->cmd_status = 0;
......@@ -2615,6 +2634,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->f_min = DW_MCI_FREQ_MIN;
mmc->f_max = DW_MCI_FREQ_MAX;
} else {
dev_info(host->dev,
"'clock-freq-min-max' property was deprecated.\n");
mmc->f_min = freq[0];
mmc->f_max = freq[1];
}
......@@ -3267,26 +3288,46 @@ EXPORT_SYMBOL(dw_mci_remove);
#ifdef CONFIG_PM_SLEEP
/*
* TODO: we should probably disable the clock to the card in the suspend path.
*/
int dw_mci_suspend(struct dw_mci *host)
#ifdef CONFIG_PM
int dw_mci_runtime_suspend(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
clk_disable_unprepare(host->ciu_clk);
if (host->cur_slot &&
(mmc_can_gpio_cd(host->cur_slot->mmc) ||
!mmc_card_is_removable(host->cur_slot->mmc)))
clk_disable_unprepare(host->biu_clk);
return 0;
}
EXPORT_SYMBOL(dw_mci_suspend);
EXPORT_SYMBOL(dw_mci_runtime_suspend);
int dw_mci_resume(struct dw_mci *host)
int dw_mci_runtime_resume(struct device *dev)
{
int i, ret;
int i, ret = 0;
struct dw_mci *host = dev_get_drvdata(dev);
if (host->cur_slot &&
(mmc_can_gpio_cd(host->cur_slot->mmc) ||
!mmc_card_is_removable(host->cur_slot->mmc))) {
ret = clk_prepare_enable(host->biu_clk);
if (ret)
return ret;
}
ret = clk_prepare_enable(host->ciu_clk);
if (ret)
goto err;
if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
clk_disable_unprepare(host->ciu_clk);
ret = -ENODEV;
return ret;
goto err;
}
if (host->use_dma && host->dma_ops->init)
......@@ -3296,8 +3337,8 @@ int dw_mci_resume(struct dw_mci *host)
* Restore the initial value at FIFOTH register
* And Invalidate the prev_blksz with zero
*/
mci_writel(host, FIFOTH, host->fifoth_val);
host->prev_blksz = 0;
mci_writel(host, FIFOTH, host->fifoth_val);
host->prev_blksz = 0;
/* Put in max timeout */
mci_writel(host, TMOUT, 0xFFFFFFFF);
......@@ -3323,9 +3364,17 @@ int dw_mci_resume(struct dw_mci *host)
dw_mci_enable_cd(host);
return 0;
err:
if (host->cur_slot &&
(mmc_can_gpio_cd(host->cur_slot->mmc) ||
!mmc_card_is_removable(host->cur_slot->mmc)))
clk_disable_unprepare(host->biu_clk);
return ret;
}
EXPORT_SYMBOL(dw_mci_resume);
#endif /* CONFIG_PM_SLEEP */
EXPORT_SYMBOL(dw_mci_runtime_resume);
#endif /* CONFIG_PM */
static int __init dw_mci_init(void)
{
......
......@@ -234,9 +234,9 @@
extern int dw_mci_probe(struct dw_mci *host);
extern void dw_mci_remove(struct dw_mci *host);
#ifdef CONFIG_PM_SLEEP
extern int dw_mci_suspend(struct dw_mci *host);
extern int dw_mci_resume(struct dw_mci *host);
#ifdef CONFIG_PM
extern int dw_mci_runtime_suspend(struct device *device);
extern int dw_mci_runtime_resume(struct device *device);
#endif
/**
......@@ -272,6 +272,7 @@ struct dw_mci_slot {
#define DW_MMC_CARD_NEED_INIT 1
#define DW_MMC_CARD_NO_LOW_PWR 2
#define DW_MMC_CARD_NO_USE_HOLD 3
#define DW_MMC_CARD_NEEDS_POLL 4
int id;
int sdio_id;
};
......
......@@ -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,
struct mmc_request *mrq,
bool is_first_req)
struct mmc_request *mrq)
{
struct jz4740_mmc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
......
此差异已折叠。
......@@ -71,7 +71,12 @@ static unsigned int fmax = 515633;
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
* @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
* @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic.
......@@ -98,6 +103,9 @@ struct variant_data {
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower;
bool explicit_mclk_control;
bool qcom_fifo;
......@@ -137,7 +145,7 @@ static struct variant_data variant_u300 = {
.clkreg_enable = MCI_ST_U300_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 16,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000,
......@@ -152,7 +160,7 @@ static struct variant_data variant_nomadik = {
.clkreg = MCI_CLK_ENABLE,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 24,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
......@@ -170,7 +178,7 @@ static struct variant_data variant_ux500 = {
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datalength_bits = 24,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
......@@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = {
.signal_direction = true,
.pwrreg_clkgate = 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,
};
......@@ -188,9 +199,9 @@ static struct variant_data variant_ux500v2 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.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,
.datactrl_mask_sdio = MCI_ST_DPSM_SDIOEN,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
.blksz_datactrl16 = true,
......@@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = {
.signal_direction = true,
.pwrreg_clkgate = 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,
};
......@@ -210,7 +224,7 @@ static struct variant_data variant_qcom = {
MCI_QCOM_CLK_SELECT_IN_FBCLK,
.clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
.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,
.datalength_bits = 24,
.pwrreg_powerup = MCI_PWR_UP,
......@@ -220,6 +234,7 @@ static struct variant_data variant_qcom = {
.qcom_dml = true,
};
/* Busy detection for the ST Micro variant */
static int mmci_card_busy(struct mmc_host *mmc)
{
struct mmci_host *host = mmc_priv(mmc);
......@@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc)
int busy = 0;
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;
spin_unlock_irqrestore(&host->lock, flags);
......@@ -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)
{
/* Keep ST Micro busy mode if enabled */
datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
/* Keep busy mode in DPSM if enabled */
datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
if (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)
next->dma_chan = NULL;
}
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
bool is_first_req)
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
......@@ -973,37 +987,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status)
{
void __iomem *base = host->base;
bool sbc, busy_resp;
bool sbc;
if (!cmd)
return;
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;
/* Check if we need to wait for busy completion. */
if (host->busy_status && (status & MCI_ST_CARDBUSY))
return;
/*
* ST Micro variant: handle busy detection.
*/
if (host->variant->busy_detect) {
bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
/* Enable busy completion if needed and supported. */
if (!host->busy_status && busy_resp &&
!(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
(readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
base + MMCIMASK0);
host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
return;
}
/* We are busy with a command, return */
if (host->busy_status &&
(status & host->variant->busy_detect_flag))
return;
/*
* We were not busy, but we now got a busy response on
* 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) {
writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
base + MMCIMASK0);
host->busy_status = 0;
/*
* At this point we are not busy with a command, we have
* not received a new busy request, mask the busy IRQ and
* fall through to process the IRQ.
*/
if (host->busy_status) {
writel(readl(base + MMCIMASK0) &
~host->variant->busy_detect_mask,
base + MMCIMASK0);
host->busy_status = 0;
}
}
host->cmd = NULL;
......@@ -1257,9 +1300,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
mmci_data_irq(host, host->data, status);
}
/* Don't poll for busy completion in irq context. */
if (host->busy_status)
status &= ~MCI_ST_CARDBUSY;
/*
* Don't poll for busy completion in irq context.
*/
if (host->variant->busy_detect && host->busy_status)
status &= ~host->variant->busy_detect_flag;
ret = 1;
} while (status);
......@@ -1612,9 +1657,18 @@ static int mmci_probe(struct amba_device *dev,
/* We support these capabilities. */
mmc->caps |= MMC_CAP_CMD23;
/*
* Enable busy detection.
*/
if (variant->busy_detect) {
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->max_busy_timeout = 0;
}
......
......@@ -51,25 +51,27 @@
#define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15))
#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 */
#define MCI_QCOM_CSPM_DATCMD BIT(12)
#define MCI_QCOM_CSPM_MCIABORT BIT(13)
#define MCI_QCOM_CSPM_CCSENABLE BIT(14)
#define MCI_QCOM_CSPM_CCSDISABLE BIT(15)
#define MCI_QCOM_CSPM_AUTO_CMD19 BIT(16)
#define MCI_QCOM_CSPM_AUTO_CMD21 BIT(21)
/* The command register controls the Command Path State Machine (CPSM) */
#define MMCICOMMAND 0x00c
#define MCI_CPSM_RESPONSE BIT(6)
#define MCI_CPSM_LONGRSP BIT(7)
#define MCI_CPSM_INTERRUPT BIT(8)
#define MCI_CPSM_PENDING BIT(9)
#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 MMCIRESPONSE0 0x014
......@@ -78,22 +80,27 @@
#define MMCIRESPONSE3 0x020
#define MMCIDATATIMER 0x024
#define MMCIDATALENGTH 0x028
/* The data control register controls the Data Path State Machine (DPSM) */
#define MMCIDATACTRL 0x02c
#define MCI_DPSM_ENABLE (1 << 0)
#define MCI_DPSM_DIRECTION (1 << 1)
#define MCI_DPSM_MODE (1 << 2)
#define MCI_DPSM_DMAENABLE (1 << 3)
#define MCI_DPSM_BLOCKSIZE (1 << 4)
#define MCI_DPSM_ENABLE BIT(0)
#define MCI_DPSM_DIRECTION BIT(1)
#define MCI_DPSM_MODE BIT(2)
#define MCI_DPSM_DMAENABLE BIT(3)
#define MCI_DPSM_BLOCKSIZE BIT(4)
/* Control register extensions in the ST Micro U300 and Ux500 versions */
#define MCI_ST_DPSM_RWSTART (1 << 8)
#define MCI_ST_DPSM_RWSTOP (1 << 9)
#define MCI_ST_DPSM_RWMOD (1 << 10)
#define MCI_ST_DPSM_SDIOEN (1 << 11)
#define MCI_DPSM_ST_RWSTART BIT(8)
#define MCI_DPSM_ST_RWSTOP BIT(9)
#define MCI_DPSM_ST_RWMOD BIT(10)
#define MCI_DPSM_ST_SDIOEN BIT(11)
/* Control register extensions in the ST Micro Ux500 versions */
#define MCI_ST_DPSM_DMAREQCTL (1 << 12)
#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13)
#define MCI_ST_DPSM_BUSYMODE (1 << 14)
#define MCI_ST_DPSM_DDRMODE (1 << 15)
#define MCI_DPSM_ST_DMAREQCTL BIT(12)
#define MCI_DPSM_ST_DBOOTMODEEN BIT(13)
#define MCI_DPSM_ST_BUSYMODE BIT(14)
#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 MMCISTATUS 0x034
......@@ -167,7 +174,7 @@
/* Extended status bits for the ST Micro variants */
#define MCI_ST_SDIOITMASK (1 << 22)
#define MCI_ST_CEATAENDMASK (1 << 23)
#define MCI_ST_BUSYEND (1 << 24)
#define MCI_ST_BUSYENDMASK (1 << 24)
#define MMCIMASK1 0x040
#define MMCIFIFOCNT 0x048
......
......@@ -927,8 +927,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
msdc_start_command(host, mrq, mrq->cmd);
}
static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
bool is_first_req)
static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct msdc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
......@@ -1713,6 +1712,7 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", },
{}
};
MODULE_DEVICE_TABLE(of, msdc_of_ids);
static struct platform_driver mt_msdc_driver = {
.probe = msdc_drv_probe,
......
......@@ -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,
bool is_first_req)
static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
......
......@@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
return using_cookie;
}
static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
bool is_first_req)
static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
......
......@@ -1374,6 +1374,8 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
mutex_init(&host->host_mutex);
rtsx_usb_init_host(host);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_enable(&pdev->dev);
#ifdef RTSX_USB_USE_LEDS_CLASS
......@@ -1428,6 +1430,7 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
mmc_free_host(mmc);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
......
......@@ -28,7 +28,6 @@
#include <mach/dma.h>
#include <mach/gpio-samsung.h>
#include <linux/platform_data/dma-s3c24xx.h>
#include <linux/platform_data/mmc-s3cmci.h>
#include "s3cmci.h"
......@@ -1682,19 +1681,13 @@ static int s3cmci_probe(struct platform_device *pdev)
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)) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
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) {
host->dma = dma_request_chan(&pdev->dev, "rx-tx");
ret = PTR_ERR_OR_ZERO(host->dma);
if (ret) {
dev_err(&pdev->dev, "cannot get DMA channel.\n");
ret = -EBUSY;
goto probe_free_gpio_wp;
}
}
......
......@@ -328,6 +328,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "80865ACC", NULL, &sdhci_acpi_slot_int_emmc },
{ "80865AD0", NULL, &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
{ "80860F14" , "2" , &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
{ "80860F16" , NULL, &sdhci_acpi_slot_int_sd },
{ "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio },
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -100,6 +100,7 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
{ .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 },
{}
};
MODULE_DEVICE_TABLE(of, sdhci_at91_dt_match);
#ifdef CONFIG_PM
static int sdhci_at91_runtime_suspend(struct device *dev)
......
此差异已折叠。
此差异已折叠。
......@@ -34,6 +34,9 @@
#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca
#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc
#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
......
......@@ -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)
{
return (void *)host->private;
return host->private;
}
extern const struct dev_pm_ops sdhci_pltfm_pmops;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册