MMC core:

- Add support for sending commands during data transfer
  - Erase/discard/trim improvements
  - Improved error handling
  - Extend sysfs with SD status register
  - Document info about the vmmc/vmmcq regulators
  - Extend pwrseq-simple to manage an optional post-power-on-delay
  - Some various minor improvements and cleanups
 
 MMC host:
  - dw_mmc: Add reset support
  - dw_mmc: Return -EILSEQ for EBE and SBE error
  - dw_mmc: Some cleanups
  - dw_mmc-k3: Add UHS-I support Hisilicon Hikey
  - tmio: Add eMMC support
  - sh_mobile_sdhi: Add r8a7796 support
  - sunxi: Don't use sample clocks for sun4i/sun5i
  - sunxi: Add support for A64 mmc controller
  - sunxi: Some cleanups and improvements
  - sdhci: Support for sending commands during data transfer
  - sdhci: Do not allow tuning procedure to be interrupted
  - sdhci-pci: Enable SD/SDIO on Merrifield
  - sdhci-pci|acpi: Enable MMC_CAP_CMD_DURING_TFR
  - sdhci-pci: Some cleanups
  - sdhci-of-arasan: Set controller to test mode when no CD bit
  - sdhci-of-arasan: Some fixes for clocks and phys
  - sdhci-brcmstb: Don't use ADMA 64-bit when not supported
  - sdhci-tegra: Mark 64-bit DMA broken on Tegra124
  - sdhci-esdhc-imx: Fixups related to data timeouts
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJX9NVDAAoJEP4mhCVzWIwpjCAP/Am7i2zfql9Gq/rhbrcp7dTe
 eTWnz/nuadqGV8p4DCMP+SzTZQpKrP1+mihnpoxDy7o+VLsu6YLrQ5xD/YBCv40j
 6Fat0fK1Cym1QSFW7nPjTL2qUAt5BbNJbiMHwqFupXpdtoFuVsMCOWJJktno1QW6
 VkAdsr2mbamY6nlpVV0INlJuss2Hqh05PEEYISHdbYxSCjMWsTZm7p2Eghkuwics
 dZMVxkLIw93BRxLf91b7s6dVerYGfKAq16pV3dmeejtW9vNwcmSGQMcMbTRZHOSl
 CtMhx1Qw88vYtGgl3LV0mKa+2/06ZWNG9ZwakuNTQZI5khVjmGuwJDINpEBq/lcC
 0QXNLhzx+Z4h+s2iY02Xv5k0tywcHlG9blIPXE6z3O1nsFVdXjyUQ5KcM9w8rbcS
 X4auw3ERLoVgyPgK1gKKax1z8dO7JnvmwFZYgVZxsbj7lIYr+2xs42R5R3enDzmt
 HPLDvqiM4RQKbpZxaiCos3XcrBs258SpPoHQSl5JyCYsYhAfQKcOZWdJpIr3BK7d
 SRQupbEzK160i6Umz6+VU15CFnaBqD3Atab4XTEt/GBY+RbzK/FeWKpeYIrPV8xe
 GSi3WN+BwIi3tczg8J81CBgr0gFqOh7VNz0lmvrm+YqvARAmRqJxIijNWU4ZwGdi
 Q1gOTVWSveyIM87PhMhG
 =b0/p
 -----END PGP SIGNATURE-----

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

Pull MMC updates from Ulf Hansson:

  MMC core:
   - Add support for sending commands during data transfer
   - Erase/discard/trim improvements
   - Improved error handling
   - Extend sysfs with SD status register
   - Document info about the vmmc/vmmcq regulators
   - Extend pwrseq-simple to manage an optional post-power-on-delay
   - Some various minor improvements and cleanups

  MMC host:
   - dw_mmc: Add reset support
   - dw_mmc: Return -EILSEQ for EBE and SBE error
   - dw_mmc: Some cleanups
   - dw_mmc-k3: Add UHS-I support Hisilicon Hikey
   - tmio: Add eMMC support
   - sh_mobile_sdhi: Add r8a7796 support
   - sunxi: Don't use sample clocks for sun4i/sun5i
   - sunxi: Add support for A64 mmc controller
   - sunxi: Some cleanups and improvements
   - sdhci: Support for sending commands during data transfer
   - sdhci: Do not allow tuning procedure to be interrupted
   - sdhci-pci: Enable SD/SDIO on Merrifield
   - sdhci-pci|acpi: Enable MMC_CAP_CMD_DURING_TFR
   - sdhci-pci: Some cleanups
   - sdhci-of-arasan: Set controller to test mode when no CD bit
   - sdhci-of-arasan: Some fixes for clocks and phys
   - sdhci-brcmstb: Don't use ADMA 64-bit when not supported
   - sdhci-tegra: Mark 64-bit DMA broken on Tegra124
   - sdhci-esdhc-imx: Fixups related to data timeouts

* tag 'mmc-v4.9' of git://git.linaro.org/people/ulf.hansson/mmc: (68 commits)
  mmc: dw_mmc: remove the deprecated "supports-highspeed" property
  mmc: dw_mmc: minor cleanup for dw_mci_adjust_fifoth
  mmc: dw_mmc: use macro to define ring buffer size
  mmc: dw_mmc: fix misleading error print if failing to do DMA transfer
  mmc: dw_mmc: avoid race condition of cpu and IDMAC
  mmc: dw_mmc: split out preparation of desc for IDMAC32 and IDMAC64
  mmc: core: don't try to switch block size for dual rate mode
  mmc: sdhci-of-arasan: Set controller to test mode when no CD bit
  dt: sdhci-of-arasan: Add device tree option xlnx, fails-without-test-cd
  mmc: tmio: add eMMC support
  mmc: rtsx_usb: use new macro for R1 without CRC
  mmc: rtsx_pci: use new macro for R1 without CRC
  mmc: add define for R1 response without CRC
  mmc: card: do away with indirection pointer
  mmc: sdhci-acpi: Set MMC_CAP_CMD_DURING_TFR for Intel eMMC controllers
  mmc: sdhci-pci: Set MMC_CAP_CMD_DURING_TFR for Intel eMMC controllers
  mmc: sdhci: Support cap_cmd_during_tfr requests
  mmc: mmc_test: Add tests for sending commands during transfer
  mmc: core: Add support for sending commands during data transfer
  mmc: sdhci-brcmstb: Fix incorrect capability
  ...
This commit is contained in:
Linus Torvalds 2016-10-05 11:34:53 -07:00
commit 64cbd16a87
49 changed files with 1305 additions and 481 deletions

View File

@ -36,6 +36,9 @@ Optional Properties:
- #clock-cells: If specified this should be the value <0>. With this property
in place we will export a clock representing the Card Clock. This clock
is expected to be consumed by our PHY. You must also specify
- xlnx,fails-without-test-cd: when present, the controller doesn't work when
the CD line is not connected properly, and the line is not connected
properly. Test mode can be used to force the controller to function.
Example:
sdhci@e0100000 {

View File

@ -8,7 +8,9 @@ on Device Tree properties to enable them for SoC/Board combinations
that support them.
Required properties:
- compatible: "brcm,bcm7425-sdhci"
- compatible: should be one of the following
- "brcm,bcm7425-sdhci"
- "brcm,bcm7445-sdhci"
Refer to clocks/clock-bindings.txt for generic clock consumer properties.

View File

@ -16,6 +16,8 @@ Optional properties:
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entry:
"ext_clock" (External clock provided to the card).
- post-power-on-delay-ms : Delay in ms after powering the card and
de-asserting the reset-gpios (if any)
Example:

View File

@ -75,6 +75,17 @@ Optional SDIO properties:
- wakeup-source: Enables wake up of host system on SDIO IRQ assertion
(Legacy property supported: "enable-sdio-wakeup")
MMC power
---------
Controllers may implement power control from both the connected cards and
the IO signaling (for example to change to high-speed 1.8V signalling). If
the system supports this, then the following two properties should point
to valid regulator nodes:
- vqmmc-supply: supply node for IO line power
- vmmc-supply: supply node for card's power
MMC power sequences:
--------------------
@ -102,11 +113,13 @@ Required host node properties when using function subnodes:
- #size-cells: should be zero.
Required function subnode properties:
- compatible: name of SDIO function following generic names recommended practice
- reg: Must contain the SDIO function number of the function this subnode
describes. A value of 0 denotes the memory SD function, values from
1 to 7 denote the SDIO functions.
Optional function subnode properties:
- compatible: name of SDIO function following generic names recommended practice
Examples
--------

View File

@ -8,7 +8,12 @@ as the speed of SD standard 3.0.
Absolute maximum transfer rate is 200MB/s
Required properties:
- compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
- compatible : should be one of:
* "allwinner,sun4i-a10-mmc"
* "allwinner,sun5i-a13-mmc"
* "allwinner,sun7i-a20-mmc"
* "allwinner,sun9i-a80-mmc"
* "allwinner,sun50i-a64-mmc"
- reg : mmc controller base registers
- clocks : a list with 4 phandle + clock specifier pairs
- clock-names : must contain "ahb", "mmc", "output" and "sample"

View File

@ -39,6 +39,10 @@ Required Properties:
Optional properties:
* resets: phandle + reset specifier pair, intended to represent hardware
reset signal present internally in some host controller IC designs.
See Documentation/devicetree/bindings/reset/reset.txt for details.
* clocks: from common clock binding: handle to biu and ciu clocks for the
bus interface unit clock and the card interface unit clock.

View File

@ -23,6 +23,7 @@ Required properties:
"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
Optional properties:
- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable

View File

@ -469,7 +469,7 @@
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
clocks = <&ahb1_gates 8>,
<&mmc0_clk 0>,
@ -488,7 +488,7 @@
};
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
clocks = <&ahb1_gates 9>,
<&mmc1_clk 0>,
@ -507,7 +507,7 @@
};
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
clocks = <&ahb1_gates 10>,
<&mmc2_clk 0>,
@ -526,7 +526,7 @@
};
mmc3: mmc@01c12000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c12000 0x1000>;
clocks = <&ahb1_gates 11>,
<&mmc3_clk 0>,

View File

@ -905,7 +905,7 @@
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
clocks = <&ahb_gates 8>,
<&mmc0_clk 0>,
@ -922,7 +922,7 @@
};
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
clocks = <&ahb_gates 9>,
<&mmc1_clk 0>,
@ -939,7 +939,7 @@
};
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
clocks = <&ahb_gates 10>,
<&mmc2_clk 0>,
@ -956,7 +956,7 @@
};
mmc3: mmc@01c12000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c12000 0x1000>;
clocks = <&ahb_gates 11>,
<&mmc3_clk 0>,

View File

@ -266,7 +266,7 @@
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
clocks = <&ahb1_gates 8>,
<&mmc0_clk 0>,
@ -285,7 +285,7 @@
};
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
clocks = <&ahb1_gates 9>,
<&mmc1_clk 0>,
@ -304,7 +304,7 @@
};
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
clocks = <&ahb1_gates 10>,
<&mmc2_clk 0>,

