summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-01-12 11:56:53 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2017-01-12 11:56:53 +1100
commit9e00aef9fd712dbff33e705899f7010850f67368 (patch)
tree7c35dce4eca430ef5e607c60764e7f6b200f9cbe /drivers
parent377aaa11683970bc32c38a703f87e70898b905bf (diff)
parentd051e947ee0d185316ba6afd95c637e9ee25c42f (diff)
Merge remote-tracking branch 'mmc/next'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/block.c47
-rw-r--r--drivers/mmc/core/core.c10
-rw-r--r--drivers/mmc/core/mmc.c14
-rw-r--r--drivers/mmc/core/mmc_ops.c44
-rw-r--r--drivers/mmc/core/mmc_test.c26
-rw-r--r--drivers/mmc/core/sd_ops.c30
-rw-r--r--drivers/mmc/core/sdio_ops.c10
-rw-r--r--drivers/mmc/host/Kconfig9
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/davinci_mmc.c1
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c1
-rw-r--r--drivers/mmc/host/dw_mmc-k3.c1
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c1
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c1
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c1
-rw-r--r--drivers/mmc/host/dw_mmc-zx.c241
-rw-r--r--drivers/mmc/host/dw_mmc-zx.h31
-rw-r--r--drivers/mmc/host/dw_mmc.c18
-rw-r--r--drivers/mmc/host/dw_mmc.h263
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c9
-rw-r--r--drivers/mmc/host/mtk-sd.c1
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c2
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c2
-rw-r--r--drivers/mmc/host/sdhci-cadence.c1
-rw-r--r--drivers/mmc/host/sdhci-iproc.c11
-rw-r--r--drivers/mmc/host/sdhci.c4
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/sh_mmcif.c28
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c66
-rw-r--r--drivers/mmc/host/tmio_mmc.h1
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c7
-rw-r--r--drivers/mmc/host/via-sdmmc.c1
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c1
33 files changed, 713 insertions, 173 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index cb1698f268f1..6adc3ce28447 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -442,9 +442,9 @@ out:
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_blk_ioc_data *idata)
{
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
+ struct mmc_request mrq = {};
struct scatterlist sg;
int err;
int is_rpmb = false;
@@ -768,9 +768,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
u32 result;
__be32 *blocks;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
@@ -819,7 +819,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
static int get_card_status(struct mmc_card *card, u32 *status, int retries)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SEND_STATUS;
@@ -884,7 +884,7 @@ static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
struct request *req, bool *gen_err, u32 *stop_status)
{
struct mmc_host *host = card->host;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
bool use_r1b_resp = rq_data_dir(req) == WRITE;
@@ -1152,7 +1152,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
if (!mmc_can_erase(card)) {
err = -EOPNOTSUPP;
- goto out;
+ goto fail;
}
from = blk_rq_pos(req);
@@ -1164,23 +1164,22 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
arg = MMC_TRIM_ARG;
else
arg = MMC_ERASE_ARG;
-retry:
- if (card->quirks & MMC_QUIRK_INAND_CMD38) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- INAND_CMD38_ARG_EXT_CSD,
- arg == MMC_TRIM_ARG ?
- INAND_CMD38_ARG_TRIM :
- INAND_CMD38_ARG_ERASE,
- 0);
- if (err)
- goto out;
- }
- err = mmc_erase(card, from, nr, arg);
-out:
- if (err == -EIO && !mmc_blk_reset(md, card->host, type))
- goto retry;
+ do {
+ err = 0;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_TRIM_ARG ?
+ INAND_CMD38_ARG_TRIM :
+ INAND_CMD38_ARG_ERASE,
+ 0);
+ }
+ if (!err)
+ err = mmc_erase(card, from, nr, arg);
+ } while (err == -EIO && !mmc_blk_reset(md, card->host, type));
if (!err)
mmc_blk_reset_success(md, type);
+fail:
blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1076b9d89df3..3b34a751eea1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -807,7 +807,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi);
*/
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {NULL};
+ struct mmc_request mrq = {};
WARN_ON(!host->claimed);
@@ -1648,7 +1648,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err = 0;
u32 clock;
@@ -2129,7 +2129,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int to, unsigned int arg)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0;
bool use_r1b_resp = false;
unsigned long timeout;
@@ -2551,7 +2551,7 @@ EXPORT_SYMBOL(mmc_calc_max_discard);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) ||
mmc_card_hs400(card) || mmc_card_hs400es(card))
@@ -2567,7 +2567,7 @@ EXPORT_SYMBOL(mmc_set_blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_BLOCK_COUNT;
cmd.arg = blockcount & 0x0000FFFF;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b61b52f9da3d..ec2e85c7ae12 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -617,6 +617,12 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.ffu_capable =
(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+
+ card->ext_csd.pre_eol_info = ext_csd[EXT_CSD_PRE_EOL_INFO];
+ card->ext_csd.device_life_time_est_typ_a =
+ ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A];
+ card->ext_csd.device_life_time_est_typ_b =
+ ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B];
}
/* eMMC v5.1 or later */
@@ -764,6 +770,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
+MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
+MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
+ card->ext_csd.device_life_time_est_typ_a,
+ card->ext_csd.device_life_time_est_typ_b);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
@@ -817,6 +827,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_prv.attr,
+ &dev_attr_pre_eol_info.attr,
+ &dev_attr_life_time.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
@@ -1805,7 +1817,7 @@ static int mmc_can_sleep(struct mmc_card *card)
static int mmc_sleep(struct mmc_host *host)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
struct mmc_card *card = host->card;
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
int err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index b11c3455b040..db2969fd39a8 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -57,7 +57,7 @@ static const u8 tuning_blk_pattern_8bit[] = {
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
@@ -79,7 +79,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SELECT_CARD;
@@ -115,7 +115,7 @@ int mmc_deselect_cards(struct mmc_host *host)
*/
int mmc_set_dsr(struct mmc_host *host)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_DSR;
@@ -128,7 +128,7 @@ int mmc_set_dsr(struct mmc_host *host)
int mmc_go_idle(struct mmc_host *host)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
/*
* Non-SPI hosts need to prevent chipselect going active during
@@ -164,7 +164,7 @@ int mmc_go_idle(struct mmc_host *host)
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
cmd.opcode = MMC_SEND_OP_COND;
@@ -203,7 +203,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
@@ -220,7 +220,7 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
int mmc_set_relative_addr(struct mmc_card *card)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
@@ -233,7 +233,7 @@ static int
mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = opcode;
cmd.arg = arg;
@@ -256,9 +256,9 @@ static int
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
u32 opcode, void *buf, unsigned len)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
mrq.cmd = &cmd;
@@ -387,7 +387,7 @@ EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SPI_READ_OCR;
@@ -402,7 +402,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SPI_CRC_ON_OFF;
@@ -533,7 +533,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
{
struct mmc_host *host = card->host;
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
bool use_r1b_resp = use_busy_signal;
unsigned char old_timing = host->ios.timing;
@@ -611,9 +611,9 @@ EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
struct mmc_ios *ios = &host->ios;
const u8 *tuning_block_pattern;
@@ -680,7 +680,7 @@ EXPORT_SYMBOL_GPL(mmc_send_tuning);
int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
/*
* eMMC specification specifies that CMD12 can be used to stop a tuning
@@ -707,9 +707,9 @@ static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
u8 *data_buf;
u8 *test_buf;
@@ -803,7 +803,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
unsigned int opcode;
int err;
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index 3ab6e52d106c..bd8eb9bfc153 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -260,7 +260,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
static int mmc_test_wait_busy(struct mmc_test_card *test)
{
int ret, busy;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
busy = 0;
do {
@@ -292,10 +292,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
static int mmc_test_buffer_transfer(struct mmc_test_card *test,
u8 *buffer, unsigned addr, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
struct scatterlist sg;
@@ -885,10 +885,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
mrq.cmd = &cmd;
mrq.data = &data;
@@ -910,10 +910,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
static int mmc_test_broken_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
struct scatterlist sg;
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index de125a41aa7a..9d5824a37586 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -25,7 +25,7 @@
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
if (WARN_ON(card && card->host != host))
return -EINVAL;
@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd);
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {NULL};
+ struct mmc_request mrq = {};
int i, err;
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -141,7 +141,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
cmd.opcode = SD_APP_OP_COND;
@@ -185,7 +185,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
static const u8 test_pattern = 0xAA;
u8 result_pattern;
@@ -217,7 +217,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
@@ -235,9 +235,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
{
int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
void *data_buf;
@@ -290,9 +290,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
/* NOTE: caller guarantees resp is heap-allocated */
@@ -332,9 +332,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
/* NOTE: caller guarantees ssr is heap-allocated */
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 90fe5545c677..3c0d3ab4324c 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -21,7 +21,7 @@
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
cmd.opcode = SD_IO_SEND_OP_COND;
@@ -66,7 +66,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
unsigned addr, u8 in, u8 *out)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
if (fn > 7)
@@ -118,9 +118,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg, *sg_ptr;
struct sg_table sgtable;
unsigned int nents, left_size, i;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2eb97014dc3f..f08691a58d7e 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -683,6 +683,15 @@ config MMC_DW_ROCKCHIP
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on RK3066, RK3188 and RK3288 SoC's.
+config MMC_DW_ZX
+ tristate "ZTE specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW && ARCH_ZX
+ select MMC_DW_PLTFM
+ help
+ This selects support for ZTE SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on ZX296718 SoC's.
+
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on HAS_DMA
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index ccc9c4cba154..6d548c4ee2fa 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
+obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 36b5af8eadb8..1e2600da105f 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -36,6 +36,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mmc/slot-gpio.h>
+#include <linux/interrupt.h>
#include <linux/platform_data/mmc-davinci.h>
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index e1335289316c..25691cca1881 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -13,7 +13,6 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c
index 9821e6bd5d5e..e38fb0020bb1 100644
--- a/drivers/mmc/host/dw_mmc-k3.c
+++ b/drivers/mmc/host/dw_mmc-k3.c
@@ -11,7 +11,6 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index ab82796b01e2..ab8713297edb 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
#include "dw_mmc.h"
#define PCI_BAR_NO 2
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 1236d49ba36e..58c13e21bd5a 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/of.h>
#include <linux/clk.h>
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 9a46e4694227..372fb6e948c1 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -11,7 +11,6 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
new file mode 100644
index 000000000000..d38e94ae2b85
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-zx.c
@@ -0,0 +1,241 @@
+/*
+ * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Copyright (C) 2016, ZTE Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+#include "dw_mmc-zx.h"
+
+struct dw_mci_zx_priv_data {
+ struct regmap *sysc_base;
+};
+
+enum delay_type {
+ DELAY_TYPE_READ, /* read dqs delay */
+ DELAY_TYPE_CLK, /* clk sample delay */
+};
+
+static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay,
+ enum delay_type dflag)
+{
+ struct dw_mci_zx_priv_data *priv = host->priv;
+ struct regmap *sysc_base = priv->sysc_base;
+ unsigned int clksel;
+ unsigned int loop = 1000;
+ int ret;
+
+ if (!sysc_base)
+ return -EINVAL;
+
+ ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+ PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE |
+ PARA_PHASE_DET_SEL_MASK |
+ PARA_DLL_LOCK_NUM_MASK |
+ DLL_REG_SET | PARA_DLL_START_MASK,
+ PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
+ if (ret)
+ return ret;
+
+ if (dflag == DELAY_TYPE_CLK) {
+ clksel &= ~CLK_SAMP_DELAY_MASK;
+ clksel |= CLK_SAMP_DELAY(delay);
+ } else {
+ clksel &= ~READ_DQS_DELAY_MASK;
+ clksel |= READ_DQS_DELAY(delay);
+ }
+
+ regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
+ regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+ PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
+ DLL_REG_SET,
+ PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
+ DLL_REG_SET);
+
+ do {
+ ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel);
+ if (ret)
+ return ret;
+
+ } while (--loop && !(clksel & ZX_DLL_LOCKED));
+
+ if (!loop) {
+ dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+ struct dw_mci *host = slot->host;
+ struct mmc_host *mmc = slot->mmc;
+ int ret, len = 0, start = 0, end = 0, delay, best = 0;
+
+ for (delay = 1; delay < 128; delay++) {
+ ret = dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
+ if (!ret && mmc_send_tuning(mmc, opcode, NULL)) {
+ if (start >= 0) {
+ end = delay - 1;
+ /* check and update longest good range */
+ if ((end - start) > len) {
+ best = (start + end) >> 1;
+ len = end - start;
+ }
+ }
+ start = -1;
+ end = 0;
+ continue;
+ }
+ if (start < 0)
+ start = delay;
+ }
+
+ if (start >= 0) {
+ end = delay - 1;
+ if ((end - start) > len) {
+ best = (start + end) >> 1;
+ len = end - start;
+ }
+ }
+ if (best < 0)
+ return -EIO;
+
+ dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
+ start, end);
+ return dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
+}
+
+static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
+ struct mmc_ios *ios)
+{
+ int ret;
+
+ /* config phase shift as 90 degree */
+ ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+ struct dw_mci *host = slot->host;
+
+ if (host->verid == 0x290a) /* only for emmc */
+ return dw_mci_zx_emmc_execute_tuning(slot, opcode);
+ /* TODO: Add 0x210a dedicated tuning for sd/sdio */
+
+ return 0;
+}
+
+static int dw_mci_zx_parse_dt(struct dw_mci *host)
+{
+ struct device_node *np = host->dev->of_node;
+ struct device_node *node;
+ struct dw_mci_zx_priv_data *priv;
+ struct regmap *sysc_base;
+ int ret;
+
+ /* syscon is needed only by emmc */
+ node = of_parse_phandle(np, "zte,aon-syscon", 0);
+ if (node) {
+ sysc_base = syscon_node_to_regmap(node);
+ of_node_put(node);
+
+ if (IS_ERR(sysc_base)) {
+ ret = PTR_ERR(sysc_base);
+ if (ret != -EPROBE_DEFER)
+ dev_err(host->dev, "Can't get syscon: %d\n",
+ ret);
+ return ret;
+ }
+ } else {
+ return 0;
+ }
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->sysc_base = sysc_base;
+ host->priv = priv;
+
+ return 0;
+}
+
+static unsigned long zx_dwmmc_caps[3] = {
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+};
+
+static const struct dw_mci_drv_data zx_drv_data = {
+ .caps = zx_dwmmc_caps,
+ .execute_tuning = dw_mci_zx_execute_tuning,
+ .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
+ .parse_dt = dw_mci_zx_parse_dt,
+};
+
+static const struct of_device_id dw_mci_zx_match[] = {
+ { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
+
+static int dw_mci_zx_probe(struct platform_device *pdev)
+{
+ const struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+
+ match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
+ drv_data = match->data;
+
+ return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
+ dw_mci_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver dw_mci_zx_pltfm_driver = {
+ .probe = dw_mci_zx_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = "dwmmc_zx",
+ .of_match_table = dw_mci_zx_match,
+ .pm = &dw_mci_zx_dev_pm_ops,
+ },
+};
+
+module_platform_driver(dw_mci_zx_pltfm_driver);
+
+MODULE_DESCRIPTION("ZTE emmc/sd driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
new file mode 100644
index 000000000000..f369997a39ec
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-zx.h
@@ -0,0 +1,31 @@
+#ifndef _DW_MMC_ZX_H_
+#define _DW_MMC_ZX_H_
+
+/* ZX296718 SoC specific DLL register offset. */
+#define LB_AON_EMMC_CFG_REG0 0x1B0
+#define LB_AON_EMMC_CFG_REG1 0x1B4
+#define LB_AON_EMMC_CFG_REG2 0x1B8
+
+/* LB_AON_EMMC_CFG_REG0 register defines */
+#define PARA_DLL_START(x) ((x) & 0xFF)
+#define PARA_DLL_START_MASK 0xFF
+#define DLL_REG_SET BIT(8)
+#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
+#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
+#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
+#define PARA_PHASE_DET_SEL_MASK (7 << 20)
+#define PARA_DLL_BYPASS_MODE BIT(23)
+#define PARA_HALF_CLK_MODE BIT(24)
+
+/* LB_AON_EMMC_CFG_REG1 register defines */
+#define READ_DQS_DELAY(x) ((x) & 0x7F)
+#define READ_DQS_DELAY_MASK (0x7F)
+#define READ_DQS_BYPASS_MODE BIT(7)
+#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
+#define CLK_SAMP_DELAY_MASK (0x7F << 8)
+#define CLK_SAMP_BYPASS_MODE BIT(15)
+
+/* LB_AON_EMMC_CFG_REG2 register defines */
+#define ZX_DLL_LOCKED BIT(2)
+
+#endif /* _DW_MMC_ZX_H_ */
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b44306b886cb..3d213e7e4df9 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -32,7 +32,6 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
@@ -1113,11 +1112,15 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
mci_writel(host, CTRL, temp);
/*
- * Use the initial fifoth_val for PIO mode.
+ * Use the initial fifoth_val for PIO mode. If wm_algined
+ * is set, we set watermark same as data size.
* If next issued data may be transfered by DMA mode,
* prev_blksz should be invalidated.
*/
- mci_writel(host, FIFOTH, host->fifoth_val);
+ if (host->wm_aligned)
+ dw_mci_adjust_fifoth(host, data);
+ else
+ mci_writel(host, FIFOTH, host->fifoth_val);
host->prev_blksz = 0;
} else {
/*
@@ -2977,6 +2980,11 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+ of_property_read_u32(np, "data-addr", &host->data_addr_override);
+
+ if (of_get_property(np, "fifo-watermark-aligned", NULL))
+ host->wm_aligned = true;
+
if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
@@ -3180,7 +3188,9 @@ int dw_mci_probe(struct dw_mci *host)
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
dev_info(host->dev, "Version ID is %04x\n", host->verid);
- if (host->verid < DW_MMC_240A)
+ if (host->data_addr_override)
+ host->fifo_reg = host->regs + host->data_addr_override;
+ else if (host->verid < DW_MMC_240A)
host->fifo_reg = host->regs + DATA_OFFSET;
else
host->fifo_reg = host->regs + DATA_240A_OFFSET;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index c59465829387..ce347361f3dc 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -14,6 +14,269 @@
#ifndef _DW_MMC_H_
#define _DW_MMC_H_
+#include <linux/scatterlist.h>
+#include <linux/mmc/core.h>
+#include <linux/dmaengine.h>
+#include <linux/reset.h>
+#include <linux/interrupt.h>
+
+#define MAX_MCI_SLOTS 2
+
+enum dw_mci_state {
+ STATE_IDLE = 0,
+ STATE_SENDING_CMD,
+ STATE_SENDING_DATA,
+ STATE_DATA_BUSY,
+ STATE_SENDING_STOP,
+ STATE_DATA_ERROR,
+ STATE_SENDING_CMD11,
+ STATE_WAITING_CMD11_DONE,
+};
+
+enum {
+ EVENT_CMD_COMPLETE = 0,
+ EVENT_XFER_COMPLETE,
+ EVENT_DATA_COMPLETE,
+ EVENT_DATA_ERROR,
+};
+
+enum dw_mci_cookie {
+ COOKIE_UNMAPPED,
+ COOKIE_PRE_MAPPED, /* mapped by pre_req() of dwmmc */
+ COOKIE_MAPPED, /* mapped by prepare_data() of dwmmc */
+};
+
+struct mmc_data;
+
+enum {
+ TRANS_MODE_PIO = 0,
+ TRANS_MODE_IDMAC,
+ TRANS_MODE_EDMAC
+};
+
+struct dw_mci_dma_slave {
+ struct dma_chan *ch;
+ enum dma_transfer_direction direction;
+};
+
+/**
+ * struct dw_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @irq_lock: Spinlock protecting the INTMASK setting.
+ * @regs: Pointer to MMIO registers.
+ * @fifo_reg: Pointer to MMIO registers for data FIFO
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @sg_miter: PIO mapping scatterlist iterator.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ * or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ * transfer is in progress.
+ * @stop_abort: The command currently prepared for stoping transfer.
+ * @prev_blksz: The former transfer blksz record.
+ * @timing: Record of current ios timing.
+ * @use_dma: Whether DMA channel is initialized or not.
+ * @using_dma: Whether DMA is in use for the current transfer.
+ * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
+ * @sg_dma: Bus address of DMA buffer.
+ * @sg_cpu: Virtual address of DMA buffer.
+ * @dma_ops: Pointer to platform-specific DMA callbacks.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ * @ring_size: Buffer size for idma descriptors.
+ * command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @dms: structure of slave-dma private data.
+ * @phy_regs: physical address of controller's register map
+ * @data_status: Snapshot of SR taken upon completion of the current
+ * data transfer. Only valid when EVENT_DATA_COMPLETE or
+ * EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ * to be sent.
+ * @dir_status: Direction of current transfer.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ * to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ * processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ * rate and timeout calculations.
+ * @current_speed: Configured rate of the controller.
+ * @num_slots: Number of slots available.
+ * @fifoth_val: The value of FIFOTH register.
+ * @verid: Denote Version ID.
+ * @dev: Device associated with the MMC controller.
+ * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
+ * @priv: Implementation defined private data.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
+ * @slot: Slots sharing this MMC controller.
+ * @fifo_depth: depth of FIFO.
+ * @data_addr_override: override fifo reg offset with this value.
+ * @wm_aligned: force fifo watermark equal with data length in PIO mode.
+ * Set as true if alignment is needed.
+ * @data_shift: log2 of FIFO item size.
+ * @part_buf_start: Start index in part_buf.
+ * @part_buf_count: Bytes of partial data in part_buf.
+ * @part_buf: Simple buffer for partial fifo reads/writes.
+ * @push_data: Pointer to FIFO push function.
+ * @pull_data: Pointer to FIFO pull function.
+ * @vqmmc_enabled: Status of vqmmc, should be true or false.
+ * @irq_flags: The flags to be passed to request_irq.
+ * @irq: The irq value to be passed to request_irq.
+ * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
+ * @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
+ * @dto_timer: Timer for broken data transfer over scheme.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @irq_lock is an irq-safe spinlock protecting the INTMASK register
+ * to allow the interrupt handler to modify it directly. Held for only long
+ * enough to read-modify-write INTMASK and no other locks are grabbed when
+ * holding this one.
+ *
+ * The @mrq field of struct dw_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interrupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
+struct dw_mci {
+ spinlock_t lock;
+ spinlock_t irq_lock;
+ void __iomem *regs;
+ void __iomem *fifo_reg;
+ u32 data_addr_override;
+ bool wm_aligned;
+
+ struct scatterlist *sg;
+ struct sg_mapping_iter sg_miter;
+
+ struct dw_mci_slot *cur_slot;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_command stop_abort;
+ unsigned int prev_blksz;
+ unsigned char timing;
+
+ /* DMA interface members*/
+ int use_dma;
+ int using_dma;
+ int dma_64bit_address;
+
+ dma_addr_t sg_dma;
+ void *sg_cpu;
+ const struct dw_mci_dma_ops *dma_ops;
+ /* For idmac */
+ unsigned int ring_size;
+
+ /* For edmac */
+ struct dw_mci_dma_slave *dms;
+ /* Registers's physical base address */
+ resource_size_t phy_regs;
+
+ u32 cmd_status;
+ u32 data_status;
+ u32 stop_cmdr;
+ u32 dir_status;
+ struct tasklet_struct tasklet;
+ unsigned long pending_events;
+ unsigned long completed_events;
+ enum dw_mci_state state;
+ struct list_head queue;
+
+ u32 bus_hz;
+ u32 current_speed;
+ u32 num_slots;
+ u32 fifoth_val;
+ u16 verid;
+ struct device *dev;
+ struct dw_mci_board *pdata;
+ const struct dw_mci_drv_data *drv_data;
+ void *priv;
+ struct clk *biu_clk;
+ struct clk *ciu_clk;
+ struct dw_mci_slot *slot[MAX_MCI_SLOTS];
+
+ /* FIFO push and pull */
+ int fifo_depth;
+ int data_shift;
+ u8 part_buf_start;
+ u8 part_buf_count;
+ union {
+ u16 part_buf16;
+ u32 part_buf32;
+ u64 part_buf;
+ };
+ void (*push_data)(struct dw_mci *host, void *buf, int cnt);
+ void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
+
+ bool vqmmc_enabled;
+ unsigned long irq_flags; /* IRQ flags */
+ int irq;
+
+ int sdio_id0;
+
+ struct timer_list cmd11_timer;
+ struct timer_list dto_timer;
+};
+
+/* DMA ops for Internal/External DMAC interface */
+struct dw_mci_dma_ops {
+ /* DMA Ops */
+ int (*init)(struct dw_mci *host);
+ int (*start)(struct dw_mci *host, unsigned int sg_len);
+ void (*complete)(void *host);
+ void (*stop)(struct dw_mci *host);
+ void (*cleanup)(struct dw_mci *host);
+ void (*exit)(struct dw_mci *host);
+};
+
+struct dma_pdata;
+
+/* Board platform data */
+struct dw_mci_board {
+ u32 num_slots;
+
+ unsigned int bus_hz; /* Clock speed at the cclk_in pad */
+
+ u32 caps; /* Capabilities */
+ u32 caps2; /* More capabilities */
+ u32 pm_caps; /* PM capabilities */
+ /*
+ * Override fifo depth. If 0, autodetect it from the FIFOTH register,
+ * but note that this may not be reliable after a bootloader has used
+ * it.
+ */
+ unsigned int fifo_depth;
+
+ /* 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;
+};
+
#define DW_MMC_240A 0x240a
#define DW_MMC_280A 0x280a
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index b352760c041e..bf19d03ce2ee 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -35,6 +35,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
#define DRIVER_NAME "meson-gx-mmc"
@@ -578,13 +579,15 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
{
struct meson_host *host = dev_id;
struct mmc_request *mrq;
- struct mmc_command *cmd = host->cmd;
+ struct mmc_command *cmd;
u32 irq_en, status, raw_status;
irqreturn_t ret = IRQ_HANDLED;
if (WARN_ON(!host))
return IRQ_NONE;
+ cmd = host->cmd;
+
mrq = host->mrq;
if (WARN_ON(!mrq))
@@ -670,10 +673,10 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
int ret = IRQ_HANDLED;
if (WARN_ON(!mrq))
- ret = IRQ_NONE;
+ return IRQ_NONE;
if (WARN_ON(!cmd))
- ret = IRQ_NONE;
+ return IRQ_NONE;
data = cmd->data;
if (data) {
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 10ef2ae1d2f6..d33828efc253 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -28,6 +28,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index ecb99a8d2fa2..41b57713b620 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -707,7 +707,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
err = sd_change_phase(host, sample_point, true);
if (err < 0)
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index dc1abd14acbc..12d2fbe9c520 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -682,7 +682,7 @@ static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
err = sd_change_phase(host, sample_point, 0);
if (err)
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 4b0ecb981842..31e786d1b71a 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -17,6 +17,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
#include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index d7046d67415a..3275d4995812 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -211,14 +211,19 @@ static const struct sdhci_iproc_data iproc_data = {
static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_MISSING_CAPS,
+ SDHCI_QUIRK_MISSING_CAPS |
+ SDHCI_QUIRK_NO_HISPD_BIT,
.ops = &sdhci_iproc_32only_ops,
};
static const struct sdhci_iproc_data bcm2835_data = {
.pdata = &sdhci_bcm2835_pltfm_data,
- .caps = SDHCI_CAN_VDD_330,
- .caps1 = 0x00000000,
+ .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
+ & SDHCI_MAX_BLOCK_MASK) |
+ SDHCI_CAN_VDD_330 |
+ SDHCI_CAN_DO_HISPD,
+ .caps1 = SDHCI_DRIVER_TYPE_A |
+ SDHCI_DRIVER_TYPE_C,
.mmc_caps = 0x00000000,
};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 23909804ffb8..51cd4f0e973f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2021,8 +2021,8 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode,
unsigned long flags)
{
struct mmc_host *mmc = host->mmc;
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {};
+ struct mmc_request mrq = {};
cmd.opcode = opcode;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 0b66f210ae82..edf3adfbc213 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -17,6 +17,8 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/interrupt.h>
#include <linux/mmc/host.h>
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 900778421be6..4062d6bef3c8 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1079,26 +1079,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->state = STATE_IDLE;
}
-static int sh_mmcif_get_cd(struct mmc_host *mmc)
-{
- struct sh_mmcif_host *host = mmc_priv(mmc);
- struct device *dev = sh_mmcif_host_to_dev(host);
- struct sh_mmcif_plat_data *p = dev->platform_data;
- int ret = mmc_gpio_get_cd(mmc);
-
- if (ret >= 0)
- return ret;
-
- if (!p || !p->get_cd)
- return -ENOSYS;
- else
- return p->get_cd(host->pd);
-}
-
static struct mmc_host_ops sh_mmcif_ops = {
.request = sh_mmcif_request,
.set_ios = sh_mmcif_set_ios,
- .get_cd = sh_mmcif_get_cd,
+ .get_cd = mmc_gpio_get_cd,
};
static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
@@ -1443,8 +1427,8 @@ static int sh_mmcif_probe(struct platform_device *pdev)
host->mmc = mmc;
host->addr = reg;
host->timeout = msecs_to_jiffies(10000);
- host->ccs_enable = !pd || !pd->ccs_unsupported;
- host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present;
+ host->ccs_enable = true;
+ host->clk_ctrl2_enable = false;
host->pd = pdev;
@@ -1509,12 +1493,6 @@ static int sh_mmcif_probe(struct platform_device *pdev)
}
}
- if (pd && pd->use_cd_gpio) {
- ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0);
- if (ret < 0)
- goto err_clk;
- }
-
mutex_init(&host->thread_lock);
ret = mmc_add_host(mmc);
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index d46c2d00c182..59db14b4827c 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -335,9 +335,6 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
{
struct sh_mobile_sdhi *priv;
- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return 0;
-
priv = host_to_priv(host);
/* set sampling clock selection range */
@@ -444,12 +441,7 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv;
-
- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return 0;
-
- priv = host_to_priv(host);
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
/* Check SCC error */
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
@@ -468,9 +460,6 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
{
struct sh_mobile_sdhi *priv;
- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return;
-
priv = host_to_priv(host);
/* Reset SCC */
@@ -556,8 +545,7 @@ static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
static int sh_mobile_sdhi_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+ const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
struct sh_mobile_sdhi *priv;
struct tmio_mmc_data *mmc_data;
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
@@ -598,9 +586,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eprobe;
}
- if (of_id && of_id->data) {
- const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+ if (of_data) {
mmc_data->flags |= of_data->tmio_flags;
mmc_data->ocr_mask = of_data->tmio_ocr_mask;
mmc_data->capabilities |= of_data->capabilities;
@@ -623,11 +610,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
host->card_busy = sh_mobile_sdhi_card_busy;
host->start_signal_voltage_switch =
sh_mobile_sdhi_start_signal_voltage_switch;
- host->init_tuning = sh_mobile_sdhi_init_tuning;
- host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
- host->select_tuning = sh_mobile_sdhi_select_tuning;
- host->check_scc_error = sh_mobile_sdhi_check_scc_error;
- host->hw_reset = sh_mobile_sdhi_hw_reset;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -668,31 +650,33 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (ret < 0)
goto efree;
- if (host->mmc->caps & MMC_CAP_UHS_SDR104) {
+ /* Enable tuning iff we have an SCC and a supported mode */
+ if (of_data && of_data->scc_offset &&
+ (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
+ host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
+ const struct sh_mobile_sdhi_scc *taps = of_data->taps;
+ bool hit = false;
+
host->mmc->caps |= MMC_CAP_HW_RESET;
- if (of_id && of_id->data) {
- const struct sh_mobile_sdhi_of_data *of_data;
- const struct sh_mobile_sdhi_scc *taps;
- bool hit = false;
-
- of_data = of_id->data;
- taps = of_data->taps;
-
- for (i = 0; i < of_data->taps_num; i++) {
- if (taps[i].clk_rate == 0 ||
- taps[i].clk_rate == host->mmc->f_max) {
- host->scc_tappos = taps->tap;
- hit = true;
- break;
- }
+ for (i = 0; i < of_data->taps_num; i++) {
+ if (taps[i].clk_rate == 0 ||
+ taps[i].clk_rate == host->mmc->f_max) {
+ host->scc_tappos = taps->tap;
+ hit = true;
+ break;
}
+ }
- if (!hit)
- dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
+ if (!hit)
+ dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
- priv->scc_ctl = host->ctl + of_data->scc_offset;
- }
+ priv->scc_ctl = host->ctl + of_data->scc_offset;
+ host->init_tuning = sh_mobile_sdhi_init_tuning;
+ host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+ host->select_tuning = sh_mobile_sdhi_select_tuning;
+ host->check_scc_error = sh_mobile_sdhi_check_scc_error;
+ host->hw_reset = sh_mobile_sdhi_hw_reset;
}
i = 0;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9e20bcf3aa8d..9b2284483cdd 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -24,6 +24,7 @@
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 2064fa1a5bf1..3ca97f3c3079 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -140,12 +140,10 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
~TMIO_SDIO_STAT_IOIRQ;
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
} else if (!enable && host->sdio_irq_enabled) {
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
host->sdio_irq_enabled = false;
pm_runtime_mark_last_busy(mmc_dev(mmc));
@@ -1232,7 +1230,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
_host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask);
- sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0000);
+ sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001);
}
spin_lock_init(&_host->lock);
@@ -1280,6 +1278,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
struct platform_device *pdev = host->pdev;
struct mmc_host *mmc = host->mmc;
+ if (host->pdata->flags & TMIO_MMC_SDIO_IRQ)
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+
if (!host->native_hotplug)
pm_runtime_get_sync(&pdev->dev);
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 63fac78b3d46..6380044c0628 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/mmc/host.h>
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
index 5af00559e9d6..21ebba88679c 100644
--- a/drivers/mmc/host/wmt-sdmmc.c
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>