View File

@ -150,7 +150,7 @@
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
clocks = <&ccu CLK_BUS_MMC0>,
<&ccu CLK_MMC0>,
@ -169,7 +169,7 @@
};
mmc1: mmc@01c10000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
clocks = <&ccu CLK_BUS_MMC1>,
<&ccu CLK_MMC1>,
@ -188,7 +188,7 @@
};
mmc2: mmc@01c11000 {
compatible = "allwinner,sun5i-a13-mmc";
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
clocks = <&ccu CLK_BUS_MMC2>,
<&ccu CLK_MMC2>,

View File

@ -142,8 +142,6 @@ static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
{
struct mmc_packed *packed = mqrq->packed;
BUG_ON(!packed);
mqrq->cmd_type = MMC_PACKED_NONE;
packed->nr_entries = MMC_PACKED_NR_ZERO;
packed->idx_failure = MMC_PACKED_NR_IDX;
@ -1443,8 +1441,6 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
int err, check, status;
u8 *ext_csd;
BUG_ON(!packed);
packed->retries--;
check = mmc_blk_err_check(card, areq);
err = get_card_status(card, &status, 0);
@ -1673,6 +1669,18 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
u8 max_packed_rw = 0;
u8 reqs = 0;
/*
* We don't need to check packed for any further
* operation of packed stuff as we set MMC_PACKED_NONE
* and return zero for reqs if geting null packed. Also
* we clean the flag of MMC_BLK_PACKED_CMD to avoid doing
* it again when removing blk req.
*/
if (!mqrq->packed) {
md->flags &= (~MMC_BLK_PACKED_CMD);
goto no_packed;
}
if (!(md->flags & MMC_BLK_PACKED_CMD))
goto no_packed;
@ -1782,8 +1790,6 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
u8 hdr_blocks;
u8 i = 1;
BUG_ON(!packed);
mqrq->cmd_type = MMC_PACKED_WRITE;
packed->blocks = 0;
packed->idx_failure = MMC_PACKED_NR_IDX;
@ -1887,8 +1893,6 @@ static int mmc_blk_end_packed_req(struct mmc_queue_req *mq_rq)
int idx = packed->idx_failure, i = 0;
int ret = 0;
BUG_ON(!packed);
while (!list_empty(&packed->list)) {
prq = list_entry_rq(packed->list.next);
if (idx == i) {
@ -1917,8 +1921,6 @@ static void mmc_blk_abort_packed_req(struct mmc_queue_req *mq_rq)
struct request *prq;
struct mmc_packed *packed = mq_rq->packed;
BUG_ON(!packed);
while (!list_empty(&packed->list)) {
prq = list_entry_rq(packed->list.next);
list_del_init(&prq->queuelist);
@ -1935,8 +1937,6 @@ static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
struct request_queue *q = mq->queue;
struct mmc_packed *packed = mq_rq->packed;
BUG_ON(!packed);
while (!list_empty(&packed->list)) {
prq = list_entry_rq(packed->list.prev);
if (prq->queuelist.prev != &packed->list) {
@ -2144,7 +2144,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
return 0;
}
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
int ret;
struct mmc_blk_data *md = mq->data;
@ -2265,7 +2265,6 @@ again:
if (ret)
goto err_putdisk;
md->queue.issue_fn = mmc_blk_issue_rq;
md->queue.data = md;
md->disk->major = MMC_BLOCK_MAJOR;
@ -2303,7 +2302,8 @@ again:
set_capacity(md->disk, size);
if (mmc_host_cmd23(card->host)) {
if (mmc_card_mmc(card) ||
if ((mmc_card_mmc(card) &&
card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
(mmc_card_sd(card) &&
card->scr.cmds & SD_SCR_CMD23_SUPPORT))
md->flags |= MMC_BLK_CMD23;

1
drivers/mmc/card/block.h Normal file
View File

@ -0,0 +1 @@
int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);

View File

@ -184,6 +184,29 @@ static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
return mmc_set_blocklen(test->card, size);
}
static bool mmc_test_card_cmd23(struct mmc_card *card)
{
return mmc_card_mmc(card) ||
(mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT);
}
static void mmc_test_prepare_sbc(struct mmc_test_card *test,
struct mmc_request *mrq, unsigned int blocks)
{
struct mmc_card *card = test->card;
if (!mrq->sbc || !mmc_host_cmd23(card->host) ||
!mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
(card->quirks & MMC_QUIRK_BLK_NO_CMD23)) {
mrq->sbc = NULL;
return;
}
mrq->sbc->opcode = MMC_SET_BLOCK_COUNT;
mrq->sbc->arg = blocks;
mrq->sbc->flags = MMC_RSP_R1 | MMC_CMD_AC;
}
/*
* Fill in the mmc_request structure given a set of transfer parameters.
*/
@ -221,6 +244,8 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
mrq->data->sg = sg;
mrq->data->sg_len = sg_len;
mmc_test_prepare_sbc(test, mrq, blocks);
mmc_set_data_timeout(mrq->data, test->card);
}
@ -693,6 +718,8 @@ static int mmc_test_check_result(struct mmc_test_card *test,
ret = 0;
if (mrq->sbc && mrq->sbc->error)
ret = mrq->sbc->error;
if (!ret && mrq->cmd->error)
ret = mrq->cmd->error;
if (!ret && mrq->data->error)
@ -2278,6 +2305,245 @@ static int mmc_test_reset(struct mmc_test_card *test)
return RESULT_FAIL;
}
struct mmc_test_req {
struct mmc_request mrq;
struct mmc_command sbc;
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_command status;
struct mmc_data data;
};
static struct mmc_test_req *mmc_test_req_alloc(void)
{
struct mmc_test_req *rq = kzalloc(sizeof(*rq), GFP_KERNEL);
if (rq) {
rq->mrq.cmd = &rq->cmd;
rq->mrq.data = &rq->data;
rq->mrq.stop = &rq->stop;
}
return rq;
}
static int mmc_test_send_status(struct mmc_test_card *test,
struct mmc_command *cmd)
{
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(test->card->host))
cmd->arg = test->card->rca << 16;
cmd->flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
return mmc_wait_for_cmd(test->card->host, cmd, 0);
}
static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
unsigned int dev_addr, int use_sbc,
int repeat_cmd, int write, int use_areq)
{
struct mmc_test_req *rq = mmc_test_req_alloc();
struct mmc_host *host = test->card->host;
struct mmc_test_area *t = &test->area;
struct mmc_async_req areq;
struct mmc_request *mrq;
unsigned long timeout;
bool expired = false;
int ret = 0, cmd_ret;
u32 status = 0;
int count = 0;
if (!rq)
return -ENOMEM;
mrq = &rq->mrq;
if (use_sbc)
mrq->sbc = &rq->sbc;
mrq->cap_cmd_during_tfr = true;
areq.mrq = mrq;
areq.err_check = mmc_test_check_result_async;
mmc_test_prepare_mrq(test, mrq, t->sg, t->sg_len, dev_addr, t->blocks,
512, write);
if (use_sbc && t->blocks > 1 && !mrq->sbc) {
ret = mmc_host_cmd23(host) ?
RESULT_UNSUP_CARD :
RESULT_UNSUP_HOST;
goto out_free;
}
/* Start ongoing data request */
if (use_areq) {
mmc_start_req(host, &areq, &ret);
if (ret)
goto out_free;
} else {
mmc_wait_for_req(host, mrq);
}
timeout = jiffies + msecs_to_jiffies(3000);
do {
count += 1;
/* Send status command while data transfer in progress */
cmd_ret = mmc_test_send_status(test, &rq->status);
if (cmd_ret)
break;
status = rq->status.resp[0];
if (status & R1_ERROR) {
cmd_ret = -EIO;
break;
}
if (mmc_is_req_done(host, mrq))
break;
expired = time_after(jiffies, timeout);
if (expired) {
pr_info("%s: timeout waiting for Tran state status %#x\n",
mmc_hostname(host), status);
cmd_ret = -ETIMEDOUT;
break;
}
} 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
mmc_wait_for_req_done(test->card->host, mrq);
/*
* For cap_cmd_during_tfr request, upper layer must send stop if
* required.
*/
if (mrq->data->stop && (mrq->data->error || !mrq->sbc)) {
if (ret)
mmc_wait_for_cmd(host, mrq->data->stop, 0);
else
ret = mmc_wait_for_cmd(host, mrq->data->stop, 0);
}
if (ret)
goto out_free;
if (cmd_ret) {
pr_info("%s: Send Status failed: status %#x, error %d\n",
mmc_hostname(test->card->host), status, cmd_ret);
}
ret = mmc_test_check_result(test, mrq);
if (ret)
goto out_free;
ret = mmc_test_wait_busy(test);
if (ret)
goto out_free;
if (repeat_cmd && (t->blocks + 1) << 9 > t->max_tfr)
pr_info("%s: %d commands completed during transfer of %u blocks\n",
mmc_hostname(test->card->host), count, t->blocks);
if (cmd_ret)
ret = cmd_ret;
out_free:
kfree(rq);
return ret;
}
static int __mmc_test_cmds_during_tfr(struct mmc_test_card *test,
unsigned long sz, int use_sbc, int write,
int use_areq)
{
struct mmc_test_area *t = &test->area;
int ret;
if (!(test->card->host->caps & MMC_CAP_CMD_DURING_TFR))
return RESULT_UNSUP_HOST;
ret = mmc_test_area_map(test, sz, 0, 0);
if (ret)
return ret;
ret = mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 0, write,
use_areq);
if (ret)
return ret;
return mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 1, write,
use_areq);
}
static int mmc_test_cmds_during_tfr(struct mmc_test_card *test, int use_sbc,
int write, int use_areq)
{
struct mmc_test_area *t = &test->area;
unsigned long sz;
int ret;
for (sz = 512; sz <= t->max_tfr; sz += 512) {
ret = __mmc_test_cmds_during_tfr(test, sz, use_sbc, write,
use_areq);
if (ret)
return ret;
}
return 0;
}
/*
* Commands during read - no Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_read(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 0, 0, 0);
}
/*
* Commands during write - no Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_write(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 0, 1, 0);
}
/*
* Commands during read - use Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_read_cmd23(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 1, 0, 0);
}
/*
* Commands during write - use Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_write_cmd23(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 1, 1, 0);
}
/*
* Commands during non-blocking read - use Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_read_cmd23_nonblock(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 1, 0, 1);
}
/*
* Commands during non-blocking write - use Set Block Count (CMD23).
*/
static int mmc_test_cmds_during_write_cmd23_nonblock(struct mmc_test_card *test)
{
return mmc_test_cmds_during_tfr(test, 1, 1, 1);
}
static const struct mmc_test_case mmc_test_cases[] = {
{
.name = "Basic write (no data verification)",
@ -2605,6 +2871,48 @@ static const struct mmc_test_case mmc_test_cases[] = {
.name = "Reset test",
.run = mmc_test_reset,
},
{
.name = "Commands during read - no Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_read,
.cleanup = mmc_test_area_cleanup,
},
{
.name = "Commands during write - no Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_write,
.cleanup = mmc_test_area_cleanup,
},
{
.name = "Commands during read - use Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_read_cmd23,
.cleanup = mmc_test_area_cleanup,
},
{
.name = "Commands during write - use Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_write_cmd23,
.cleanup = mmc_test_area_cleanup,
},
{
.name = "Commands during non-blocking read - use Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_read_cmd23_nonblock,
.cleanup = mmc_test_area_cleanup,
},
{
.name = "Commands during non-blocking write - use Set Block Count (CMD23)",
.prepare = mmc_test_area_prepare,
.run = mmc_test_cmds_during_write_cmd23_nonblock,
.cleanup = mmc_test_area_cleanup,
},
};
static DEFINE_MUTEX(mmc_test_lock);

View File

@ -19,7 +19,9 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include "queue.h"
#include "block.h"
#define MMC_QUEUE_BOUNCESZ 65536
@ -68,7 +70,7 @@ static int mmc_queue_thread(void *d)
bool req_is_special = mmc_req_is_special(req);
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
mmc_blk_issue_rq(mq, req);
cond_resched();
if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
mq->flags &= ~MMC_QUEUE_NEW_REQUEST;

View File

@ -57,8 +57,6 @@ struct mmc_queue {
unsigned int flags;
#define MMC_QUEUE_SUSPENDED (1 << 0)
#define MMC_QUEUE_NEW_REQUEST (1 << 1)
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
struct mmc_queue_req mqrq[2];

View File

@ -58,6 +58,9 @@
*/
#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
/* The max erase timeout, used when host->max_busy_timeout isn't specified */
#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
/*
@ -117,6 +120,24 @@ static inline void mmc_should_fail_request(struct mmc_host *host,
#endif /* CONFIG_FAIL_MMC_REQUEST */
static inline void mmc_complete_cmd(struct mmc_request *mrq)
{
if (mrq->cap_cmd_during_tfr && !completion_done(&mrq->cmd_completion))
complete_all(&mrq->cmd_completion);
}
void mmc_command_done(struct mmc_host *host, struct mmc_request *mrq)
{
if (!mrq->cap_cmd_during_tfr)
return;
mmc_complete_cmd(mrq);
pr_debug("%s: cmd done, tfr ongoing (CMD%u)\n",
mmc_hostname(host), mrq->cmd->opcode);
}
EXPORT_SYMBOL(mmc_command_done);
/**
* mmc_request_done - finish processing an MMC request
* @host: MMC host which completed request
@ -143,6 +164,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->retries = 0;
}
if (host->ongoing_mrq == mrq)
host->ongoing_mrq = NULL;
mmc_complete_cmd(mrq);
trace_mmc_request_done(host, mrq);
if (err && cmd->retries && !mmc_card_removed(host->card)) {
@ -155,7 +181,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
} else {
mmc_should_fail_request(host, mrq);
led_trigger_event(host->led, LED_OFF);
if (!host->ongoing_mrq)
led_trigger_event(host->led, LED_OFF);
if (mrq->sbc) {
pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n",
@ -220,6 +247,15 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
}
}
if (mrq->cap_cmd_during_tfr) {
host->ongoing_mrq = mrq;
/*
* Retry path could come through here without having waiting on
* cmd_completion, so ensure it is reinitialised.
*/
reinit_completion(&mrq->cmd_completion);
}
trace_mmc_request_start(host, mrq);
host->ops->request(host, mrq);
@ -386,6 +422,18 @@ static void mmc_wait_done(struct mmc_request *mrq)
complete(&mrq->completion);
}
static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host)
{
struct mmc_request *ongoing_mrq = READ_ONCE(host->ongoing_mrq);
/*
* If there is an ongoing transfer, wait for the command line to become
* available.
*/
if (ongoing_mrq && !completion_done(&ongoing_mrq->cmd_completion))
wait_for_completion(&ongoing_mrq->cmd_completion);
}
/*
*__mmc_start_data_req() - starts data request
* @host: MMC host to start the request
@ -393,17 +441,24 @@ static void mmc_wait_done(struct mmc_request *mrq)
*
* Sets the done callback to be called when request is completed by the card.
* Starts data mmc request execution
* If an ongoing transfer is already in progress, wait for the command line
* to become available before sending another command.
*/
static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
mmc_wait_ongoing_tfr_cmd(host);
mrq->done = mmc_wait_data_done;
mrq->host = host;
init_completion(&mrq->cmd_completion);
err = mmc_start_request(host, mrq);
if (err) {
mrq->cmd->error = err;
mmc_complete_cmd(mrq);
mmc_wait_data_done(mrq);
}
@ -414,12 +469,17 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
mmc_wait_ongoing_tfr_cmd(host);
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
init_completion(&mrq->cmd_completion);
err = mmc_start_request(host, mrq);
if (err) {
mrq->cmd->error = err;
mmc_complete_cmd(mrq);
complete(&mrq->completion);
}
@ -483,8 +543,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
return err;
}
static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd;
@ -525,6 +584,28 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
mmc_retune_release(host);
}
EXPORT_SYMBOL(mmc_wait_for_req_done);
/**
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
* @host: MMC host
* @mrq: MMC request
*
* mmc_is_req_done() is used with requests that have
* mrq->cap_cmd_during_tfr = true. mmc_is_req_done() must be called after
* starting a request and before waiting for it to complete. That is,
* either in between calls to mmc_start_req(), or after mmc_wait_for_req()
* and before mmc_wait_for_req_done(). If it is called at other times the
* result is not meaningful.
*/
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq)
{
if (host->areq)
return host->context_info.is_done_rcv;
else
return completion_done(&mrq->completion);
}
EXPORT_SYMBOL(mmc_is_req_done);
/**
* mmc_pre_req - Prepare for a new request
@ -645,13 +726,18 @@ EXPORT_SYMBOL(mmc_start_req);
* @mrq: MMC request to start
*
* Start a new MMC custom command request for a host, and wait
* for the command to complete. Does not attempt to parse the
* response.
* for the command to complete. In the case of 'cap_cmd_during_tfr'
* requests, the transfer is ongoing and the caller can issue further
* commands that do not use the data lines, and then wait by calling
* mmc_wait_for_req_done().
* Does not attempt to parse the response.
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
if (!mrq->cap_cmd_during_tfr)
mmc_wait_for_req_done(host, mrq);
}
EXPORT_SYMBOL(mmc_wait_for_req);
@ -2202,6 +2288,54 @@ out:
return err;
}
static unsigned int mmc_align_erase_size(struct mmc_card *card,
unsigned int *from,
unsigned int *to,
unsigned int nr)
{
unsigned int from_new = *from, nr_new = nr, rem;
/*
* When the 'card->erase_size' is power of 2, we can use round_up/down()
* to align the erase size efficiently.
*/
if (is_power_of_2(card->erase_size)) {
unsigned int temp = from_new;
from_new = round_up(temp, card->erase_size);
rem = from_new - temp;
if (nr_new > rem)
nr_new -= rem;
else
return 0;
nr_new = round_down(nr_new, card->erase_size);
} else {
rem = from_new % card->erase_size;
if (rem) {
rem = card->erase_size - rem;
from_new += rem;
if (nr_new > rem)
nr_new -= rem;
else
return 0;
}
rem = nr_new % card->erase_size;
if (rem)
nr_new -= rem;
}
if (nr_new == 0)
return 0;
*to = from_new + nr_new;
*from = from_new;
return nr_new;
}
/**
* mmc_erase - erase sectors.
* @card: card to erase
@ -2240,26 +2374,12 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
return -EINVAL;
}
if (arg == MMC_ERASE_ARG) {
rem = from % card->erase_size;
if (rem) {
rem = card->erase_size - rem;
from += rem;
if (nr > rem)
nr -= rem;
else
return 0;
}
rem = nr % card->erase_size;
if (rem)
nr -= rem;
}
if (arg == MMC_ERASE_ARG)
nr = mmc_align_erase_size(card, &from, &to, nr);
if (nr == 0)
return 0;
to = from + nr;
if (to <= from)
return -EINVAL;
@ -2352,6 +2472,8 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
struct mmc_host *host = card->host;
unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;
unsigned int last_timeout = 0;
unsigned int max_busy_timeout = host->max_busy_timeout ?
host->max_busy_timeout : MMC_ERASE_TIMEOUT_MS;
if (card->erase_shift) {
max_qty = UINT_MAX >> card->erase_shift;
@ -2374,15 +2496,15 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
* matter what size of 'host->max_busy_timeout', but if the
* 'host->max_busy_timeout' is large enough for more discard sectors,
* then we can continue to increase the max discard sectors until we
* get a balance value.
* get a balance value. In cases when the 'host->max_busy_timeout'
* isn't specified, use the default max erase timeout.
*/
do {
y = 0;
for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
timeout = mmc_erase_timeout(card, arg, qty + x);
if (qty + x > min_qty &&
timeout > host->max_busy_timeout)
if (qty + x > min_qty && timeout > max_busy_timeout)
break;
if (timeout < last_timeout)
@ -2427,9 +2549,6 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
struct mmc_host *host = card->host;
unsigned int max_discard, max_trim;
if (!host->max_busy_timeout)
return UINT_MAX;
/*
* Without erase_group_def set, MMC erase timeout depends on clock
* frequence which can change. In that case, the best choice is
@ -2447,7 +2566,8 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
max_discard = 0;
}
pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
mmc_hostname(host), max_discard, host->max_busy_timeout);
mmc_hostname(host), max_discard, host->max_busy_timeout ?
host->max_busy_timeout : MMC_ERASE_TIMEOUT_MS);
return max_discard;
}
EXPORT_SYMBOL(mmc_calc_max_discard);
@ -2456,7 +2576,8 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
struct mmc_command cmd = {0};
if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) ||
mmc_card_hs400(card) || mmc_card_hs400es(card))
return 0;
cmd.opcode = MMC_SET_BLOCKLEN;

View File

@ -1029,6 +1029,10 @@ static int mmc_select_hs(struct mmc_card *card)
err = mmc_switch_status(card);
}
if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err);
return err;
}
@ -1265,11 +1269,8 @@ static int mmc_select_hs400es(struct mmc_card *card)
/* Switch card to HS mode */
err = mmc_select_hs(card);
if (err) {
pr_err("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(host), err);
if (err)
goto out_err;
}
err = mmc_switch_status(card);
if (err)

View File

@ -16,6 +16,8 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/property.h>
#include <linux/mmc/host.h>
@ -24,6 +26,7 @@
struct mmc_pwrseq_simple {
struct mmc_pwrseq pwrseq;
bool clk_enabled;
u32 post_power_on_delay_ms;
struct clk *ext_clk;
struct gpio_descs *reset_gpios;
};
@ -64,6 +67,9 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
if (pwrseq->post_power_on_delay_ms)
msleep(pwrseq->post_power_on_delay_ms);
}
static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
@ -111,6 +117,9 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
return PTR_ERR(pwrseq->reset_gpios);
}
device_property_read_u32(dev, "post-power-on-delay-ms",
&pwrseq->post_power_on_delay_ms);
pwrseq->pwrseq.dev = dev;
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
pwrseq->pwrseq.owner = THIS_MODULE;

View File

@ -223,8 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card)
static int mmc_read_ssr(struct mmc_card *card)
{
unsigned int au, es, et, eo;
int err, i;
u32 *ssr;
int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
pr_warn("%s: card lacks mandatory SD Status function\n",
@ -232,33 +231,27 @@ static int mmc_read_ssr(struct mmc_card *card)
return 0;
}
ssr = kmalloc(64, GFP_KERNEL);
if (!ssr)
return -ENOMEM;
err = mmc_app_sd_status(card, ssr);
if (err) {
if (mmc_app_sd_status(card, card->raw_ssr)) {
pr_warn("%s: problem reading SD Status register\n",
mmc_hostname(card->host));
err = 0;
goto out;
return 0;
}
for (i = 0; i < 16; i++)
ssr[i] = be32_to_cpu(ssr[i]);
card->raw_ssr[i] = be32_to_cpu(card->raw_ssr[i]);
/*
* UNSTUFF_BITS only works with four u32s so we have to offset the
* bitfield positions accordingly.
*/
au = UNSTUFF_BITS(ssr, 428 - 384, 4);
au = UNSTUFF_BITS(card->raw_ssr, 428 - 384, 4);
if (au) {
if (au <= 9 || card->scr.sda_spec3) {
card->ssr.au = sd_au_size[au];
es = UNSTUFF_BITS(ssr, 408 - 384, 16);
et = UNSTUFF_BITS(ssr, 402 - 384, 6);
es = UNSTUFF_BITS(card->raw_ssr, 408 - 384, 16);
et = UNSTUFF_BITS(card->raw_ssr, 402 - 384, 6);
if (es && et) {
eo = UNSTUFF_BITS(ssr, 400 - 384, 2);
eo = UNSTUFF_BITS(card->raw_ssr, 400 - 384, 2);
card->ssr.erase_timeout = (et * 1000) / es;
card->ssr.erase_offset = eo * 1000;
}
@ -267,9 +260,8 @@ static int mmc_read_ssr(struct mmc_card *card)
mmc_hostname(card->host));
}
}
out:
kfree(ssr);
return err;
return 0;
}
/*
@ -666,6 +658,14 @@ MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_DEV_ATTR(ssr,
"%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x\n",
card->raw_ssr[0], card->raw_ssr[1], card->raw_ssr[2],
card->raw_ssr[3], card->raw_ssr[4], card->raw_ssr[5],
card->raw_ssr[6], card->raw_ssr[7], card->raw_ssr[8],
card->raw_ssr[9], card->raw_ssr[10], card->raw_ssr[11],
card->raw_ssr[12], card->raw_ssr[13], card->raw_ssr[14],
card->raw_ssr[15]);
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
@ -698,6 +698,7 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
&dev_attr_scr.attr,
&dev_attr_ssr.attr,
&dev_attr_date.attr,
&dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr,

View File

@ -26,8 +26,8 @@
*/
void sdio_claim_host(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);
if (WARN_ON(!func))
return;
mmc_claim_host(func->card->host);
}
@ -42,8 +42,8 @@ EXPORT_SYMBOL_GPL(sdio_claim_host);
*/
void sdio_release_host(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);
if (WARN_ON(!func))
return;
mmc_release_host(func->card->host);
}
@ -62,8 +62,8 @@ int sdio_enable_func(struct sdio_func *func)
unsigned char reg;
unsigned long timeout;
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return -EINVAL;
pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
@ -112,8 +112,8 @@ int sdio_disable_func(struct sdio_func *func)
int ret;
unsigned char reg;
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return -EINVAL;
pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func));
@ -307,6 +307,9 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
unsigned max_blocks;
int ret;
if (!func || (func->num > 7))
return -EINVAL;
/* Do the bulk of the transfer using block mode (if supported). */
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
/* Blocks per command is limited by host count, host transfer
@ -367,7 +370,10 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
int ret;
u8 val;
BUG_ON(!func);
if (!func) {
*err_ret = -EINVAL;
return 0xFF;
}
if (err_ret)
*err_ret = 0;
@ -398,7 +404,10 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
{
int ret;
BUG_ON(!func);
if (!func) {
*err_ret = -EINVAL;
return;
}
ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL);
if (err_ret)
@ -623,7 +632,10 @@ unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
int ret;
unsigned char val;
BUG_ON(!func);
if (!func) {
*err_ret = -EINVAL;
return 0xFF;
}
if (err_ret)
*err_ret = 0;
@ -658,7 +670,10 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
{
int ret;
BUG_ON(!func);
if (!func) {
*err_ret = -EINVAL;
return;
}
if ((addr < 0xF0 || addr > 0xFF) && (!mmc_card_lenient_fn0(func->card))) {
if (err_ret)
@ -684,8 +699,8 @@ EXPORT_SYMBOL_GPL(sdio_f0_writeb);
*/
mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return 0;
return func->card->host->pm_caps;
}
@ -707,8 +722,8 @@ int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
{
struct mmc_host *host;
BUG_ON(!func);
BUG_ON(!func->card);
if (!func)
return -EINVAL;
host = func->card->host;

View File

@ -24,8 +24,6 @@ int mmc_send_io_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_IO_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
@ -71,8 +69,8 @@ static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
struct mmc_command cmd = {0};
int err;
BUG_ON(!host);
BUG_ON(fn > 7);
if (fn > 7)
return -EINVAL;
/* sanity check */
if (addr & ~0x1FFFF)
@ -114,7 +112,6 @@ static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8 *out)
{
BUG_ON(!card);
return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
}
@ -129,8 +126,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned int nents, left_size, i;
unsigned int seg_size = card->host->max_seg_size;
BUG_ON(!card);
BUG_ON(fn > 7);
WARN_ON(blksz == 0);
/* sanity check */

View File

@ -1216,9 +1216,11 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq == NO_IRQ)
if (!r)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
mem_size = resource_size(r);
mem = devm_request_mem_region(&pdev->dev, r->start, mem_size,

View File

@ -225,8 +225,12 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
* Not supported to configure register
* related to HS400
*/
if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) {
if (timing == MMC_TIMING_MMC_HS400)
dev_warn(host->dev,
"cannot configure HS400, unsupported chipset\n");
return;
}
dqs = priv->saved_dqs_en;
strobe = priv->saved_strobe_ctrl;

View File

@ -131,11 +131,17 @@ static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios)
host->bus_hz = clk_get_rate(host->biu_clk);
}
static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
return 0;
}
static const struct dw_mci_drv_data hi6220_data = {
.caps = dw_mci_hi6220_caps,
.switch_voltage = dw_mci_hi6220_switch_voltage,
.set_ios = dw_mci_hi6220_set_ios,
.parse_dt = dw_mci_hi6220_parse_dt,
.execute_tuning = dw_mci_hi6220_execute_tuning,
};
static const struct of_device_id dw_mci_k3_match[] = {

View File

@ -61,6 +61,8 @@
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
SDMMC_IDMAC_INT_TI)
#define DESC_RING_BUF_SZ PAGE_SIZE
struct idmac_desc_64addr {
u32 des0; /* Control Descriptor */
@ -467,136 +469,6 @@ static void dw_mci_dmac_complete_dma(void *arg)
}
}
static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
unsigned int sg_len)
{
unsigned int desc_len;
int i;
if (host->dma_64bit_address == 1) {
struct idmac_desc_64addr *desc_first, *desc_last, *desc;
desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u64 mem_addr = sg_dma_address(&data->sg[i]);
for ( ; length ; desc++) {
desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
length : DW_MCI_DESC_DATA_LENGTH;
length -= desc_len;
/*
* Set the OWN bit and disable interrupts
* for this descriptor
*/
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
IDMAC_DES0_CH;
/* Buffer length */
IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
}
/* Set first descriptor */
desc_first->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */
desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc_last->des0 |= IDMAC_DES0_LD;
} else {
struct idmac_desc *desc_first, *desc_last, *desc;
desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&data->sg[i]);
for ( ; length ; desc++) {
desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
length : DW_MCI_DESC_DATA_LENGTH;
length -= desc_len;
/*
* Set the OWN bit and disable interrupts
* for this descriptor
*/
desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
IDMAC_DES0_DIC |
IDMAC_DES0_CH);
/* Buffer length */
IDMAC_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des2 = cpu_to_le32(mem_addr);
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
}
/* Set first descriptor */
desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
/* Set last descriptor */
desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH |
IDMAC_DES0_DIC));
desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD);
}
wmb(); /* drain writebuffer */
}
static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
{
u32 temp;
dw_mci_translate_sglist(host, host->data, sg_len);
/* Make sure to reset DMA in case we did PIO before this */
dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET);
dw_mci_idmac_reset(host);
/* Select IDMAC interface */
temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_USE_IDMAC;
mci_writel(host, CTRL, temp);
/* drain writebuffer */
wmb();
/* Enable the IDMAC */
temp = mci_readl(host, BMOD);
temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
mci_writel(host, BMOD, temp);
/* Start it running */
mci_writel(host, PLDMND, 1);
return 0;
}
static int dw_mci_idmac_init(struct dw_mci *host)
{
int i;
@ -604,7 +476,8 @@ static int dw_mci_idmac_init(struct dw_mci *host)
if (host->dma_64bit_address == 1) {
struct idmac_desc_64addr *p;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
host->ring_size =
DESC_RING_BUF_SZ / sizeof(struct idmac_desc_64addr);
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
@ -630,7 +503,8 @@ static int dw_mci_idmac_init(struct dw_mci *host)
} else {
struct idmac_desc *p;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
host->ring_size =
DESC_RING_BUF_SZ / sizeof(struct idmac_desc);
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu;
@ -671,6 +545,195 @@ static int dw_mci_idmac_init(struct dw_mci *host)
return 0;
}
static inline int dw_mci_prepare_desc64(struct dw_mci *host,
struct mmc_data *data,
unsigned int sg_len)
{
unsigned int desc_len;
struct idmac_desc_64addr *desc_first, *desc_last, *desc;
unsigned long timeout;
int i;
desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u64 mem_addr = sg_dma_address(&data->sg[i]);
for ( ; length ; desc++) {
desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
length : DW_MCI_DESC_DATA_LENGTH;
length -= desc_len;
/*
* Wait for the former clear OWN bit operation
* of IDMAC to make sure that this descriptor
* isn't still owned by IDMAC as IDMAC's write
* ops and CPU's read ops are asynchronous.
*/
timeout = jiffies + msecs_to_jiffies(100);
while (readl(&desc->des0) & IDMAC_DES0_OWN) {
if (time_after(jiffies, timeout))
goto err_own_bit;
udelay(10);
}
/*
* Set the OWN bit and disable interrupts
* for this descriptor
*/
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
IDMAC_DES0_CH;
/* Buffer length */
IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
}
/* Set first descriptor */
desc_first->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */
desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc_last->des0 |= IDMAC_DES0_LD;
return 0;
err_own_bit:
/* restore the descriptor chain as it's polluted */
dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n");
memset(host->sg_cpu, 0, DESC_RING_BUF_SZ);
dw_mci_idmac_init(host);
return -EINVAL;
}
static inline int dw_mci_prepare_desc32(struct dw_mci *host,
struct mmc_data *data,
unsigned int sg_len)
{
unsigned int desc_len;
struct idmac_desc *desc_first, *desc_last, *desc;
unsigned long timeout;
int i;
desc_first = desc_last = desc = host->sg_cpu;
for (i = 0; i < sg_len; i++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&data->sg[i]);
for ( ; length ; desc++) {
desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
length : DW_MCI_DESC_DATA_LENGTH;
length -= desc_len;
/*
* Wait for the former clear OWN bit operation
* of IDMAC to make sure that this descriptor
* isn't still owned by IDMAC as IDMAC's write
* ops and CPU's read ops are asynchronous.
*/
timeout = jiffies + msecs_to_jiffies(100);
while (readl(&desc->des0) &
cpu_to_le32(IDMAC_DES0_OWN)) {
if (time_after(jiffies, timeout))
goto err_own_bit;
udelay(10);
}
/*
* Set the OWN bit and disable interrupts
* for this descriptor
*/
desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
IDMAC_DES0_DIC |
IDMAC_DES0_CH);
/* Buffer length */
IDMAC_SET_BUFFER1_SIZE(desc, desc_len);
/* Physical address to DMA to/from */
desc->des2 = cpu_to_le32(mem_addr);
/* Update physical address for the next desc */
mem_addr += desc_len;
/* Save pointer to the last descriptor */
desc_last = desc;
}
}
/* Set first descriptor */
desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
/* Set last descriptor */
desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH |
IDMAC_DES0_DIC));
desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD);
return 0;
err_own_bit:
/* restore the descriptor chain as it's polluted */
dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n");
memset(host->sg_cpu, 0, DESC_RING_BUF_SZ);
dw_mci_idmac_init(host);
return -EINVAL;
}
static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
{
u32 temp;
int ret;
if (host->dma_64bit_address == 1)
ret = dw_mci_prepare_desc64(host, host->data, sg_len);
else
ret = dw_mci_prepare_desc32(host, host->data, sg_len);
if (ret)
goto out;
/* drain writebuffer */
wmb();
/* Make sure to reset DMA in case we did PIO before this */
dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET);
dw_mci_idmac_reset(host);
/* Select IDMAC interface */
temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_USE_IDMAC;
mci_writel(host, CTRL, temp);
/* drain writebuffer */
wmb();
/* Enable the IDMAC */
temp = mci_readl(host, BMOD);
temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
mci_writel(host, BMOD, temp);
/* Start it running */
mci_writel(host, PLDMND, 1);
out:
return ret;
}
static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
.init = dw_mci_idmac_init,
.start = dw_mci_idmac_start_dma,
@ -876,11 +939,8 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
* MSIZE is '1',
* if blksz is not a multiple of the FIFO width
*/
if (blksz % fifo_width) {
msize = 0;
rx_wmark = 1;
if (blksz % fifo_width)
goto done;
}
do {
if (!((blksz_depth % mszs[idx]) ||
@ -998,8 +1058,10 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
spin_unlock_irqrestore(&host->irq_lock, irqflags);
if (host->dma_ops->start(host, sg_len)) {
/* We can't do DMA */
dev_err(host->dev, "%s: failed to start DMA.\n", __func__);
/* We can't do DMA, try PIO for this one */
dev_dbg(host->dev,
"%s: fall back to PIO mode for current transfer\n",
__func__);
return -ENODEV;
}
@ -1695,11 +1757,11 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
data->error = -ETIMEDOUT;
} else if (host->dir_status ==
DW_MCI_RECV_STATUS) {
data->error = -EIO;
data->error = -EILSEQ;
}
} else {
/* SDMMC_INT_SBE is included */
data->error = -EIO;
data->error = -EILSEQ;
}
dev_dbg(host->dev, "data error, status 0x%08x\n", status);
@ -2527,47 +2589,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
#ifdef CONFIG_OF
/* given a slot, find out the device node representing that slot */
static struct device_node *dw_mci_of_find_slot_node(struct dw_mci_slot *slot)
{
struct device *dev = slot->mmc->parent;
struct device_node *np;
const __be32 *addr;
int len;
if (!dev || !dev->of_node)
return NULL;
for_each_child_of_node(dev->of_node, np) {
addr = of_get_property(np, "reg", &len);
if (!addr || (len < sizeof(int)))
continue;
if (be32_to_cpup(addr) == slot->id)
return np;
}
return NULL;
}
static void dw_mci_slot_of_parse(struct dw_mci_slot *slot)
{
struct device_node *np = dw_mci_of_find_slot_node(slot);
if (!np)
return;
if (of_property_read_bool(np, "disable-wp")) {
slot->mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
dev_warn(slot->mmc->parent,
"Slot quirk 'disable-wp' is deprecated\n");
}
}
#else /* CONFIG_OF */
static void dw_mci_slot_of_parse(struct dw_mci_slot *slot)
{
}
#endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
@ -2630,8 +2651,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2;
dw_mci_slot_of_parse(slot);
ret = mmc_of_parse(mmc);
if (ret)
goto err_host_allocated;
@ -2736,7 +2755,8 @@ static void dw_mci_init_dma(struct dw_mci *host)
}
/* Alloc memory for sg translation */
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
host->sg_cpu = dmam_alloc_coherent(host->dev,
DESC_RING_BUF_SZ,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
dev_err(host->dev,
@ -2919,6 +2939,13 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
if (!pdata)
return ERR_PTR(-ENOMEM);
/* find reset controller when exist */
pdata->rstc = devm_reset_control_get_optional(dev, NULL);
if (IS_ERR(pdata->rstc)) {
if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
}
/* find out number of slots supported */
of_property_read_u32(np, "num-slots", &pdata->num_slots);
@ -2937,11 +2964,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret);
}
if (of_find_property(np, "supports-highspeed", NULL)) {
dev_info(dev, "supports-highspeed property is deprecated.\n");
pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
}
return pdata;
}
@ -2990,7 +3012,9 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->pdata) {
host->pdata = dw_mci_parse_dt(host);
if (IS_ERR(host->pdata)) {
if (PTR_ERR(host->pdata) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (IS_ERR(host->pdata)) {
dev_err(host->dev, "platform data not available\n");
return -EINVAL;
}
@ -3044,6 +3068,12 @@ int dw_mci_probe(struct dw_mci *host)
}
}
if (!IS_ERR(host->pdata->rstc)) {
reset_control_assert(host->pdata->rstc);
usleep_range(10, 50);
reset_control_deassert(host->pdata->rstc);
}
setup_timer(&host->cmd11_timer,
dw_mci_cmd11_timer, (unsigned long)host);
@ -3193,13 +3223,14 @@ err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
if (!IS_ERR(host->pdata->rstc))
reset_control_assert(host->pdata->rstc);
err_clk_ciu:
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
clk_disable_unprepare(host->ciu_clk);
err_clk_biu:
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
clk_disable_unprepare(host->biu_clk);
return ret;
}
@ -3225,11 +3256,11 @@ void dw_mci_remove(struct dw_mci *host)
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
if (!IS_ERR(host->pdata->rstc))
reset_control_assert(host->pdata->rstc);
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
clk_disable_unprepare(host->ciu_clk);
clk_disable_unprepare(host->biu_clk);
}
EXPORT_SYMBOL(dw_mci_remove);

View File

@ -257,7 +257,7 @@ static void moxart_dma_complete(void *param)
static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
{
u32 len, dir_data, dir_slave;
unsigned long dma_time;
long dma_time;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *dma_chan;
@ -397,7 +397,8 @@ static void moxart_prepare_data(struct moxart_host *host)
static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct moxart_host *host = mmc_priv(mmc);
unsigned long pio_time, flags;
long pio_time;
unsigned long flags;
u32 status;
spin_lock_irqsave(&host->lock, flags);

View File

@ -126,7 +126,7 @@ static int sd_response_type(struct mmc_command *cmd)
return SD_RSP_TYPE_R0;
case MMC_RSP_R1:
return SD_RSP_TYPE_R1;
case MMC_RSP_R1 & ~MMC_RSP_CRC:
case MMC_RSP_R1_NO_CRC:
return SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
case MMC_RSP_R1B:
return SD_RSP_TYPE_R1b;

View File

@ -324,7 +324,7 @@ static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
case MMC_RSP_R1:
rsp_type = SD_RSP_TYPE_R1;
break;
case MMC_RSP_R1 & ~MMC_RSP_CRC:
case MMC_RSP_R1_NO_CRC:
rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
break;
case MMC_RSP_R1B:

View File

@ -275,7 +275,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.chip = &sdhci_acpi_chip_int,
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_WAIT_WHILE_BUSY,
MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY,
.caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,

View File

@ -253,12 +253,14 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
goto err_pltfm_free;
}
if (clk_set_rate(pltfm_priv->clk, host->mmc->f_max) != 0) {
ret = clk_set_rate(pltfm_priv->clk, host->mmc->f_max);
if (ret) {
dev_err(dev, "Failed to set rate core clock\n");
goto err_pltfm_free;
}
if (clk_prepare_enable(pltfm_priv->clk) != 0) {
ret = clk_prepare_enable(pltfm_priv->clk);
if (ret) {
dev_err(dev, "Failed to enable core clock\n");
goto err_pltfm_free;
}

View File

@ -98,6 +98,8 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
* properties through mmc_of_parse().
*/
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm7425-sdhci"))
host->caps &= ~SDHCI_CAN_64BIT;
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50);
@ -121,6 +123,7 @@ err_clk:
static const struct of_device_id sdhci_brcm_of_match[] = {
{ .compatible = "brcm,bcm7425-sdhci" },
{ .compatible = "brcm,bcm7445-sdhci" },
{},
};
MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
@ -128,7 +131,6 @@ MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
static struct platform_driver sdhci_brcmstb_driver = {
.driver = {
.name = "sdhci-brcmstb",
.owner = THIS_MODULE,
.pm = &sdhci_brcmstb_pmops,
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
},

View File

@ -31,6 +31,7 @@
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
#define ESDHC_CTRL_D3CD 0x08
#define ESDHC_BURST_LEN_EN_INCR (1 << 27)
/* VENDOR SPEC register */
@ -928,7 +929,8 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27;
/* Doc Errata: the uSDHC actual maximum timeout count is 1 << 29 */
return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27;
}
static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@ -937,7 +939,8 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
/* use maximum timeout counter */
sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK,
esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
SDHCI_TIMEOUT_CONTROL);
}

View File

@ -26,6 +26,7 @@
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include "sdhci-pltfm.h"
#include <linux/of.h>
#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
@ -35,6 +36,8 @@
#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT)
#define CLK_CTRL_TIMEOUT_MIN_EXP 13
#define PHY_CLK_TOO_SLOW_HZ 400000
/*
* On some SoCs the syscon area has a feature where the upper 16-bits of
* each 32-bit register act as a write mask for the lower 16-bits. This allows
@ -65,10 +68,12 @@ struct sdhci_arasan_soc_ctl_field {
* accessible via the syscon API.
*
* @baseclkfreq: Where to find corecfg_baseclkfreq
* @clockmultiplier: Where to find corecfg_clockmultiplier
* @hiword_update: If true, use HIWORD_UPDATE to access the syscon
*/
struct sdhci_arasan_soc_ctl_map {
struct sdhci_arasan_soc_ctl_field baseclkfreq;
struct sdhci_arasan_soc_ctl_field clockmultiplier;
bool hiword_update;
};
@ -77,6 +82,7 @@ struct sdhci_arasan_soc_ctl_map {
* @host: Pointer to the main SDHCI host structure.
* @clk_ahb: Pointer to the AHB clock
* @phy: Pointer to the generic phy
* @is_phy_on: True if the PHY is on; false if not.
* @sdcardclk_hw: Struct for the clock we might provide to a PHY.
* @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw.
* @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers.
@ -86,16 +92,22 @@ struct sdhci_arasan_data {
struct sdhci_host *host;
struct clk *clk_ahb;
struct phy *phy;
bool is_phy_on;
struct clk_hw sdcardclk_hw;
struct clk *sdcardclk;
struct regmap *soc_ctl_base;
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
unsigned int quirks; /* Arasan deviations from spec */
/* Controller does not have CD wired and will not function normally without */
#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0)
};
static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
.hiword_update = true,
};
@ -170,13 +182,47 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
bool ctrl_phy = false;
if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
ctrl_phy = true;
if (!IS_ERR(sdhci_arasan->phy)) {
if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) {
/*
* If PHY off, set clock to max speed and power PHY on.
*
* Although PHY docs apparently suggest power cycling
* when changing the clock the PHY doesn't like to be
* powered on while at low speeds like those used in ID
* mode. Even worse is powering the PHY on while the
* clock is off.
*
* To workaround the PHY limitations, the best we can
* do is to power it on at a faster speed and then slam
* through low speeds without power cycling.
*/
sdhci_set_clock(host, host->max_clk);
spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
if (ctrl_phy) {
/*
* We'll now fall through to the below case with
* ctrl_phy = false (so we won't turn off/on). The
* sdhci_set_clock() will set the real clock.
*/
} else if (clock > PHY_CLK_TOO_SLOW_HZ) {
/*
* At higher clock speeds the PHY is fine being power
* cycled and docs say you _should_ power cycle when
* changing clock speeds.
*/
ctrl_phy = true;
}
}
if (ctrl_phy && sdhci_arasan->is_phy_on) {
spin_unlock_irq(&host->lock);
phy_power_off(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = false;
}
sdhci_set_clock(host, clock);
@ -185,6 +231,7 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
}
}
@ -203,12 +250,27 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
}
void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
{
u8 ctrl;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
sdhci_reset(host, mask);
if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
}
static struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_arasan_get_timeout_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.reset = sdhci_arasan_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
@ -239,13 +301,14 @@ static int sdhci_arasan_suspend(struct device *dev)
if (ret)
return ret;
if (!IS_ERR(sdhci_arasan->phy)) {
if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) {
ret = phy_power_off(sdhci_arasan->phy);
if (ret) {
dev_err(dev, "Cannot power off phy.\n");
sdhci_resume_host(host);
return ret;
}
sdhci_arasan->is_phy_on = false;
}
clk_disable(pltfm_host->clk);
@ -281,12 +344,13 @@ static int sdhci_arasan_resume(struct device *dev)
return ret;
}
if (!IS_ERR(sdhci_arasan->phy)) {
if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) {
ret = phy_power_on(sdhci_arasan->phy);
if (ret) {
dev_err(dev, "Cannot power on phy.\n");
return ret;
}
sdhci_arasan->is_phy_on = true;
}
return sdhci_resume_host(host);
@ -337,6 +401,45 @@ static const struct clk_ops arasan_sdcardclk_ops = {
.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
};
/**
* sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier
*
* The corecfg_clockmultiplier is supposed to contain clock multiplier
* value of programmable clock generator.
*
* NOTES:
* - Many existing devices don't seem to do this and work fine. To keep
* compatibility for old hardware where the device tree doesn't provide a
* register map, this function is a noop if a soc_ctl_map hasn't been provided
* for this platform.
* - The value of corecfg_clockmultiplier should sync with that of corresponding
* value reading from sdhci_capability_register. So this function is called
* once at probe time and never called again.
*
* @host: The sdhci_host
*/
static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host,
u32 value)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
sdhci_arasan->soc_ctl_map;
/* Having a map is optional */
if (!soc_ctl_map)
return;
/* If we have a map, we expect to have a syscon */
if (!sdhci_arasan->soc_ctl_base) {
pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
mmc_hostname(host->mmc));
return;
}
sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value);
}
/**
* sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
*
@ -462,6 +565,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_arasan_data *sdhci_arasan;
struct device_node *np = pdev->dev.of_node;
host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata,
sizeof(*sdhci_arasan));
@ -516,8 +620,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
}
sdhci_get_of_property(pdev);
if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
pltfm_host->clk = clk_xin;
if (of_device_is_compatible(pdev->dev.of_node,
"rockchip,rk3399-sdhci-5.1"))
sdhci_arasan_update_clockmultiplier(host, 0x0);
sdhci_arasan_update_baseclkfreq(host);
ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev);
@ -547,12 +659,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
goto unreg_clk;
}
ret = phy_power_on(sdhci_arasan->phy);
if (ret < 0) {
dev_err(&pdev->dev, "phy_power_on err.\n");
goto err_phy_power;
}
host->mmc_host_ops.hs400_enhanced_strobe =
sdhci_arasan_hs400_enhanced_strobe;
}
@ -564,9 +670,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
return 0;
err_add_host:
if (!IS_ERR(sdhci_arasan->phy))
phy_power_off(sdhci_arasan->phy);
err_phy_power:
if (!IS_ERR(sdhci_arasan->phy))
phy_exit(sdhci_arasan->phy);
unreg_clk:
@ -589,7 +692,8 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
struct clk *clk_ahb = sdhci_arasan->clk_ahb;
if (!IS_ERR(sdhci_arasan->phy)) {
phy_power_off(sdhci_arasan->phy);
if (sdhci_arasan->is_phy_on)
phy_power_off(sdhci_arasan->phy);
phy_exit(sdhci_arasan->phy);
}

View File

@ -583,7 +583,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
np = pdev->dev.of_node;
if (of_get_property(np, "little-endian", NULL))
if (of_property_read_bool(np, "little-endian"))
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata,
sizeof(struct sdhci_esdhc));
else

View File

@ -156,7 +156,7 @@ static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
if (!gpio_is_valid(gpio))
return;
err = gpio_request(gpio, "sd_cd");
err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd");
if (err < 0)
goto out;
@ -179,7 +179,7 @@ static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
return;
out_free:
gpio_free(gpio);
devm_gpio_free(&slot->chip->pdev->dev, gpio);
out:
dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
}
@ -188,8 +188,6 @@ static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
{
if (slot->cd_irq >= 0)
free_irq(slot->cd_irq, slot);
if (gpio_is_valid(slot->cd_gpio))
gpio_free(slot->cd_gpio);
}
#else
@ -356,6 +354,7 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_CMD_DURING_TFR |
MMC_CAP_WAIT_WHILE_BUSY;
slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
slot->hw_reset = sdhci_pci_int_hw_reset;
@ -421,17 +420,30 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
/* Define Host controllers for Intel Merrifield platform */
#define INTEL_MRFLD_EMMC_0 0
#define INTEL_MRFLD_EMMC_1 1
#define INTEL_MRFLD_SD 2
#define INTEL_MRFLD_SDIO 3
static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
{
if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_0) &&
(PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_1))
/* SD support is not ready yet */
unsigned int func = PCI_FUNC(slot->chip->pdev->devfn);
switch (func) {
case INTEL_MRFLD_EMMC_0:
case INTEL_MRFLD_EMMC_1:
slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE |
MMC_CAP_8_BIT_DATA |
MMC_CAP_1_8V_DDR;
break;
case INTEL_MRFLD_SD:
slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
break;
case INTEL_MRFLD_SDIO:
slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE |
MMC_CAP_POWER_OFF_CARD;
break;
default:
return -ENODEV;
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_1_8V_DDR;
}
return 0;
}
@ -1615,7 +1627,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
slot->chip = chip;
slot->host = host;
slot->pci_bar = bar;
slot->rst_n_gpio = -EINVAL;
slot->cd_gpio = -EINVAL;
slot->cd_idx = -1;
@ -1643,27 +1654,22 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
host->irq = pdev->irq;
ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
ret = pcim_iomap_regions(pdev, BIT(bar), mmc_hostname(host->mmc));
if (ret) {
dev_err(&pdev->dev, "cannot request region\n");
goto cleanup;
}
host->ioaddr = pci_ioremap_bar(pdev, bar);
if (!host->ioaddr) {
dev_err(&pdev->dev, "failed to remap registers\n");
ret = -ENOMEM;
goto release;
}
host->ioaddr = pcim_iomap_table(pdev)[bar];
if (chip->fixes && chip->fixes->probe_slot) {
ret = chip->fixes->probe_slot(slot);
if (ret)
goto unmap;
goto cleanup;
}
if (gpio_is_valid(slot->rst_n_gpio)) {
if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) {
gpio_direction_output(slot->rst_n_gpio, 1);
slot->host->mmc->caps |= MMC_CAP_HW_RESET;
slot->hw_reset = sdhci_pci_gpio_hw_reset;
@ -1702,18 +1708,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
return slot;
remove:
if (gpio_is_valid(slot->rst_n_gpio))
gpio_free(slot->rst_n_gpio);
if (chip->fixes && chip->fixes->remove_slot)
chip->fixes->remove_slot(slot, 0);
unmap:
iounmap(host->ioaddr);
release:
pci_release_region(pdev, bar);
cleanup:
if (slot->data && slot->data->cleanup)
slot->data->cleanup(slot->data);
@ -1738,17 +1735,12 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
sdhci_remove_host(slot->host, dead);
if (gpio_is_valid(slot->rst_n_gpio))
gpio_free(slot->rst_n_gpio);
if (slot->chip->fixes && slot->chip->fixes->remove_slot)
slot->chip->fixes->remove_slot(slot, dead);
if (slot->data && slot->data->cleanup)
slot->data->cleanup(slot->data);
pci_release_region(slot->chip->pdev, slot->pci_bar);
sdhci_free_host(slot->host);
}

View File

@ -72,7 +72,6 @@ struct sdhci_pci_slot {
struct sdhci_host *host;
struct sdhci_pci_data *data;
int pci_bar;
int rst_n_gpio;
int cd_gpio;
int cd_irq;

View File

@ -156,13 +156,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
host->quirks2 = pdata->quirks2;
}
/*
* Some platforms need to probe the controller to be able to
* determine which caps should be used.
*/
if (host->ops && host->ops->platform_init)
host->ops->platform_init(host);
platform_set_drvdata(pdev, host);
return host;

View File

@ -391,6 +391,31 @@ static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata,
};
static const struct sdhci_pltfm_data sdhci_tegra124_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
/*
* The TRM states that the SD/MMC controller found on
* Tegra124 can address 34 bits (the maximum supported by
* the Tegra memory controller), but tests show that DMA
* to or from above 4 GiB doesn't work. This is possibly
* caused by missing programming, though it's not obvious
* what sequence is required. Mark 64-bit DMA broken for
* now to fix this for existing users (e.g. Nyan boards).
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.ops = &tegra114_sdhci_ops,
};
static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
.pdata = &sdhci_tegra124_pdata,
};
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@ -408,7 +433,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
static const struct of_device_id sdhci_tegra_dt_match[] = {
{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 },
{ .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
{ .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },

View File

@ -888,7 +888,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
struct mmc_request *mrq)
{
return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12);
return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
!mrq->cap_cmd_during_tfr;
}
static void sdhci_set_transfer_mode(struct sdhci_host *host,
@ -1031,9 +1032,18 @@ static void sdhci_finish_data(struct sdhci_host *host)
sdhci_do_reset(host, SDHCI_RESET_DATA);
}
/* Avoid triggering warning in sdhci_send_command() */
host->cmd = NULL;
sdhci_send_command(host, data->stop);
/*
* 'cap_cmd_during_tfr' request must not use the command line
* after mmc_command_done() has been called. It is upper layer's
* responsibility to send the stop command if required.
*/
if (data->mrq->cap_cmd_during_tfr) {
sdhci_finish_mrq(host, data->mrq);
} else {
/* Avoid triggering warning in sdhci_send_command() */
host->cmd = NULL;
sdhci_send_command(host, data->stop);
}
} else {
sdhci_finish_mrq(host, data->mrq);
}
@ -1165,6 +1175,9 @@ static void sdhci_finish_command(struct sdhci_host *host)
}
}
if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
mmc_command_done(host->mmc, cmd->mrq);
/*
* The host can send and interrupt when the busy state has
* ended, allowing us to wait without wasting CPU cycles.
@ -2062,7 +2075,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
spin_unlock_irqrestore(&host->lock, flags);
/* Wait for Buffer Read Ready interrupt */
wait_event_interruptible_timeout(host->buf_ready_int,
wait_event_timeout(host->buf_ready_int,
(host->tuning_done == 1),
msecs_to_jiffies(50));
spin_lock_irqsave(&host->lock, flags);

View File

@ -84,6 +84,8 @@
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01
@ -555,7 +557,6 @@ struct sdhci_ops {
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
int (*select_drive_strength)(struct sdhci_host *host,

View File

@ -94,6 +94,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{},
};
MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@ -213,6 +214,13 @@ static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host)
clk_disable_unprepare(priv->clk);
}
static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
}
static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@ -369,7 +377,14 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
host->clk_update = sh_mobile_sdhi_clk_update;
host->clk_disable = sh_mobile_sdhi_clk_disable;
host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch;
/* SDR speeds are only available on Gen2+ */
if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
/* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
host->card_busy = sh_mobile_sdhi_card_busy;
host->start_signal_voltage_switch =
sh_mobile_sdhi_start_signal_voltage_switch;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */

View File

@ -72,6 +72,13 @@
#define SDXC_REG_CHDA (0x90)
#define SDXC_REG_CBDA (0x94)
/* New registers introduced in A64 */
#define SDXC_REG_A12A 0x058 /* SMC Auto Command 12 Register */
#define SDXC_REG_SD_NTSR 0x05C /* SMC New Timing Set Register */
#define SDXC_REG_DRV_DL 0x140 /* Drive Delay Control Register */
#define SDXC_REG_SAMP_DL_REG 0x144 /* SMC sample delay control */
#define SDXC_REG_DS_DL_REG 0x148 /* SMC data strobe delay control */
#define mmc_readl(host, reg) \
readl((host)->reg_base + SDXC_##reg)
#define mmc_writel(host, reg, value) \
@ -217,21 +224,41 @@
#define SDXC_CLK_50M_DDR 3
#define SDXC_CLK_50M_DDR_8BIT 4
#define SDXC_2X_TIMING_MODE BIT(31)
#define SDXC_CAL_START BIT(15)
#define SDXC_CAL_DONE BIT(14)
#define SDXC_CAL_DL_SHIFT 8
#define SDXC_CAL_DL_SW_EN BIT(7)
#define SDXC_CAL_DL_SW_SHIFT 0
#define SDXC_CAL_DL_MASK 0x3f
#define SDXC_CAL_TIMEOUT 3 /* in seconds, 3s is enough*/
struct sunxi_mmc_clk_delay {
u32 output;
u32 sample;
};
struct sunxi_idma_des {
u32 config;
u32 buf_size;
u32 buf_addr_ptr1;
u32 buf_addr_ptr2;
__le32 config;
__le32 buf_size;
__le32 buf_addr_ptr1;
__le32 buf_addr_ptr2;
};
struct sunxi_mmc_cfg {
u32 idma_des_size_bits;
const struct sunxi_mmc_clk_delay *clk_delays;
/* does the IP block support autocalibration? */
bool can_calibrate;
};
struct sunxi_mmc_host {
struct mmc_host *mmc;
struct reset_control *reset;
const struct sunxi_mmc_cfg *cfg;
/* IO mapping base */
void __iomem *reg_base;
@ -241,7 +268,6 @@ struct sunxi_mmc_host {
struct clk *clk_mmc;
struct clk *clk_sample;
struct clk *clk_output;
const struct sunxi_mmc_clk_delay *clk_delays;
/* irq */
spinlock_t lock;
@ -250,7 +276,6 @@ struct sunxi_mmc_host {
u32 sdio_imask;
/* dma */
u32 idma_des_size_bits;
dma_addr_t sg_dma;
void *sg_cpu;
bool wait_dma;
@ -322,25 +347,28 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
{
struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
dma_addr_t next_desc = host->sg_dma;
int i, max_len = (1 << host->idma_des_size_bits);
int i, max_len = (1 << host->cfg->idma_des_size_bits);
for (i = 0; i < data->sg_len; i++) {
pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
SDXC_IDMAC_DES0_DIC;
pdes[i].config = cpu_to_le32(SDXC_IDMAC_DES0_CH |
SDXC_IDMAC_DES0_OWN |
SDXC_IDMAC_DES0_DIC);
if (data->sg[i].length == max_len)
pdes[i].buf_size = 0; /* 0 == max_len */
else
pdes[i].buf_size = data->sg[i].length;
pdes[i].buf_size = cpu_to_le32(data->sg[i].length);
next_desc += sizeof(struct sunxi_idma_des);
pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
pdes[i].buf_addr_ptr2 = (u32)next_desc;
pdes[i].buf_addr_ptr1 =
cpu_to_le32(sg_dma_address(&data->sg[i]));
pdes[i].buf_addr_ptr2 = cpu_to_le32((u32)next_desc);
}
pdes[0].config |= SDXC_IDMAC_DES0_FD;
pdes[i - 1].config |= SDXC_IDMAC_DES0_LD | SDXC_IDMAC_DES0_ER;
pdes[i - 1].config &= ~SDXC_IDMAC_DES0_DIC;
pdes[0].config |= cpu_to_le32(SDXC_IDMAC_DES0_FD);
pdes[i - 1].config |= cpu_to_le32(SDXC_IDMAC_DES0_LD |
SDXC_IDMAC_DES0_ER);
pdes[i - 1].config &= cpu_to_le32(~SDXC_IDMAC_DES0_DIC);
pdes[i - 1].buf_addr_ptr2 = 0;
/*
@ -653,11 +681,84 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
return 0;
}
static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off)
{
u32 reg = readl(host->reg_base + reg_off);
u32 delay;
unsigned long timeout;
if (!host->cfg->can_calibrate)
return 0;
reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT);
reg &= ~SDXC_CAL_DL_SW_EN;
writel(reg | SDXC_CAL_START, host->reg_base + reg_off);
dev_dbg(mmc_dev(host->mmc), "calibration started\n");
timeout = jiffies + HZ * SDXC_CAL_TIMEOUT;
while (!((reg = readl(host->reg_base + reg_off)) & SDXC_CAL_DONE)) {
if (time_before(jiffies, timeout))
cpu_relax();
else {
reg &= ~SDXC_CAL_START;
writel(reg, host->reg_base + reg_off);
return -ETIMEDOUT;
}
}
delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK;
reg &= ~SDXC_CAL_START;
reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN;
writel(reg, host->reg_base + reg_off);
dev_dbg(mmc_dev(host->mmc), "calibration ended, reg is 0x%x\n", reg);
return 0;
}
static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host,
struct mmc_ios *ios, u32 rate)
{
int index;
if (!host->cfg->clk_delays)
return 0;
/* determine delays */
if (rate <= 400000) {
index = SDXC_CLK_400K;
} else if (rate <= 25000000) {
index = SDXC_CLK_25M;
} else if (rate <= 52000000) {
if (ios->timing != MMC_TIMING_UHS_DDR50 &&
ios->timing != MMC_TIMING_MMC_DDR52) {
index = SDXC_CLK_50M;
} else if (ios->bus_width == MMC_BUS_WIDTH_8) {
index = SDXC_CLK_50M_DDR_8BIT;
} else {
index = SDXC_CLK_50M_DDR;
}
} else {
return -EINVAL;
}
clk_set_phase(host->clk_sample, host->cfg->clk_delays[index].sample);
clk_set_phase(host->clk_output, host->cfg->clk_delays[index].output);
return 0;
}
static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
struct mmc_ios *ios)
{
u32 rate, oclk_dly, rval, sclk_dly;
u32 clock = ios->clock;
long rate;
u32 rval, clock = ios->clock;
int ret;
/* 8 bit DDR requires a higher module clock */
@ -666,13 +767,18 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
clock <<= 1;
rate = clk_round_rate(host->clk_mmc, clock);
dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n",
if (rate < 0) {
dev_err(mmc_dev(host->mmc), "error rounding clk to %d: %ld\n",
clock, rate);
return rate;
}
dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %ld\n",
clock, rate);
/* setting clock rate */
ret = clk_set_rate(host->clk_mmc, rate);
if (ret) {
dev_err(mmc_dev(host->mmc), "error setting clk to %d: %d\n",
dev_err(mmc_dev(host->mmc), "error setting clk to %ld: %d\n",
rate, ret);
return ret;
}
@ -692,31 +798,15 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
}
mmc_writel(host, REG_CLKCR, rval);
/* determine delays */
if (rate <= 400000) {
oclk_dly = host->clk_delays[SDXC_CLK_400K].output;
sclk_dly = host->clk_delays[SDXC_CLK_400K].sample;
} else if (rate <= 25000000) {
oclk_dly = host->clk_delays[SDXC_CLK_25M].output;
sclk_dly = host->clk_delays[SDXC_CLK_25M].sample;
} else if (rate <= 52000000) {
if (ios->timing != MMC_TIMING_UHS_DDR50 &&
ios->timing != MMC_TIMING_MMC_DDR52) {
oclk_dly = host->clk_delays[SDXC_CLK_50M].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M].sample;
} else if (ios->bus_width == MMC_BUS_WIDTH_8) {
oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].sample;
} else {
oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;
}
} else {
return -EINVAL;
}
ret = sunxi_mmc_clk_set_phase(host, ios, rate);
if (ret)
return ret;
clk_set_phase(host->clk_sample, sclk_dly);
clk_set_phase(host->clk_output, oclk_dly);
ret = sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL_REG);
if (ret)
return ret;
/* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */
return sunxi_mmc_oclk_onoff(host, 1);
}
@ -938,14 +1028,6 @@ static int sunxi_mmc_card_busy(struct mmc_host *mmc)
return !!(mmc_readl(host, REG_STAS) & SDXC_CARD_DATA_BUSY);
}
static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", },
{ .compatible = "allwinner,sun5i-a13-mmc", },
{ .compatible = "allwinner,sun9i-a80-mmc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
static struct mmc_host_ops sunxi_mmc_ops = {
.request = sunxi_mmc_request,
.set_ios = sunxi_mmc_set_ios,
@ -974,21 +1056,54 @@ static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = {
[SDXC_CLK_50M_DDR_8BIT] = { .output = 72, .sample = 72 },
};
static const struct sunxi_mmc_cfg sun4i_a10_cfg = {
.idma_des_size_bits = 13,
.clk_delays = NULL,
.can_calibrate = false,
};
static const struct sunxi_mmc_cfg sun5i_a13_cfg = {
.idma_des_size_bits = 16,
.clk_delays = NULL,
.can_calibrate = false,
};
static const struct sunxi_mmc_cfg sun7i_a20_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sunxi_mmc_clk_delays,
.can_calibrate = false,
};
static const struct sunxi_mmc_cfg sun9i_a80_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sun9i_mmc_clk_delays,
.can_calibrate = false,
};
static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
.idma_des_size_bits = 16,
.clk_delays = NULL,
.can_calibrate = true,
};
static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", .data = &sun4i_a10_cfg },
{ .compatible = "allwinner,sun5i-a13-mmc", .data = &sun5i_a13_cfg },
{ .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
{ .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
{ .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int ret;
if (of_device_is_compatible(np, "allwinner,sun4i-a10-mmc"))
host->idma_des_size_bits = 13;
else
host->idma_des_size_bits = 16;
if (of_device_is_compatible(np, "allwinner,sun9i-a80-mmc"))
host->clk_delays = sun9i_mmc_clk_delays;
else
host->clk_delays = sunxi_mmc_clk_delays;
host->cfg = of_device_get_match_data(&pdev->dev);
if (!host->cfg)
return -EINVAL;
ret = mmc_regulator_get_supply(host->mmc);
if (ret) {
@ -1014,16 +1129,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
return PTR_ERR(host->clk_mmc);
}
host->clk_output = devm_clk_get(&pdev->dev, "output");
if (IS_ERR(host->clk_output)) {
dev_err(&pdev->dev, "Could not get output clock\n");
return PTR_ERR(host->clk_output);
}
if (host->cfg->clk_delays) {
host->clk_output = devm_clk_get(&pdev->dev, "output");
if (IS_ERR(host->clk_output)) {
dev_err(&pdev->dev, "Could not get output clock\n");
return PTR_ERR(host->clk_output);
}
host->clk_sample = devm_clk_get(&pdev->dev, "sample");
if (IS_ERR(host->clk_sample)) {
dev_err(&pdev->dev, "Could not get sample clock\n");
return PTR_ERR(host->clk_sample);
host->clk_sample = devm_clk_get(&pdev->dev, "sample");
if (IS_ERR(host->clk_sample)) {
dev_err(&pdev->dev, "Could not get sample clock\n");
return PTR_ERR(host->clk_sample);
}
}
host->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");
@ -1120,15 +1237,17 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
mmc->max_blk_count = 8192;
mmc->max_blk_size = 4096;
mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des);
mmc->max_seg_size = (1 << host->idma_des_size_bits);
mmc->max_seg_size = (1 << host->cfg->idma_des_size_bits);
mmc->max_req_size = mmc->max_seg_size * mmc->max_segs;
/* 400kHz ~ 52MHz */
mmc->f_min = 400000;
mmc->f_max = 52000000;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_1_8V_DDR |
MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
if (host->cfg->clk_delays)
mmc->caps |= MMC_CAP_1_8V_DDR;
ret = mmc_of_parse(mmc);
if (ret)
goto error_free_dma;
@ -1160,6 +1279,8 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
if (!IS_ERR(host->reset))
reset_control_assert(host->reset);
clk_disable_unprepare(host->clk_sample);
clk_disable_unprepare(host->clk_output);
clk_disable_unprepare(host->clk_mmc);
clk_disable_unprepare(host->clk_ahb);

View File

@ -79,6 +79,9 @@
#define CLK_CTL_DIV_MASK 0xff
#define CLK_CTL_SCLKEN BIT(8)
#define CARD_OPT_WIDTH8 BIT(13)
#define CARD_OPT_WIDTH BIT(15)
#define TMIO_BBS 512 /* Boot block size */
/* Definitions for values the CTRL_SDIO_STATUS register can take. */
@ -158,6 +161,7 @@ struct tmio_mmc_host {
void (*clk_disable)(struct tmio_mmc_host *host);
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
int (*card_busy)(struct mmc_host *mmc);
int (*start_signal_voltage_switch)(struct mmc_host *mmc,
struct mmc_ios *ios);
};

View File

@ -336,7 +336,9 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE: c |= RESP_NONE; break;
case MMC_RSP_R1: c |= RESP_R1; break;
case MMC_RSP_R1:
case MMC_RSP_R1_NO_CRC:
c |= RESP_R1; break;
case MMC_RSP_R1B: c |= RESP_R1B; break;
case MMC_RSP_R2: c |= RESP_R2; break;
case MMC_RSP_R3: c |= RESP_R3; break;
@ -730,12 +732,13 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n",
data->blksz, data->blocks);
/* Some hardware cannot perform 2 byte requests in 4 bit mode */
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
/* Some hardware cannot perform 2 byte requests in 4/8 bit mode */
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4 ||
host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES;
if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) {
pr_err("%s: %d byte block unsupported in 4 bit mode\n",
pr_err("%s: %d byte block unsupported in 4/8 bit mode\n",
mmc_hostname(host->mmc), data->blksz);
return -EINVAL;
}
@ -857,14 +860,16 @@ static void tmio_mmc_power_off(struct tmio_mmc_host *host)
static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
unsigned char bus_width)
{
switch (bus_width) {
case MMC_BUS_WIDTH_1:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
break;
case MMC_BUS_WIDTH_4:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
break;
}
u16 reg = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT)
& ~(CARD_OPT_WIDTH | CARD_OPT_WIDTH8);
/* reg now applies to MMC_BUS_WIDTH_4 */
if (bus_width == MMC_BUS_WIDTH_1)
reg |= CARD_OPT_WIDTH;
else if (bus_width == MMC_BUS_WIDTH_8)
reg |= CARD_OPT_WIDTH8;
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
}
/* Set MMC clock / power.
@ -960,20 +965,12 @@ static int tmio_multi_io_quirk(struct mmc_card *card,
return blk_size;
}
static int tmio_mmc_card_busy(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
}
static struct mmc_host_ops tmio_mmc_ops = {
.request = tmio_mmc_request,
.set_ios = tmio_mmc_set_ios,
.get_ro = tmio_mmc_get_ro,
.get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
.card_busy = tmio_mmc_card_busy,
.multi_io_quirk = tmio_multi_io_quirk,
};
@ -1072,6 +1069,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
goto host_free;
}
tmio_mmc_ops.card_busy = _host->card_busy;
tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch;
mmc->ops = &tmio_mmc_ops;
@ -1089,6 +1087,15 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
!mmc_card_is_removable(mmc) ||
mmc->slot.cd_irq >= 0);
/*
* On Gen2+, eMMC with NONREMOVABLE currently fails because native
* hotplug gets disabled. It seems RuntimePM related yet we need further
* research. Since we are planning a PM overhaul anyway, let's enforce
* for now the device being active by enabling native hotplug always.
*/
if (pdata->flags & TMIO_MMC_MIN_RCAR2)
_host->native_hotplug = true;
if (tmio_mmc_clk_enable(_host) < 0) {
mmc->f_max = pdata->hclk;
mmc->f_min = mmc->f_max / 512;

View File

@ -292,6 +292,7 @@ struct mmc_card {
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
u32 raw_ssr[16]; /* raw card SSR */
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */

View File

@ -55,6 +55,9 @@ struct mmc_command {
#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
/* Can be used by core to poll after switch to MMC HS mode */
#define MMC_RSP_R1_NO_CRC (MMC_RSP_PRESENT|MMC_RSP_OPCODE)
#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
/*
@ -133,8 +136,12 @@ struct mmc_request {
struct mmc_command *stop;
struct completion completion;
struct completion cmd_completion;
void (*done)(struct mmc_request *);/* completion function */
struct mmc_host *host;
/* Allow other commands during this ongoing data transfer or busy wait */
bool cap_cmd_during_tfr;
};
struct mmc_card;
@ -146,6 +153,9 @@ extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq);
extern bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,

View File

@ -17,6 +17,7 @@
#include <linux/scatterlist.h>
#include <linux/mmc/core.h>
#include <linux/dmaengine.h>
#include <linux/reset.h>
#define MAX_MCI_SLOTS 2
@ -259,6 +260,7 @@ struct dw_mci_board {
/* delay in mS before detecting cards after interrupt */
u32 detect_delay_ms;
struct reset_control *rstc;
struct dw_mci_dma_ops *dma_ops;
struct dma_pdata *data;
};

View File

@ -281,6 +281,7 @@ struct mmc_host {
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
#define MMC_CAP_CMD_DURING_TFR (1 << 29) /* Commands during data transfer */
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
@ -382,6 +383,9 @@ struct mmc_host {
struct mmc_async_req *areq; /* active async req */
struct mmc_context_info context_info; /* async synchronization info */
/* Ongoing data transfer that allows commands during transfer */
struct mmc_request *ongoing_mrq;
#ifdef CONFIG_FAIL_MMC_REQUEST
struct fault_attr fail_mmc_request;
#endif
@ -418,6 +422,7 @@ int mmc_power_restore_host(struct mmc_host *host);
void mmc_detect_change(struct mmc_host *, unsigned long delay);
void mmc_request_done(struct mmc_host *, struct mmc_request *);
void mmc_command_done(struct mmc_host *host, struct mmc_request *mrq);
static inline void mmc_signal_sdio_irq(struct mmc_host *host)
{