aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/block.c92
-rw-r--r--drivers/mmc/core/bus.c2
-rw-r--r--drivers/mmc/core/card.h7
-rw-r--r--drivers/mmc/core/core.c20
-rw-r--r--drivers/mmc/core/host.c11
-rw-r--r--drivers/mmc/core/mmc.c6
-rw-r--r--drivers/mmc/core/queue.c9
-rw-r--r--drivers/mmc/core/queue.h1
-rw-r--r--drivers/mmc/core/quirks.h116
-rw-r--r--drivers/mmc/core/sd.c213
-rw-r--r--drivers/mmc/core/sd_ops.c134
-rw-r--r--drivers/mmc/core/sd_ops.h6
-rw-r--r--drivers/mmc/host/Kconfig30
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/bcm2835-mmc.c1560
-rw-r--r--drivers/mmc/host/bcm2835.c17
-rw-r--r--drivers/mmc/host/cqhci-core.c11
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c276
-rw-r--r--drivers/mmc/host/sdhci-iproc.c1
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c60
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c8
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h3
-rw-r--r--drivers/mmc/host/sdhci.c51
-rw-r--r--drivers/mmc/host/sdhci.h9
24 files changed, 2440 insertions, 204 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index dd6cffc0df72..f377c7705e9a 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -218,6 +218,13 @@ static DEFINE_MUTEX(open_lock);
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+/*
+ * Allow quirks to be overridden for the current card
+ */
+static char *card_quirks;
+module_param(card_quirks, charp, 0644);
+MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)");
+
static inline int mmc_blk_part_switch(struct mmc_card *card,
unsigned int part_type);
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
@@ -927,7 +934,10 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card,
if ((part_type & mask) == rpmb) {
if (card->ext_csd.cmdq_en) {
- ret = mmc_cmdq_disable(card);
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_disable(card);
+ else
+ ret = mmc_cmdq_disable(card);
if (ret)
return ret;
}
@@ -946,8 +956,12 @@ static int mmc_blk_part_switch_post(struct mmc_card *card,
if ((part_type & mask) == rpmb) {
mmc_retune_unpause(card->host);
- if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
- ret = mmc_cmdq_enable(card);
+ if (card->reenable_cmdq && !card->ext_csd.cmdq_en) {
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_enable(card);
+ else
+ ret = mmc_cmdq_enable(card);
+ }
}
return ret;
@@ -1158,7 +1172,10 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL:
if (card->ext_csd.cmdq_en) {
- ret = mmc_cmdq_disable(card);
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_disable(card);
+ else
+ ret = mmc_cmdq_disable(card);
if (ret)
break;
}
@@ -1176,8 +1193,12 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
/* Always switch back to main area after RPMB access */
if (rpmb_ioctl)
mmc_blk_part_switch(card, 0);
- else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
- mmc_cmdq_enable(card);
+ else if (card->reenable_cmdq && !card->ext_csd.cmdq_en) {
+ if (mmc_card_sd(card))
+ mmc_sd_cmdq_enable(card);
+ else
+ mmc_cmdq_enable(card);
+ }
break;
case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1219,12 +1240,26 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
sector_t from;
int err = 0;
blk_status_t status = BLK_STS_OK;
+ bool restart_cmdq = false;
if (!mmc_card_can_erase(card)) {
status = BLK_STS_NOTSUPP;
goto fail;
}
+ /*
+ * Only Discard ops are supported with SD cards in CQ mode
+ * (SD Physical Spec v9.00 4.19.2)
+ */
+ if (mmc_card_sd(card) && card->ext_csd.cmdq_en && erase_arg != SD_DISCARD_ARG) {
+ restart_cmdq = true;
+ err = mmc_sd_cmdq_disable(card);
+ if (err) {
+ status = BLK_STS_IOERR;
+ goto fail;
+ }
+ }
+
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
@@ -1245,6 +1280,11 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
status = BLK_STS_IOERR;
else
mmc_blk_reset_success(md, type);
+
+ if (restart_cmdq)
+ err = mmc_sd_cmdq_enable(card);
+ if (err)
+ status = BLK_STS_IOERR;
fail:
blk_mq_end_request(req, status);
}
@@ -1567,6 +1607,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
struct request_queue *q = req->q;
struct mmc_host *host = mq->card->host;
enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ bool write = req_op(req) == REQ_OP_WRITE;
unsigned long flags;
bool put_card;
int err;
@@ -1598,6 +1639,8 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
spin_lock_irqsave(&mq->lock, flags);
+ if (write)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -2011,7 +2054,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
return;
}
- if (rq_data_dir(req) == READ && brq->data.blocks >
+ if (0 && rq_data_dir(req) == READ && brq->data.blocks >
queue_physical_block_size(mq->queue) >> 9) {
/* Read one (native) sector at a time */
mmc_blk_read_single(mq, req);
@@ -2119,6 +2162,8 @@ static void mmc_blk_mq_complete_rq(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
unsigned int nr_bytes = mqrq->brq.data.bytes_xfered;
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
if (nr_bytes) {
if (blk_update_request(req, BLK_STS_OK, nr_bytes))
blk_mq_requeue_request(req, true);
@@ -2213,13 +2258,17 @@ static void mmc_blk_mq_poll_completion(struct mmc_queue *mq,
mmc_blk_urgent_bkops(mq, mqrq);
}
-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type,
+ bool write)
{
unsigned long flags;
bool put_card;
spin_lock_irqsave(&mq->lock, flags);
+ if (write)
+ mq->pending_writes--;
+
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -2234,6 +2283,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req,
bool can_sleep)
{
enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ bool write = req_op(req) == REQ_OP_WRITE;
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
struct mmc_request *mrq = &mqrq->brq.mrq;
struct mmc_host *host = mq->card->host;
@@ -2253,7 +2303,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req,
blk_mq_complete_request(req);
}
- mmc_blk_mq_dec_in_flight(mq, issue_type);
+ mmc_blk_mq_dec_in_flight(mq, issue_type, write);
}
void mmc_blk_mq_recovery(struct mmc_queue *mq)
@@ -3315,6 +3365,8 @@ static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int ret = 0;
+ char quirk_str[24];
+ char cap_str[10];
/*
* Check that the card supports the command class(es) we need.
@@ -3322,7 +3374,16 @@ static int mmc_blk_probe(struct mmc_card *card)
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
- mmc_fixup_device(card, mmc_blk_fixups);
+ if (card_quirks) {
+ unsigned long quirks;
+ if (kstrtoul(card_quirks, 0, &quirks) == 0)
+ card->quirks = (unsigned int)quirks;
+ else
+ pr_err("mmc_block: Invalid card_quirks parameter '%s'\n",
+ card_quirks);
+ }
+ else
+ mmc_fixup_device(card, mmc_blk_fixups);
card->complete_wq = alloc_workqueue("mmc_complete",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
@@ -3337,6 +3398,17 @@ static int mmc_blk_probe(struct mmc_card *card)
goto out_free;
}
+ string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ if (card->quirks)
+ snprintf(quirk_str, sizeof(quirk_str),
+ " (quirks 0x%08x)", card->quirks);
+ else
+ quirk_str[0] = '\0';
+ pr_info("%s: %s %s %s%s%s\n",
+ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+ cap_str, md->read_only ? " (ro)" : "", quirk_str);
+
ret = mmc_blk_alloc_parts(card, md);
if (ret)
goto out;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 1cf64e0952fb..6da9484c13b1 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -266,6 +266,8 @@ static void mmc_release_card(struct device *dev)
sdio_free_common_cis(card);
+ kfree(card->ext_reg_buf);
+
kfree(card->info);
kfree(card);
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index 9cbdd240c3a7..f32955c26d1a 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -88,11 +88,13 @@ struct mmc_fixup {
#define CID_MANFID_GIGASTONE 0x12
#define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15
+#define CID_MANFID_SAMSUNG_SD 0x1b
#define CID_MANFID_APACER 0x27
#define CID_MANFID_SWISSBIT 0x5D
#define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_HYNIX 0x90
#define CID_MANFID_KINGSTON_SD 0x9F
+#define CID_MANFID_LONGSYS_SD 0xAD
#define CID_MANFID_NUMONYX 0xFE
#define END_FIXUP { NULL }
@@ -295,6 +297,11 @@ static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
}
+static inline int mmc_card_working_sd_cq(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_WORKING_SD_CQ;
+}
+
static inline int mmc_card_no_uhs_ddr50_tuning(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_NO_UHS_DDR50_TUNING;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 874c6fe92855..749660629542 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -463,6 +463,7 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
goto out_err;
trace_mmc_request_start(host, mrq);
+ led_trigger_event(host->led, LED_FULL);
return 0;
@@ -550,10 +551,18 @@ int mmc_cqe_recovery(struct mmc_host *host)
* Recovery is expected seldom, if at all, but it reduces performance,
* so make sure it is not completely silent.
*/
- pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
+ pr_warn_ratelimited("%s: running CQE recovery\n", mmc_hostname(host));
host->cqe_ops->cqe_recovery_start(host);
+ err = mmc_detect_card_removed(host);
+ if (err) {
+ host->cqe_ops->cqe_recovery_finish(host);
+ host->cqe_ops->cqe_off(host);
+ mmc_retune_release(host);
+ return err;
+ }
+
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_STOP_TRANSMISSION;
cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */
@@ -563,7 +572,11 @@ int mmc_cqe_recovery(struct mmc_host *host)
mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO);
memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = MMC_CMDQ_TASK_MGMT;
+ if (mmc_card_sd(host->card))
+ cmd.opcode = SD_CMDQ_TASK_MGMT;
+ else
+ cmd.opcode = MMC_CMDQ_TASK_MGMT;
+
cmd.arg = 1; /* Discard entire queue */
cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
@@ -1838,7 +1851,8 @@ EXPORT_SYMBOL(mmc_erase);
bool mmc_card_can_erase(struct mmc_card *card)
{
- return (card->csd.cmdclass & CCC_ERASE && card->erase_size);
+ return (card->csd.cmdclass & CCC_ERASE && card->erase_size) &&
+ !(card->quirks & MMC_QUIRK_ERASE_BROKEN);
}
EXPORT_SYMBOL(mmc_card_can_erase);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index f14671ea5716..09ab3fa7fc25 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -271,7 +271,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase);
int mmc_of_parse(struct mmc_host *host)
{
struct device *dev = host->parent;
- u32 bus_width, drv_type, cd_debounce_delay_ms;
+ u32 bus_width, drv_type, cd_debounce_delay_ms, cq_allow;
int ret;
if (!dev || !dev_fwnode(dev))
@@ -406,6 +406,15 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
+ cq_allow = 0;
+ /*
+ * Downstream property - if a u32 and 2 instead of a bool,
+ * trust most A2 SD cards claiming CQ support.
+ */
+ device_property_read_u32(dev, "supports-cqe", &cq_allow);
+ if (cq_allow == 2)
+ host->caps2 |= MMC_CAP2_SD_CQE_PERMISSIVE;
+
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
if (host->caps & MMC_CAP_NONREMOVABLE)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 5be9b42d5057..5468bdb9d341 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1667,6 +1667,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
card->ocr = ocr;
card->type = MMC_TYPE_MMC;
card->rca = 1;
+ card->max_posted_writes = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
@@ -1925,13 +1926,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
host->cqe_enabled = true;
if (card->ext_csd.cmdq_en) {
- pr_info("%s: Command Queue Engine enabled\n",
- mmc_hostname(host));
+ pr_info("%s: Command Queue Engine enabled, %u tags\n",
+ mmc_hostname(host), card->ext_csd.cmdq_depth);
} else {
host->hsq_enabled = true;
pr_info("%s: Host Software Queue enabled\n",
mmc_hostname(host));
}
+ card->max_posted_writes = card->ext_csd.cmdq_depth;
}
}
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index 284856c8f655..feda8ddbd8b6 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -266,6 +266,11 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
spin_unlock_irq(&mq->lock);
return BLK_STS_RESOURCE;
}
+ if (!host->hsq_enabled && host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
+ mq->pending_writes >= card->max_posted_writes) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
break;
default:
/*
@@ -282,6 +287,8 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
/* Parallel dispatch of requests is not supported at the moment */
mq->busy = true;
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes++;
mq->in_flight[issue_type] += 1;
get_card = (mmc_tot_in_flight(mq) == 1);
cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1);
@@ -321,6 +328,8 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
bool put_card = false;
spin_lock_irq(&mq->lock);
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
if (mmc_tot_in_flight(mq) == 0)
put_card = true;
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
index 1498840a4ea0..39180d97911b 100644
--- a/drivers/mmc/core/queue.h
+++ b/drivers/mmc/core/queue.h
@@ -79,6 +79,7 @@ struct mmc_queue {
struct request_queue *queue;
spinlock_t lock;
int in_flight[MMC_ISSUE_MAX];
+ int pending_writes;
unsigned int cqe_busy;
#define MMC_CQE_DCMD_BUSY BIT(0)
bool busy;
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index c417ed34c057..d975d62b3734 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -18,20 +18,33 @@
static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
/*
* Kingston Canvas Go! Plus microSD cards never finish SD cache flush.
- * This has so far only been observed on cards from 11/2019, while new
- * cards from 2023/05 do not exhibit this behavior.
+ * This has been observed on cards from 2019/11 and 2021/11, while new
+ * cards from 2023/05 and 2024/08 do not exhibit this behavior.
*/
- _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11,
- 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
- MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_KINGSTON_SD, 0x5449, 2019,
+ CID_MONTH_ANY, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_sd, MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_KINGSTON_SD, 0x5449, 2020,
+ CID_MONTH_ANY, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_sd, MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_KINGSTON_SD, 0x5449, 2021,
+ CID_MONTH_ANY, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_sd, MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_KINGSTON_SD, 0x5449, 2022,
+ CID_MONTH_ANY, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_sd, MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
/*
* GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never
* clear Flush Cache bit and set Poweroff Notification Ready bit.
*/
- _FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2,
- 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
- MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
+ _FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2, 0, -1ull,
+ SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE |
+ MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
EXT_CSD_REV_ANY),
/*
@@ -40,8 +53,8 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
* only been observed on cards manufactured on 01/2019 that are using
* Bay Trail host controllers.
*/
- _FIXUP_EXT("0016G", CID_MANFID_SWISSBIT, 0x5342, 2019, 1,
- 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ _FIXUP_EXT("0016G", CID_MANFID_SWISSBIT, 0x5342, 2019, 1, 0, -1ull,
+ SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_NO_UHS_DDR50_TUNING, EXT_CSD_REV_ANY),
/*
@@ -50,13 +63,39 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_DISCARD),
+ /*
+ * Samsung Pro Plus/EVO Plus/Pro Ultimate SD cards (2023) claim to cache
+ * flush OK, but become unresponsive afterwards.
+ */
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SAMSUNG_SD, 0x534d, 2023, CID_MONTH_ANY,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ /*
+ * Early Sandisk Extreme and Extreme Pro A2 cards never finish SD cache
+ * flush in CQ mode. Latest card date this was seen on is 10/2020.
+ */
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2019, CID_MONTH_ANY,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2020, CID_MONTH_ANY,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ /* SD A2 allow-list - only trust CQ on these cards */
+ /* Raspberry Pi A2 cards */
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_LONGSYS_SD, 0x4c53, CID_YEAR_ANY, CID_MONTH_ANY,
+ cid_rev(1, 0, 0, 0), -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_WORKING_SD_CQ, EXT_CSD_REV_ANY),
+
END_FIXUP
};
static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
-#define INAND_CMD38_ARG_EXT_CSD 113
-#define INAND_CMD38_ARG_ERASE 0x00
-#define INAND_CMD38_ARG_TRIM 0x01
+#define INAND_CMD38_ARG_EXT_CSD 113
+#define INAND_CMD38_ARG_ERASE 0x00
+#define INAND_CMD38_ARG_TRIM 0x01
#define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
@@ -153,6 +192,29 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
+ /*
+ * Some SD cards reports discard support while they don't
+ */
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_DISCARD),
+
+ /*
+ * On some Kingston SD cards, multiple erases of less than 64
+ * sectors can cause corruption.
+ */
+ MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+ MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+ MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+
+ /*
+ * Larger Integral SD cards using rebranded Phison controllers trash
+ * nearby flash blocks after erases.
+ */
+ MMC_FIXUP("SD64G", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+ MMC_FIXUP("SD128", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+ MMC_FIXUP("SD256", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+ MMC_FIXUP("SD512", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+
END_FIXUP
};
@@ -161,19 +223,18 @@ static const struct mmc_fixup __maybe_unused mmc_ext_csd_fixups[] = {
* Certain Hynix eMMC 4.41 cards might get broken when HPI feature
* is used so disable the HPI feature for such buggy cards.
*/
- MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
- 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, 0x014a, add_quirk,
+ MMC_QUIRK_BROKEN_HPI, 5),
/*
* Certain Micron (Numonyx) eMMC 4.5 cards might get broken when HPI
* feature is used so disable the HPI feature for such buggy cards.
*/
- MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX,
- 0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6),
+ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX, 0x014e,
+ add_quirk, MMC_QUIRK_BROKEN_HPI, 6),
END_FIXUP
};
-
static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
@@ -181,14 +242,14 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
add_quirk, MMC_QUIRK_DISABLE_CD),
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk,
+ MMC_QUIRK_NONSTD_FUNC_IF),
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_DISABLE_CD),
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk,
+ MMC_QUIRK_DISABLE_CD),
- SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
- add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
+ SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, add_quirk,
+ MMC_QUIRK_BROKEN_BYTE_MODE_512),
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
@@ -204,8 +265,8 @@ static const struct mmc_fixup __maybe_unused sdio_card_init_methods[] = {
SDIO_FIXUP_COMPATIBLE("silabs,wf200", add_quirk,
MMC_QUIRK_BROKEN_BYTE_MODE_512 |
- MMC_QUIRK_LENIENT_FN0 |
- MMC_QUIRK_BLKSZ_FOR_BYTE_MODE),
+ MMC_QUIRK_LENIENT_FN0 |
+ MMC_QUIRK_BLKSZ_FOR_BYTE_MODE),
END_FIXUP
};
@@ -235,8 +296,7 @@ static inline void mmc_fixup_device(struct mmc_card *card,
if (f->manfid != CID_MANFID_ANY &&
f->manfid != card->cid.manfid)
continue;
- if (f->oemid != CID_OEMID_ANY &&
- f->oemid != card->cid.oemid)
+ if (f->oemid != CID_OEMID_ANY && f->oemid != card->cid.oemid)
continue;
if (f->name != CID_NAME_ANY &&
strncmp(f->name, card->cid.prod_name,
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index ec02067f03c5..67b82a6ea09d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -730,7 +730,8 @@ MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
-
+MMC_DEV_ATTR(ext_perf, "%02x\n", card->ext_perf.feature_support);
+MMC_DEV_ATTR(ext_power, "%02x\n", card->ext_power.feature_support);
static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -792,6 +793,8 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_ocr.attr,
&dev_attr_rca.attr,
&dev_attr_dsr.attr,
+ &dev_attr_ext_perf.attr,
+ &dev_attr_ext_power.attr,
NULL,
};
@@ -1034,98 +1037,16 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
}
-static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
- u8 reg_data)
-{
- struct mmc_host *host = card->host;
- struct mmc_request mrq = {};
- struct mmc_command cmd = {};
- struct mmc_data data = {};
- struct scatterlist sg;
- u8 *reg_buf;
-
- reg_buf = kzalloc(512, GFP_KERNEL);
- if (!reg_buf)
- return -ENOMEM;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- /*
- * Arguments of CMD49:
- * [31:31] MIO (0 = memory).
- * [30:27] FNO (function number).
- * [26:26] MW - mask write mode (0 = disable).
- * [25:18] page number.
- * [17:9] offset address.
- * [8:0] length (0 = 1 byte).
- */
- cmd.arg = fno << 27 | page << 18 | offset << 9;
-
- /* The first byte in the buffer is the data to be written. */
- reg_buf[0] = reg_data;
-
- data.flags = MMC_DATA_WRITE;
- data.blksz = 512;
- data.blocks = 1;
- data.sg = &sg;
- data.sg_len = 1;
- sg_init_one(&sg, reg_buf, 512);
-
- cmd.opcode = SD_WRITE_EXTR_SINGLE;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- mmc_set_data_timeout(&data, card);
- mmc_wait_for_req(host, &mrq);
-
- kfree(reg_buf);
-
- /*
- * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
- * after the CMD49. Although, let's leave this to be managed by the
- * caller.
- */
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
-static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
- u16 offset, u16 len, u8 *reg_buf)
-{
- u32 cmd_args;
-
- /*
- * Command arguments of CMD48:
- * [31:31] MIO (0 = memory).
- * [30:27] FNO (function number).
- * [26:26] reserved (0).
- * [25:18] page number.
- * [17:9] offset address.
- * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
- */
- cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
-
- return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
- cmd_args, reg_buf, 512);
-}
-
static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
u16 offset)
{
int err;
u8 *reg_buf;
- reg_buf = kzalloc(512, GFP_KERNEL);
- if (!reg_buf)
- return -ENOMEM;
+ reg_buf = card->ext_reg_buf;
/* Read the extension register for power management function. */
- err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
if (err) {
pr_warn("%s: error %d reading PM func of ext reg\n",
mmc_hostname(card->host), err);
@@ -1152,7 +1073,6 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
card->ext_power.offset = offset;
out:
- kfree(reg_buf);
return err;
}
@@ -1162,11 +1082,9 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
int err;
u8 *reg_buf;
- reg_buf = kzalloc(512, GFP_KERNEL);
- if (!reg_buf)
- return -ENOMEM;
+ reg_buf = card->ext_reg_buf;
- err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
if (err) {
pr_warn("%s: error %d reading PERF func of ext reg\n",
mmc_hostname(card->host), err);
@@ -1192,16 +1110,34 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
if ((reg_buf[4] & BIT(0)) && !mmc_card_broken_sd_cache(card))
card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
- /* Command queue support indicated via queue depth bits (0 to 4). */
- if (reg_buf[6] & 0x1f)
+ /*
+ * Command queue support indicated via queue depth bits (0 to 4).
+ * Qualify this with the other mandatory required features.
+ */
+ if (reg_buf[6] & 0x1f && card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY &&
+ card->ext_perf.feature_support & SD_EXT_PERF_CACHE) {
card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE;
+ card->ext_csd.cmdq_depth = reg_buf[6] & 0x1f;
+ card->ext_csd.cmdq_support = true;
+ pr_debug("%s: Command Queue supported depth %u\n",
+ mmc_hostname(card->host),
+ card->ext_csd.cmdq_depth);
+ /*
+ * If CQ is enabled, there is a contract between host and card such that
+ * VDD will be maintained and removed only if a power off notification
+ * is provided. An SD card in an accessible slot means surprise removal
+ * is a possibility. As a middle ground, keep the default maximum of 1
+ * posted write unless the card is "hardwired".
+ */
+ if (!mmc_card_is_removable(card->host))
+ card->max_posted_writes = card->ext_csd.cmdq_depth;
+ }
card->ext_perf.fno = fno;
card->ext_perf.page = page;
card->ext_perf.offset = offset;
out:
- kfree(reg_buf);
return err;
}
@@ -1256,7 +1192,7 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
return 0;
}
-static int sd_read_ext_regs(struct mmc_card *card)
+static int mmc_sd_read_ext_regs(struct mmc_card *card)
{
int err, i;
u8 num_ext, *gen_info_buf;
@@ -1268,15 +1204,21 @@ static int sd_read_ext_regs(struct mmc_card *card)
if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
return 0;
- gen_info_buf = kzalloc(512, GFP_KERNEL);
+ gen_info_buf = kzalloc(1024, GFP_KERNEL);
if (!gen_info_buf)
return -ENOMEM;
+ card->ext_reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!card->ext_reg_buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+
/*
* Read 512 bytes of general info, which is found at function number 0,
* at page 0 and with no offset.
*/
- err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
+ err = mmc_sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
if (err) {
pr_err("%s: error %d reading general info of SD ext reg\n",
mmc_hostname(card->host), err);
@@ -1293,14 +1235,23 @@ static int sd_read_ext_regs(struct mmc_card *card)
num_ext = gen_info_buf[4];
/*
- * We only support revision 0 and limit it to 512 bytes for simplicity.
+ * We only support revision 0 and up to the spec-defined maximum of 1K.
* No matter what, let's return zero to allow us to continue using the
* card, even if we can't support the features from the SD function
* extensions registers.
*/
- if (rev != 0 || len > 512) {
- pr_warn("%s: non-supported SD ext reg layout\n",
- mmc_hostname(card->host));
+ if (rev != 0 || len > 1024) {
+ pr_warn("%s: non-supported SD ext reg layout rev %u length %u\n",
+ mmc_hostname(card->host), rev, len);
+ goto out;
+ }
+
+ /* If the General Information block spills into the next page, read the rest */
+ if (len > 512)
+ err = mmc_sd_read_ext_reg(card, 0, 1, 0, 512, &gen_info_buf[512]);
+ if (err) {
+ pr_err("%s: error %d reading page 1 of general info of SD ext reg\n",
+ mmc_hostname(card->host), err);
goto out;
}
@@ -1338,9 +1289,7 @@ static int sd_flush_cache(struct mmc_host *host)
if (!sd_cache_enabled(host))
return 0;
- reg_buf = kzalloc(512, GFP_KERNEL);
- if (!reg_buf)
- return -ENOMEM;
+ reg_buf = card->ext_reg_buf;
/*
* Set Flush Cache at bit 0 in the performance enhancement register at
@@ -1350,7 +1299,7 @@ static int sd_flush_cache(struct mmc_host *host)
page = card->ext_perf.page;
offset = card->ext_perf.offset + 261;
- err = sd_write_ext_reg(card, fno, page, offset, BIT(0));
+ err = mmc_sd_write_ext_reg(card, fno, page, offset, BIT(0));
if (err) {
pr_warn("%s: error %d writing Cache Flush bit\n",
mmc_hostname(host), err);
@@ -1366,7 +1315,7 @@ static int sd_flush_cache(struct mmc_host *host)
* Read the Flush Cache bit. The card shall reset it, to confirm that
* it's has completed the flushing of the cache.
*/
- err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
+ err = mmc_sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
if (err) {
pr_warn("%s: error %d reading Cache Flush bit\n",
mmc_hostname(host), err);
@@ -1376,26 +1325,20 @@ static int sd_flush_cache(struct mmc_host *host)
if (reg_buf[0] & BIT(0))
err = -ETIMEDOUT;
out:
- kfree(reg_buf);
return err;
}
static int sd_enable_cache(struct mmc_card *card)
{
- u8 *reg_buf;
int err;
card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE;
- reg_buf = kzalloc(512, GFP_KERNEL);
- if (!reg_buf)
- return -ENOMEM;
-
/*
* Set Cache Enable at bit 0 in the performance enhancement register at
* 260 bytes offset.
*/
- err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+ err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
card->ext_perf.offset + 260, BIT(0));
if (err) {
pr_warn("%s: error %d writing Cache Enable bit\n",
@@ -1409,7 +1352,6 @@ static int sd_enable_cache(struct mmc_card *card)
card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE;
out:
- kfree(reg_buf);
return err;
}
@@ -1452,6 +1394,7 @@ retry:
card->ocr = ocr;
card->type = MMC_TYPE_SD;
+ card->max_posted_writes = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
@@ -1572,7 +1515,7 @@ retry:
cont:
if (!oldcard) {
/* Read/parse the extension registers. */
- err = sd_read_ext_regs(card);
+ err = mmc_sd_read_ext_regs(card);
if (err)
goto free_card;
}
@@ -1584,13 +1527,45 @@ cont:
goto free_card;
}
+ /* Disallow command queueing on unvetted cards unless overridden */
+ if (!(host->caps2 & MMC_CAP2_SD_CQE_PERMISSIVE) && !mmc_card_working_sd_cq(card))
+ card->ext_csd.cmdq_support = false;
+
+ /* Enable command queueing if supported */
+ if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
+ /*
+ * Right now the MMC block layer uses DCMDs to issue
+ * cache-flush commands specific to eMMC devices.
+ * Turning off DCMD support avoids generating Illegal Command
+ * errors on SD, and flushing is instead done synchronously
+ * by mmc_blk_issue_flush().
+ */
+ host->caps2 &= ~MMC_CAP2_CQE_DCMD;
+ err = mmc_sd_cmdq_enable(card);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warn("%s: Enabling CMDQ failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.cmdq_support = false;
+ card->ext_csd.cmdq_depth = 0;
+ }
+ }
+ card->reenable_cmdq = card->ext_csd.cmdq_en;
+
if (!mmc_card_ult_capacity(card) && host->cqe_ops && !host->cqe_enabled) {
err = host->cqe_ops->cqe_enable(host, card);
if (!err) {
host->cqe_enabled = true;
- host->hsq_enabled = true;
- pr_info("%s: Host Software Queue enabled\n",
- mmc_hostname(host));
+
+ if (card->ext_csd.cmdq_en) {
+ pr_info("%s: Command Queue Engine enabled, %u tags\n",
+ mmc_hostname(host), card->ext_csd.cmdq_depth);
+ } else {
+ host->hsq_enabled = true;
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
}
}
@@ -1663,7 +1638,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
* one byte offset and is one byte long. The Power Off Notification
* Ready is bit 0.
*/
- err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ err = mmc_sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
card->ext_power.offset + 1, 1, data->reg_buf);
if (err) {
pr_warn("%s: error %d reading status reg of PM func\n",
@@ -1689,7 +1664,7 @@ static int sd_poweroff_notify(struct mmc_card *card)
* Set the Power Off Notification bit in the power management settings
* register at 2 bytes offset.
*/
- err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ err = mmc_sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
card->ext_power.offset + 2, BIT(0));
if (err) {
pr_warn("%s: error %d writing Power Off Notify bit\n",
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index cd86463dd306..5d03b6b6e69b 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/export.h>
+#include <linux/ktime.h>
#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
@@ -417,3 +418,136 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
return 0;
}
+
+
+int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+ u8 reg_data)
+{
+ struct mmc_host *host = card->host;
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
+ struct scatterlist sg;
+ u8 *reg_buf;
+
+ reg_buf = card->ext_reg_buf;
+ memset(reg_buf, 0, 512);
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ /*
+ * Arguments of CMD49:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] MW - mask write mode (0 = disable).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte).
+ */
+ cmd.arg = fno << 27 | page << 18 | offset << 9;
+
+ /* The first byte in the buffer is the data to be written. */
+ reg_buf[0] = reg_data;
+
+ data.flags = MMC_DATA_WRITE;
+ data.blksz = 512;
+ data.blocks = 1;
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, reg_buf, 512);
+
+ cmd.opcode = SD_WRITE_EXTR_SINGLE;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ mmc_set_data_timeout(&data, card);
+ mmc_wait_for_req(host, &mrq);
+
+ /*
+ * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
+ * after the CMD49. Although, let's leave this to be managed by the
+ * caller.
+ */
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
+int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset, u16 len, u8 *reg_buf)
+{
+ u32 cmd_args;
+
+ /*
+ * Command arguments of CMD48:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] reserved (0).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
+ */
+ cmd_args = fno << 27 | page << 18 | offset << 9 | (len - 1);
+
+ return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
+ cmd_args, reg_buf, 512);
+}
+
+static int mmc_sd_cmdq_switch(struct mmc_card *card, bool enable)
+{
+ int err;
+ u8 reg = 0;
+ u8 *reg_buf = card->ext_reg_buf;
+ ktime_t timeout;
+ /*
+ * SD offers two command queueing modes - sequential (in-order) and
+ * voluntary (out-of-order). Apps Class A2 performance is only
+ * guaranteed for voluntary CQ (bit 1 = 0), so use that in preference
+ * to sequential.
+ */
+ if (enable)
+ reg = BIT(0);
+
+ /* Performance enhancement register byte 262 controls command queueing */
+ err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+ card->ext_perf.offset + 262, reg);
+ if (err)
+ goto out;
+
+ /* Poll the register - cards may have a lazy init/deinit sequence. */
+ timeout = ktime_add_ms(ktime_get(), 10);
+ while (1) {
+ err = mmc_sd_read_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+ card->ext_perf.offset + 262, 1, reg_buf);
+ if (err)
+ break;
+ if ((reg_buf[0] & BIT(0)) == reg)
+ break;
+ if (ktime_after(ktime_get(), timeout)) {
+ err = -EBADMSG;
+ break;
+ }
+ usleep_range(100, 200);
+ }
+out:
+ if (!err)
+ card->ext_csd.cmdq_en = enable;
+
+ return err;
+}
+
+int mmc_sd_cmdq_enable(struct mmc_card *card)
+{
+ return mmc_sd_cmdq_switch(card, true);
+}
+EXPORT_SYMBOL_GPL(mmc_sd_cmdq_enable);
+
+int mmc_sd_cmdq_disable(struct mmc_card *card)
+{
+ return mmc_sd_cmdq_switch(card, false);
+}
+EXPORT_SYMBOL_GPL(mmc_sd_cmdq_disable);
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 8fffc1b29757..db04885ecb0f 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -24,6 +24,12 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr);
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
+int mmc_sd_cmdq_enable(struct mmc_card *card);
+int mmc_sd_cmdq_disable(struct mmc_card *card);
+int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+ u8 reg_data);
+int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset, u16 len, u8 *reg_buf);
#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5cc415ba4f55..6a72ab170ccf 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -5,6 +5,35 @@
comment "MMC/SD/SDIO Host Controller Drivers"
+config MMC_BCM2835_MMC
+ tristate "MMC support on BCM2835"
+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
+ help
+ This selects the MMC Interface on BCM2835.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_BCM2835_DMA
+ bool "DMA support on BCM2835 Arasan controller"
+ depends on MMC_BCM2835_MMC
+ help
+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
+ based chips.
+
+ If unsure, say N.
+
+config MMC_BCM2835_PIO_DMA_BARRIER
+ int "Block count limit for PIO transfers"
+ depends on MMC_BCM2835_MMC && MMC_BCM2835_DMA
+ range 0 256
+ default 2
+ help
+ The inclusive limit in bytes under which PIO will be used instead of DMA
+
+ If unsure, say 2 here.
+
config MMC_DEBUG
bool "MMC host drivers debugging"
depends on MMC != n
@@ -1056,6 +1085,7 @@ config MMC_SDHCI_BRCMSTB
depends on ARCH_BRCMSTB || ARCH_BCM2835 || BMIPS_GENERIC || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_CQHCI
+ select OF_DYNAMIC
default ARCH_BRCMSTB || BMIPS_GENERIC
help
This selects support for the SDIO/SD/MMC Host Controller on
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 5057fea8afb6..f0cb916d248f 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
obj-$(CONFIG_MMC_SDHCI_MILBEAUT) += sdhci-milbeaut.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_SDHCI_AM654) += sdhci_am654.o
+obj-$(CONFIG_MMC_BCM2835_MMC) += bcm2835-mmc.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_ALCOR) += alcor.o
diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c
new file mode 100644
index 000000000000..fec210b33231
--- /dev/null
+++ b/drivers/mmc/host/bcm2835-mmc.c
@@ -0,0 +1,1560 @@
+/*
+ * BCM2835 MMC host driver.
+ *
+ * Author: Gellert Weisz <[email protected]>
+ * Copyright 2014
+ *
+ * Based on
+ * sdhci-bcm2708.c by Broadcom
+ * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
+ * sdhci.c and sdhci-pci.c by Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sd.h>
+#include <linux/scatterlist.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_dma.h>
+#include <linux/swiotlb.h>
+
+#include "sdhci.h"
+
+
+#define DRIVER_NAME "mmc-bcm2835"
+
+#define DBG(f, x...) \
+pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+
+#ifndef CONFIG_MMC_BCM2835_DMA
+ #define FORCE_PIO
+#endif
+
+
+/* the inclusive limit in bytes under which PIO will be used instead of DMA */
+#ifdef CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
+#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
+#else
+#define PIO_DMA_BARRIER 00
+#endif
+
+#define MIN_FREQ 400000
+#define TIMEOUT_VAL 0xE
+#define BCM2835_SDHCI_WRITE_DELAY(f) (((2 * 1000000) / f) + 1)
+
+
+unsigned mmc_debug;
+unsigned mmc_debug2;
+
+struct bcm2835_host {
+ spinlock_t lock;
+
+ void __iomem *ioaddr;
+ u32 bus_addr;
+
+ struct mmc_host *mmc;
+
+ u32 timeout;
+
+ int clock; /* Current clock speed */
+ u8 pwr; /* Current voltage */
+
+ unsigned int max_clk; /* Max possible freq */
+ unsigned int timeout_clk; /* Timeout freq (KHz) */
+ unsigned int clk_mul; /* Clock Muliplier value */
+
+ struct tasklet_struct finish_tasklet; /* Tasklet structures */
+
+ struct timer_list timer; /* Timer for timeouts */
+
+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
+ unsigned int blocks; /* remaining PIO blocks */
+
+ int irq; /* Device IRQ */
+
+
+ u32 ier; /* cached registers */
+
+ struct mmc_request *mrq; /* Current request */
+ struct mmc_command *cmd; /* Current command */
+ struct mmc_data *data; /* Current data request */
+ unsigned int data_early:1; /* Data finished before cmd */
+
+ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
+
+ u32 shadow;
+
+ /*DMA part*/
+ struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
+ struct dma_slave_config dma_cfg_rx;
+ struct dma_slave_config dma_cfg_tx;
+ struct dma_async_tx_descriptor *tx_desc; /* descriptor */
+
+ bool have_dma;
+ bool use_dma;
+ bool wait_for_dma;
+ /*end of DMA part*/
+
+ int max_delay; /* maximum length of time spent waiting */
+
+ int flags; /* Host attributes */
+#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
+#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
+#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
+
+ u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
+ u32 max_overclock; /* Highest reported */
+};
+
+
+static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from)
+{
+ unsigned delay;
+ lockdep_assert_held_once(&host->lock);
+ writel(val, host->ioaddr + reg);
+ udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
+
+ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf);
+ if (delay && !((1<<from) & mmc_debug2))
+ udelay(delay);
+}
+
+static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
+{
+ unsigned delay;
+ lockdep_assert_held_once(&host->lock);
+ writel(val, host->ioaddr + reg);
+
+ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf);
+ if (delay)
+ udelay(delay);
+}
+
+static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
+{
+ lockdep_assert_held_once(&host->lock);
+ return readl(host->ioaddr + reg);
+}
+
+static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg)
+{
+ u32 oldval = (reg == SDHCI_COMMAND) ? host->shadow :
+ bcm2835_mmc_readl(host, reg & ~3);
+ u32 word_num = (reg >> 1) & 1;
+ u32 word_shift = word_num * 16;
+ u32 mask = 0xffff << word_shift;
+ u32 newval = (oldval & ~mask) | (val << word_shift);
+
+ if (reg == SDHCI_TRANSFER_MODE)
+ host->shadow = newval;
+ else
+ bcm2835_mmc_writel(host, newval, reg & ~3, 0);
+
+}
+
+static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg)
+{
+ u32 oldval = bcm2835_mmc_readl(host, reg & ~3);
+ u32 byte_num = reg & 3;
+ u32 byte_shift = byte_num * 8;
+ u32 mask = 0xff << byte_shift;
+ u32 newval = (oldval & ~mask) | (val << byte_shift);
+
+ bcm2835_mmc_writel(host, newval, reg & ~3, 1);
+}
+
+
+static inline u16 bcm2835_mmc_readw(struct bcm2835_host *host, int reg)
+{
+ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
+ u32 word_num = (reg >> 1) & 1;
+ u32 word_shift = word_num * 16;
+ u32 word = (val >> word_shift) & 0xffff;
+
+ return word;
+}
+
+static inline u8 bcm2835_mmc_readb(struct bcm2835_host *host, int reg)
+{
+ u32 val = bcm2835_mmc_readl(host, (reg & ~3));
+ u32 byte_num = reg & 3;
+ u32 byte_shift = byte_num * 8;
+ u32 byte = (val >> byte_shift) & 0xff;
+
+ return byte;
+}
+
+static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear)
+{
+ u32 ier;
+
+ ier = bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE);
+ ier &= ~clear;
+ /* change which requests generate IRQs - makes no difference to
+ the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
+ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2);
+}
+
+
+static void bcm2835_mmc_dumpregs(struct bcm2835_host *host)
+{
+ pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+ mmc_hostname(host->mmc));
+
+ pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
+ bcm2835_mmc_readl(host, SDHCI_DMA_ADDRESS),
+ bcm2835_mmc_readw(host, SDHCI_HOST_VERSION));
+ pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
+ bcm2835_mmc_readw(host, SDHCI_BLOCK_SIZE),
+ bcm2835_mmc_readw(host, SDHCI_BLOCK_COUNT));
+ pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+ bcm2835_mmc_readl(host, SDHCI_ARGUMENT),
+ bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE));
+ pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
+ bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE),
+ bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL));
+ pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
+ bcm2835_mmc_readb(host, SDHCI_POWER_CONTROL),
+ bcm2835_mmc_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+ pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
+ bcm2835_mmc_readb(host, SDHCI_WAKE_UP_CONTROL),
+ bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL));
+ pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
+ bcm2835_mmc_readb(host, SDHCI_TIMEOUT_CONTROL),
+ bcm2835_mmc_readl(host, SDHCI_INT_STATUS));
+ pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+ bcm2835_mmc_readl(host, SDHCI_INT_ENABLE),
+ bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE));
+ pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+ bcm2835_mmc_readw(host, SDHCI_AUTO_CMD_STATUS),
+ bcm2835_mmc_readw(host, SDHCI_SLOT_INT_STATUS));
+ pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
+ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES),
+ bcm2835_mmc_readl(host, SDHCI_CAPABILITIES_1));
+ pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
+ bcm2835_mmc_readw(host, SDHCI_COMMAND),
+ bcm2835_mmc_readl(host, SDHCI_MAX_CURRENT));
+ pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
+ bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2));
+
+ pr_debug(DRIVER_NAME ": ===========================================\n");
+}
+
+
+static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
+{
+ unsigned long timeout;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+
+ if (mask & SDHCI_RESET_ALL)
+ host->clock = 0;
+
+ /* Wait max 100 ms */
+ timeout = 100;
+
+ /* hw clears the bit when it's done */
+ while (bcm2835_mmc_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
+ if (timeout == 0) {
+ pr_err("%s: Reset 0x%x never completed.\n",
+ mmc_hostname(host->mmc), (int)mask);
+ bcm2835_mmc_dumpregs(host);
+ return;
+ }
+ timeout--;
+ spin_unlock_irqrestore(&host->lock, flags);
+ mdelay(1);
+ spin_lock_irqsave(&host->lock, flags);
+ }
+
+ if (100-timeout > 10 && 100-timeout > host->max_delay) {
+ host->max_delay = 100-timeout;
+ pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
+{
+ unsigned long flags;
+ if (soft)
+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+ else
+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+ SDHCI_INT_RESPONSE;
+
+ spin_lock_irqsave(&host->lock, flags);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (soft) {
+ /* force clock reconfiguration */
+ host->clock = 0;
+ bcm2835_mmc_set_ios(host->mmc, &host->mmc->ios);
+ }
+}
+
+
+
+static void bcm2835_mmc_finish_data(struct bcm2835_host *host);
+
+static void bcm2835_mmc_dma_complete(void *param)
+{
+ struct bcm2835_host *host = param;
+ struct dma_chan *dma_chan;
+ unsigned long flags;
+ u32 dir_data;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->use_dma = false;
+
+ if (host->data) {
+ dma_chan = host->dma_chan_rxtx;
+ if (host->data->flags & MMC_DATA_WRITE)
+ dir_data = DMA_TO_DEVICE;
+ else
+ dir_data = DMA_FROM_DEVICE;
+ dma_unmap_sg(dma_chan->device->dev,
+ host->data->sg, host->data->sg_len,
+ dir_data);
+ if (! (host->data->flags & MMC_DATA_WRITE))
+ bcm2835_mmc_finish_data(host);
+ } else if (host->wait_for_dma) {
+ host->wait_for_dma = false;
+ tasklet_schedule(&host->finish_tasklet);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_bcm2835_mmc_read_block_pio(struct bcm2835_host *host)
+{
+ unsigned long flags;
+ size_t blksize, len, chunk;
+
+ u32 scratch = 0;
+ u8 *buf;
+
+ blksize = host->data->blksz;
+ chunk = 0;
+
+ local_irq_save(flags);
+
+ while (blksize) {
+ if (!sg_miter_next(&host->sg_miter))
+ BUG();
+
+ len = min(host->sg_miter.length, blksize);
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = host->sg_miter.addr;
+
+ while (len) {
+ if (chunk == 0) {
+ scratch = bcm2835_mmc_readl(host, SDHCI_BUFFER);
+ chunk = 4;
+ }
+
+ *buf = scratch & 0xFF;
+
+ buf++;
+ scratch >>= 8;
+ chunk--;
+ len--;
+ }
+ }
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
+}
+
+static void bcm2835_bcm2835_mmc_write_block_pio(struct bcm2835_host *host)
+{
+ unsigned long flags;
+ size_t blksize, len, chunk;
+ u32 scratch;
+ u8 *buf;
+
+ blksize = host->data->blksz;
+ chunk = 0;
+ chunk = 0;
+ scratch = 0;
+
+ local_irq_save(flags);
+
+ while (blksize) {
+ if (!sg_miter_next(&host->sg_miter))
+ BUG();
+
+ len = min(host->sg_miter.length, blksize);
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = host->sg_miter.addr;
+
+ while (len) {
+ scratch |= (u32)*buf << (chunk * 8);
+
+ buf++;
+ chunk++;
+ len--;
+
+ if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
+ mmc_raw_writel(host, scratch, SDHCI_BUFFER);
+ chunk = 0;
+ scratch = 0;
+ }
+ }
+ }
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
+}
+
+
+static void bcm2835_mmc_transfer_pio(struct bcm2835_host *host)
+{
+ u32 mask;
+
+ BUG_ON(!host->data);
+
+ if (host->blocks == 0)
+ return;
+
+ if (host->data->flags & MMC_DATA_READ)
+ mask = SDHCI_DATA_AVAILABLE;
+ else
+ mask = SDHCI_SPACE_AVAILABLE;
+
+ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
+
+ if (host->data->flags & MMC_DATA_READ)
+ bcm2835_bcm2835_mmc_read_block_pio(host);
+ else
+ bcm2835_bcm2835_mmc_write_block_pio(host);
+
+ host->blocks--;
+
+ /* QUIRK used in sdhci.c removes the 'if' */
+ /* but it seems this is unnecessary */
+ if (host->blocks == 0)
+ break;
+
+
+ }
+}
+
+
+static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
+{
+ u32 len, dir_data, dir_slave;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *dma_chan;
+
+
+ WARN_ON(!host->data);
+
+ if (!host->data)
+ return;
+
+ if (host->blocks == 0)
+ return;
+
+ dma_chan = host->dma_chan_rxtx;
+ if (host->data->flags & MMC_DATA_READ) {
+ dir_data = DMA_FROM_DEVICE;
+ dir_slave = DMA_DEV_TO_MEM;
+ } else {
+ dir_data = DMA_TO_DEVICE;
+ dir_slave = DMA_MEM_TO_DEV;
+ }
+
+ /* The parameters have already been validated, so this will not fail */
+ (void)dmaengine_slave_config(dma_chan,
+ (dir_data == DMA_FROM_DEVICE) ?
+ &host->dma_cfg_rx :
+ &host->dma_cfg_tx);
+
+ BUG_ON(!dma_chan->device);
+ BUG_ON(!dma_chan->device->dev);
+ BUG_ON(!host->data->sg);
+
+ len = dma_map_sg(dma_chan->device->dev, host->data->sg,
+ host->data->sg_len, dir_data);
+ if (len > 0) {
+ desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
+ len, dir_slave,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ } else {
+ dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
+ }
+ if (desc) {
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+ bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
+ SDHCI_INT_SPACE_AVAIL);
+ host->tx_desc = desc;
+ desc->callback = bcm2835_mmc_dma_complete;
+ desc->callback_param = host;
+ spin_unlock_irqrestore(&host->lock, flags);
+ dmaengine_submit(desc);
+ dma_async_issue_pending(dma_chan);
+ } else {
+ dma_unmap_sg(dma_chan->device->dev, host->data->sg, len, dir_data);
+ }
+
+}
+
+
+
+static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host)
+{
+ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
+ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
+
+ if (host->use_dma)
+ host->ier = (host->ier & ~pio_irqs) | dma_irqs;
+ else
+ host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4);
+}
+
+
+static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
+{
+ u8 count;
+ struct mmc_data *data = cmd->data;
+
+ WARN_ON(host->data);
+
+ if (data || (cmd->flags & MMC_RSP_BUSY)) {
+ count = TIMEOUT_VAL;
+ bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+ }
+
+ if (!data)
+ return;
+
+ /* Sanity checks */
+ BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
+ BUG_ON(data->blocks > 65535);
+
+ host->data = data;
+ host->data_early = 0;
+ host->data->bytes_xfered = 0;
+
+
+ if (!(host->flags & SDHCI_REQ_USE_DMA)) {
+ int flags;
+
+ flags = SG_MITER_ATOMIC;
+ if (host->data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+ host->blocks = data->blocks;
+ }
+
+ host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER;
+
+ bcm2835_mmc_set_transfer_irqs(host);
+
+ /* Set the DMA boundary value and block size */
+ bcm2835_mmc_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+ data->blksz), SDHCI_BLOCK_SIZE);
+ bcm2835_mmc_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+ BUG_ON(!host->data);
+}
+
+static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host,
+ struct mmc_command *cmd)
+{
+ u16 mode;
+ struct mmc_data *data = cmd->data;
+
+ if (data == NULL) {
+ /* clear Auto CMD settings for no data CMDs */
+ mode = bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE);
+ bcm2835_mmc_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
+ SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
+ return;
+ }
+
+ WARN_ON(!host->data);
+
+ mode = SDHCI_TRNS_BLK_CNT_EN;
+
+ if ((mmc_op_multi(cmd->opcode) || data->blocks > 1)) {
+ mode |= SDHCI_TRNS_MULTI;
+
+ /*
+ * If we are sending CMD23, CMD12 never gets sent
+ * on successful completion (so no Auto-CMD12).
+ */
+ if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+ mode |= SDHCI_TRNS_AUTO_CMD12;
+ else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+ mode |= SDHCI_TRNS_AUTO_CMD23;
+ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5);
+ }
+ }
+
+ if (data->flags & MMC_DATA_READ)
+ mode |= SDHCI_TRNS_READ;
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ mode |= SDHCI_TRNS_DMA;
+
+ bcm2835_mmc_writew(host, mode, SDHCI_TRANSFER_MODE);
+}
+
+static void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
+{
+ int flags;
+ u32 mask;
+ unsigned long timeout;
+
+ WARN_ON(host->cmd);
+
+ /* Wait max 10 ms */
+ timeout = 1000;
+
+ mask = SDHCI_CMD_INHIBIT;
+ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+ mask |= SDHCI_DATA_INHIBIT;
+
+ /* We shouldn't wait for data inihibit for stop commands, even
+ though they might use busy signaling */
+ if (host->mrq->data && (cmd == host->mrq->data->stop))
+ mask &= ~SDHCI_DATA_INHIBIT;
+
+ while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
+ if (timeout == 0) {
+ pr_err("%s: Controller never released inhibit bit(s).\n",
+ mmc_hostname(host->mmc));
+ bcm2835_mmc_dumpregs(host);
+ cmd->error = -EIO;
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+ }
+ timeout--;
+ udelay(10);
+ }
+
+ if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
+ host->max_delay = (1000-timeout)/100;
+ pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+ }
+
+ timeout = jiffies;
+ if (!cmd->data && cmd->busy_timeout > 9000)
+ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+ else
+ timeout += 10 * HZ;
+ mod_timer(&host->timer, timeout);
+
+ host->cmd = cmd;
+ host->use_dma = false;
+
+ bcm2835_mmc_prepare_data(host, cmd);
+
+ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6);
+
+ bcm2835_mmc_set_transfer_mode(host, cmd);
+
+ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+ pr_err("%s: Unsupported response type!\n",
+ mmc_hostname(host->mmc));
+ cmd->error = -EINVAL;
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+ }
+
+ if (!(cmd->flags & MMC_RSP_PRESENT))
+ flags = SDHCI_CMD_RESP_NONE;
+ else if (cmd->flags & MMC_RSP_136)
+ flags = SDHCI_CMD_RESP_LONG;
+ else if (cmd->flags & MMC_RSP_BUSY)
+ flags = SDHCI_CMD_RESP_SHORT_BUSY;
+ else
+ flags = SDHCI_CMD_RESP_SHORT;
+
+ if (cmd->flags & MMC_RSP_CRC)
+ flags |= SDHCI_CMD_CRC;
+ if (cmd->flags & MMC_RSP_OPCODE)
+ flags |= SDHCI_CMD_INDEX;
+
+ if (cmd->data)
+ flags |= SDHCI_CMD_DATA;
+
+ bcm2835_mmc_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
+}
+
+
+static void bcm2835_mmc_finish_data(struct bcm2835_host *host)
+{
+ struct mmc_data *data;
+
+ BUG_ON(!host->data);
+
+ data = host->data;
+ host->data = NULL;
+
+ if (data->error)
+ data->bytes_xfered = 0;
+ else
+ data->bytes_xfered = data->blksz * data->blocks;
+
+ /*
+ * Need to send CMD12 if -
+ * a) open-ended multiblock transfer (no CMD23)
+ * b) error in multiblock transfer
+ */
+ if (data->stop &&
+ (data->error ||
+ !host->mrq->sbc)) {
+
+ /*
+ * The controller needs a reset of internal state machines
+ * upon error conditions.
+ */
+ if (data->error) {
+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
+ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
+ }
+
+ bcm2835_mmc_send_command(host, data->stop);
+ } else if (host->use_dma) {
+ host->wait_for_dma = true;
+ } else {
+ tasklet_schedule(&host->finish_tasklet);
+ }
+}
+
+static void bcm2835_mmc_finish_command(struct bcm2835_host *host)
+{
+ int i;
+
+ BUG_ON(host->cmd == NULL);
+
+ if (host->cmd->flags & MMC_RSP_PRESENT) {
+ if (host->cmd->flags & MMC_RSP_136) {
+ /* CRC is stripped so we need to do some shifting. */
+ for (i = 0; i < 4; i++) {
+ host->cmd->resp[i] = bcm2835_mmc_readl(host,
+ SDHCI_RESPONSE + (3-i)*4) << 8;
+ if (i != 3)
+ host->cmd->resp[i] |=
+ bcm2835_mmc_readb(host,
+ SDHCI_RESPONSE + (3-i)*4-1);
+ }
+ } else {
+ host->cmd->resp[0] = bcm2835_mmc_readl(host, SDHCI_RESPONSE);
+ }
+ }
+
+ host->cmd->error = 0;
+
+ /* Finished CMD23, now send actual command. */
+ if (host->cmd == host->mrq->sbc) {
+ host->cmd = NULL;
+ bcm2835_mmc_send_command(host, host->mrq->cmd);
+
+ if (host->mrq->cmd->data && host->use_dma) {
+ /* DMA transfer starts now, PIO starts after interrupt */
+ bcm2835_mmc_transfer_dma(host);
+ }
+ } else {
+
+ /* Processed actual command. */
+ if (host->data && host->data_early)
+ bcm2835_mmc_finish_data(host);
+
+ if (!host->cmd->data)
+ tasklet_schedule(&host->finish_tasklet);
+
+ host->cmd = NULL;
+ }
+}
+
+
+static void bcm2835_mmc_timeout_timer(struct timer_list *t)
+{
+ struct bcm2835_host *host = timer_container_of(host, t, timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->mrq) {
+ pr_err("%s: Timeout waiting for hardware interrupt.\n",
+ mmc_hostname(host->mmc));
+ bcm2835_mmc_dumpregs(host);
+
+ if (host->data) {
+ host->data->error = -ETIMEDOUT;
+ bcm2835_mmc_finish_data(host);
+ } else {
+ if (host->cmd)
+ host->cmd->error = -ETIMEDOUT;
+ else
+ host->mrq->cmd->error = -ETIMEDOUT;
+
+ tasklet_schedule(&host->finish_tasklet);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+
+static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
+{
+ if (!(host->flags & SDHCI_DEVICE_DEAD)) {
+ if (enable)
+ host->ier |= SDHCI_INT_CARD_INT;
+ else
+ host->ier &= ~SDHCI_INT_CARD_INT;
+
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7);
+ }
+}
+
+static void bcm2835_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct bcm2835_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (enable)
+ host->flags |= SDHCI_SDIO_IRQ_ENABLED;
+ else
+ host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
+
+ bcm2835_mmc_enable_sdio_irq_nolock(host, enable);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_mmc_cmd_irq(struct bcm2835_host *host, u32 intmask)
+{
+
+ BUG_ON(intmask == 0);
+
+ if (!host->cmd) {
+ pr_err("%s: Got command interrupt 0x%08x even "
+ "though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ bcm2835_mmc_dumpregs(host);
+ return;
+ }
+
+ if (intmask & SDHCI_INT_TIMEOUT)
+ host->cmd->error = -ETIMEDOUT;
+ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+ SDHCI_INT_INDEX)) {
+ host->cmd->error = -EILSEQ;
+ }
+
+ if (host->cmd->error) {
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+ }
+
+ if (intmask & SDHCI_INT_RESPONSE)
+ bcm2835_mmc_finish_command(host);
+
+}
+
+static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask)
+{
+ struct dma_chan *dma_chan;
+ u32 dir_data;
+
+ BUG_ON(intmask == 0);
+
+ if (!host->data) {
+ /*
+ * The "data complete" interrupt is also used to
+ * indicate that a busy state has ended. See comment
+ * above in sdhci_cmd_irq().
+ */
+ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+ if (intmask & SDHCI_INT_DATA_END) {
+ bcm2835_mmc_finish_command(host);
+ return;
+ }
+ }
+
+ pr_debug("%s: Got data interrupt 0x%08x even "
+ "though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ bcm2835_mmc_dumpregs(host);
+
+ return;
+ }
+
+ if (intmask & SDHCI_INT_DATA_TIMEOUT)
+ host->data->error = -ETIMEDOUT;
+ else if (intmask & SDHCI_INT_DATA_END_BIT)
+ host->data->error = -EILSEQ;
+ else if ((intmask & SDHCI_INT_DATA_CRC) &&
+ SDHCI_GET_CMD(bcm2835_mmc_readw(host, SDHCI_COMMAND))
+ != MMC_BUS_TEST_R)
+ host->data->error = -EILSEQ;
+
+ if (host->use_dma) {
+ if (host->data->flags & MMC_DATA_WRITE) {
+ /* IRQ handled here */
+
+ dma_chan = host->dma_chan_rxtx;
+ dir_data = DMA_TO_DEVICE;
+ dma_unmap_sg(dma_chan->device->dev,
+ host->data->sg, host->data->sg_len,
+ dir_data);
+
+ bcm2835_mmc_finish_data(host);
+ }
+
+ } else {
+ if (host->data->error)
+ bcm2835_mmc_finish_data(host);
+ else {
+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
+ bcm2835_mmc_transfer_pio(host);
+
+ if (intmask & SDHCI_INT_DATA_END) {
+ if (host->cmd) {
+ /*
+ * Data managed to finish before the
+ * command completed. Make sure we do
+ * things in the proper order.
+ */
+ host->data_early = 1;
+ } else {
+ bcm2835_mmc_finish_data(host);
+ }
+ }
+ }
+ }
+}
+
+
+static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
+{
+ irqreturn_t result = IRQ_NONE;
+ struct bcm2835_host *host = dev_id;
+ u32 intmask, mask, unexpected = 0;
+ int max_loops = 16;
+
+ spin_lock(&host->lock);
+
+ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+
+ if (!intmask || intmask == 0xffffffff) {
+ result = IRQ_NONE;
+ goto out;
+ }
+
+ do {
+ /* Clear selected interrupts. */
+ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_BUS_POWER);
+ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8);
+
+
+ if (intmask & SDHCI_INT_CMD_MASK)
+ bcm2835_mmc_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+
+ if (intmask & SDHCI_INT_DATA_MASK)
+ bcm2835_mmc_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+
+ if (intmask & SDHCI_INT_BUS_POWER)
+ pr_err("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
+
+ if (intmask & SDHCI_INT_CARD_INT) {
+ bcm2835_mmc_enable_sdio_irq_nolock(host, false);
+ sdio_signal_irq(host->mmc);
+ }
+
+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+ SDHCI_INT_CARD_INT);
+
+ if (intmask) {
+ unexpected |= intmask;
+ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9);
+ }
+
+ if (result == IRQ_NONE)
+ result = IRQ_HANDLED;
+
+ intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+ } while (intmask && --max_loops);
+out:
+ spin_unlock(&host->lock);
+
+ if (unexpected) {
+ pr_err("%s: Unexpected interrupt 0x%08x.\n",
+ mmc_hostname(host->mmc), unexpected);
+ bcm2835_mmc_dumpregs(host);
+ }
+
+ return result;
+}
+
+
+static void bcm2835_mmc_ack_sdio_irq(struct mmc_host *mmc)
+{
+ struct bcm2835_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+ bcm2835_mmc_enable_sdio_irq_nolock(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock)
+{
+ int div = 0; /* Initialized for compiler warning */
+ int real_div = div, clk_mul = 1;
+ u16 clk = 0;
+ unsigned long timeout;
+ unsigned int input_clock = clock;
+
+ if (host->overclock_50 && (clock == 50000000))
+ clock = host->overclock_50 * 1000000 + 999999;
+
+ host->mmc->actual_clock = 0;
+
+ bcm2835_mmc_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ if (clock == 0)
+ return;
+
+ /* Version 3.00 divisors must be a multiple of 2. */
+ if (host->max_clk <= clock)
+ div = 1;
+ else {
+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+ div += 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ }
+
+ real_div = div;
+ div >>= 1;
+
+ if (real_div)
+ clock = (host->max_clk * clk_mul) / real_div;
+ host->mmc->actual_clock = clock;
+
+ if ((clock > input_clock) && (clock > host->max_overclock)) {
+ pr_warn("%s: Overclocking to %dHz\n",
+ mmc_hostname(host->mmc), clock);
+ host->max_overclock = clock;
+ }
+
+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+ << SDHCI_DIVIDER_HI_SHIFT;
+ clk |= SDHCI_CLOCK_INT_EN;
+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 20 ms */
+ timeout = 20;
+ while (!((clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never "
+ "stabilised.\n", mmc_hostname(host->mmc));
+ bcm2835_mmc_dumpregs(host);
+ return;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ if (20-timeout > 10 && 20-timeout > host->max_delay) {
+ host->max_delay = 20-timeout;
+ pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+ }
+
+ clk |= SDHCI_CLOCK_CARD_EN;
+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void bcm2835_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct bcm2835_host *host;
+ unsigned long flags;
+
+ host = mmc_priv(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+
+ host->mrq = mrq;
+
+ if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+ bcm2835_mmc_send_command(host, mrq->sbc);
+ else
+ bcm2835_mmc_send_command(host, mrq->cmd);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (!(mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) && mrq->cmd->data && host->use_dma) {
+ /* DMA transfer starts now, PIO starts after interrupt */
+ bcm2835_mmc_transfer_dma(host);
+ }
+}
+
+
+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+ struct bcm2835_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ u8 ctrl;
+ u16 clk, ctrl_2;
+
+ pr_debug("bcm2835_mmc_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n",
+ ios->clock, ios->power_mode, ios->bus_width,
+ ios->timing, ios->signal_voltage, ios->drv_type);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (!ios->clock || ios->clock != host->clock) {
+ bcm2835_mmc_set_clock(host, ios->clock);
+ host->clock = ios->clock;
+ }
+
+ if (host->pwr != SDHCI_POWER_330) {
+ host->pwr = SDHCI_POWER_330;
+ bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+ }
+
+ ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL);
+
+ /* set bus width */
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+
+ ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */
+
+
+ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ /*
+ * We only need to set Driver Strength if the
+ * preset value enable is not set.
+ */
+ ctrl_2 = bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+ if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+
+ bcm2835_mmc_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ /* Reset SD Clock Enable */
+ clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Re-enable SD Clock */
+ bcm2835_mmc_set_clock(host, host->clock);
+ bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+
+static struct mmc_host_ops bcm2835_ops = {
+ .request = bcm2835_mmc_request,
+ .set_ios = bcm2835_mmc_set_ios,
+ .enable_sdio_irq = bcm2835_mmc_enable_sdio_irq,
+ .ack_sdio_irq = bcm2835_mmc_ack_sdio_irq,
+};
+
+
+static void bcm2835_mmc_tasklet_finish(unsigned long param)
+{
+ struct bcm2835_host *host;
+ unsigned long flags;
+ struct mmc_request *mrq;
+
+ host = (struct bcm2835_host *)param;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * If this tasklet gets rescheduled while running, it will
+ * be run again afterwards but without any active request.
+ */
+ if (!host->mrq) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ timer_delete(&host->timer);
+
+ mrq = host->mrq;
+
+ /*
+ * The controller needs a reset of internal state machines
+ * upon error conditions.
+ */
+ if (!(host->flags & SDHCI_DEVICE_DEAD) &&
+ ((mrq->cmd && mrq->cmd->error) ||
+ (mrq->data && (mrq->data->error ||
+ (mrq->data->stop && mrq->data->stop->error))))) {
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
+ bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
+ spin_lock_irqsave(&host->lock, flags);
+ }
+
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ mmc_request_done(host->mmc, mrq);
+}
+
+
+
+static int bcm2835_mmc_add_host(struct bcm2835_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct device *dev = mmc->parent;
+#ifndef FORCE_PIO
+ struct dma_slave_config cfg;
+#endif
+ int ret;
+
+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+ host->clk_mul = 0;
+
+ if (!mmc->f_max || mmc->f_max > host->max_clk)
+ mmc->f_max = host->max_clk;
+ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+
+ /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */
+ host->timeout_clk = mmc->f_max / 1000;
+ mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
+
+ /* host controller capabilities */
+ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_NEEDS_POLL |
+ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_MMC_HIGHSPEED;
+
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
+ host->flags = SDHCI_AUTO_CMD23;
+
+ dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2);
+#ifdef FORCE_PIO
+ dev_info(dev, "Forcing PIO mode\n");
+ host->have_dma = false;
+#else
+ if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
+ dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
+ DRIVER_NAME);
+ host->have_dma = false;
+ } else {
+ dev_info(dev, "DMA channel allocated");
+
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ /* Validate the slave configurations */
+
+ cfg.direction = DMA_MEM_TO_DEV;
+ cfg.src_addr = 0;
+ cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
+
+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+
+ if (ret == 0) {
+ host->dma_cfg_tx = cfg;
+
+ cfg.direction = DMA_DEV_TO_MEM;
+ cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
+ cfg.dst_addr = 0;
+
+ ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+ }
+
+ if (ret == 0) {
+ host->dma_cfg_rx = cfg;
+
+ host->have_dma = true;
+ } else {
+ pr_err("%s: unable to configure DMA channel. "
+ "Falling back to PIO\n",
+ mmc_hostname(mmc));
+ dma_release_channel(host->dma_chan_rxtx);
+ host->dma_chan_rxtx = NULL;
+ host->have_dma = false;
+ }
+ }
+#endif
+ mmc->max_segs = 128;
+ mmc->max_req_size = min_t(size_t, 524288, dma_max_mapping_size(dev));
+ mmc->max_seg_size = mmc->max_req_size;
+ mmc->max_blk_size = 512;
+ mmc->max_blk_count = 65535;
+
+ /* report supported voltage ranges */
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ tasklet_init(&host->finish_tasklet,
+ bcm2835_mmc_tasklet_finish, (unsigned long)host);
+
+ timer_setup(&host->timer, bcm2835_mmc_timeout_timer, 0);
+ init_waitqueue_head(&host->buf_ready_int);
+
+ bcm2835_mmc_init(host, 0);
+ ret = request_irq(host->irq, bcm2835_mmc_irq, IRQF_SHARED,
+ mmc_hostname(mmc), host);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
+ goto untasklet;
+ }
+
+ ret = mmc_add_host(mmc);
+ if (ret) {
+ dev_err(dev, "could not add MMC host\n");
+ goto free_irq;
+ }
+
+ return 0;
+
+free_irq:
+ free_irq(host->irq, host);
+untasklet:
+ tasklet_kill(&host->finish_tasklet);
+
+ return ret;
+}
+
+static int bcm2835_mmc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct clk *clk;
+ struct resource *iomem;
+ struct bcm2835_host *host;
+ struct mmc_host *mmc;
+ int ret;
+
+ mmc = mmc_alloc_host(sizeof(*host), dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ mmc->ops = &bcm2835_ops;
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->timeout = msecs_to_jiffies(1000);
+ spin_lock_init(&host->lock);
+
+ host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &iomem);
+ if (IS_ERR(host->ioaddr)) {
+ ret = PTR_ERR(host->ioaddr);
+ goto err;
+ }
+
+ host->bus_addr = iomem->start;
+
+#ifndef FORCE_PIO
+ if (node) {
+ host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
+ if (!host->dma_chan_rxtx)
+ host->dma_chan_rxtx =
+ dma_request_slave_channel(dev, "tx");
+ if (!host->dma_chan_rxtx)
+ host->dma_chan_rxtx =
+ dma_request_slave_channel(dev, "rx");
+ } else {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ /* we don't care about the channel, any would work */
+ dma_cap_set(DMA_SLAVE, mask);
+ host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
+ }
+#endif
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ if (ret == -EPROBE_DEFER)
+ dev_info(dev, "could not get clk, deferring probe\n");
+ else
+ dev_err(dev, "could not get clk\n");
+ goto err;
+ }
+
+ host->max_clk = clk_get_rate(clk);
+
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq <= 0) {
+ dev_err(dev, "get IRQ failed\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (node) {
+ ret = mmc_of_parse(mmc);
+ if (ret)
+ goto err;
+
+ /* Read any custom properties */
+ of_property_read_u32(node,
+ "brcm,overclock-50",
+ &host->overclock_50);
+ } else {
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ }
+
+ ret = bcm2835_mmc_add_host(host);
+ if (ret)
+ goto err;
+
+ platform_set_drvdata(pdev, host);
+
+ return 0;
+err:
+ if (host->dma_chan_rxtx)
+ dma_release_channel(host->dma_chan_rxtx);
+ mmc_free_host(mmc);
+
+ return ret;
+}
+
+static void bcm2835_mmc_remove(struct platform_device *pdev)
+{
+ struct bcm2835_host *host = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int dead;
+ u32 scratch;
+
+ dead = 0;
+ scratch = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+ if (scratch == (u32)-1)
+ dead = 1;
+
+
+ if (dead) {
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->flags |= SDHCI_DEVICE_DEAD;
+
+ if (host->mrq) {
+ pr_err("%s: Controller removed during "
+ " transfer!\n", mmc_hostname(host->mmc));
+
+ host->mrq->cmd->error = -ENOMEDIUM;
+ tasklet_schedule(&host->finish_tasklet);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ mmc_remove_host(host->mmc);
+
+ if (!dead)
+ bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+ free_irq(host->irq, host);
+
+ timer_delete_sync(&host->timer);
+
+ tasklet_kill(&host->finish_tasklet);
+
+ if (host->dma_chan_rxtx)
+ dma_release_channel(host->dma_chan_rxtx);
+
+ mmc_free_host(host->mmc);
+}
+
+
+static const struct of_device_id bcm2835_mmc_match[] = {
+ { .compatible = "brcm,bcm2835-mmc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bcm2835_mmc_match);
+
+
+
+static struct platform_driver bcm2835_mmc_driver = {
+ .probe = bcm2835_mmc_probe,
+ .remove = bcm2835_mmc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_mmc_match,
+ },
+};
+module_platform_driver(bcm2835_mmc_driver);
+
+module_param(mmc_debug, uint, 0644);
+module_param(mmc_debug2, uint, 0644);
+MODULE_ALIAS("platform:mmc-bcm2835");
+MODULE_DESCRIPTION("BCM2835 SDHCI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gellert Weisz");
diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c
index ee63835b3ca0..bae88c3b45b5 100644
--- a/drivers/mmc/host/bcm2835.c
+++ b/drivers/mmc/host/bcm2835.c
@@ -38,7 +38,6 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
@@ -1367,8 +1366,8 @@ static int bcm2835_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm2835_host *host;
+ struct resource *iomem;
struct mmc_host *mmc;
- const __be32 *regaddr_p;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -1381,23 +1380,13 @@ static int bcm2835_probe(struct platform_device *pdev)
host->pdev = pdev;
spin_lock_init(&host->lock);
- host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
+ host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &iomem);
if (IS_ERR(host->ioaddr)) {
ret = PTR_ERR(host->ioaddr);
goto err;
}
- /* Parse OF address directly to get the physical address for
- * DMA to our registers.
- */
- regaddr_p = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
- if (!regaddr_p) {
- dev_err(dev, "Can't get phys address\n");
- ret = -EINVAL;
- goto err;
- }
-
- host->phys_addr = be32_to_cpup(regaddr_p);
+ host->phys_addr = iomem->start;
host->dma_chan = NULL;
host->dma_desc = NULL;
diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c
index 178277d90c31..78e80bc574eb 100644
--- a/drivers/mmc/host/cqhci-core.c
+++ b/drivers/mmc/host/cqhci-core.c
@@ -388,9 +388,11 @@ static void cqhci_off(struct mmc_host *mmc)
err = readx_poll_timeout(cqhci_read_ctl, cq_host, reg,
reg & CQHCI_HALT, 0, CQHCI_OFF_TIMEOUT);
- if (err < 0)
+ if (err < 0) {
pr_err("%s: cqhci: CQE stuck on\n", mmc_hostname(mmc));
- else
+ /* eMMC v5.1 B.2.8 recommends writing 0 to CQHCI_CTL if stuck */
+ cqhci_writel(cq_host, 0, CQHCI_CTL);
+ } else
pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc));
if (cq_host->ops->post_disable)
@@ -980,8 +982,11 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout)
ret = cqhci_halted(cq_host);
- if (!ret)
+ if (!ret) {
pr_warn("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
+ /* eMMC v5.1 B.2.8 recommends writing 0 to CQHCI_CTL if stuck */
+ cqhci_writel(cq_host, 0, CQHCI_CTL);
+ }
return ret;
}
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index efc2f3bdc631..721e40d5a959 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
@@ -28,29 +30,38 @@
#define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0)
#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1)
+#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS BIT(2)
#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200
#define SDIO_CFG_CQ_CAPABILITY 0x4c
-#define SDIO_CFG_CQ_CAPABILITY_FMUL GENMASK(13, 12)
+#define SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT 12
#define SDIO_CFG_CTRL 0x0
#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31)
#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30)
+#define SDIO_CFG_SD_PIN_SEL 0x44
+#define SDIO_CFG_SD_PIN_SEL_MASK 0x3
+#define SDIO_CFG_SD_PIN_SEL_SD BIT(1)
+#define SDIO_CFG_SD_PIN_SEL_MMC BIT(0)
+
#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac
#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31)
#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0)
-#define MMC_CAP_HSE_MASK (MMC_CAP2_HSX00_1_2V | MMC_CAP2_HSX00_1_8V)
-/* Select all SD UHS type I SDR speed above 50MB/s */
-#define MMC_CAP_UHS_I_SDR_MASK (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104)
-
struct sdhci_brcmstb_priv {
void __iomem *cfg_regs;
unsigned int flags;
struct clk *base_clk;
u32 base_freq_hz;
+ struct regulator *sde_1v8;
+ struct device_node *sde_pcie;
+ void *__iomem sde_ioaddr;
+ void *__iomem sde_ioaddr2;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sdex;
};
struct brcmstb_match_priv {
@@ -141,6 +152,42 @@ static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
writel(reg, host->ioaddr + SDHCI_VENDOR);
}
+static void sdhci_bcm2712_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ u16 clk;
+ u32 reg;
+ bool is_emmc_rate = false;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
+
+ host->mmc->actual_clock = 0;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ switch (host->mmc->ios.timing) {
+ case MMC_TIMING_MMC_HS400:
+ case MMC_TIMING_MMC_HS200:
+ case MMC_TIMING_MMC_DDR52:
+ case MMC_TIMING_MMC_HS:
+ is_emmc_rate = true;
+ break;
+ }
+
+ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
+ reg &= ~SDIO_CFG_SD_PIN_SEL_MASK;
+ if (is_emmc_rate)
+ reg |= SDIO_CFG_SD_PIN_SEL_MMC;
+ else
+ reg |= SDIO_CFG_SD_PIN_SEL_SD;
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
+
+ if (clock == 0)
+ return;
+
+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ sdhci_enable_clk(host, clk);
+}
+
static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
@@ -156,6 +203,17 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_enable_clk(host, clk);
}
+static void sdhci_brcmstb_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ }
+ sdhci_set_power_noreg(host, mode, vdd);
+}
+
static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
@@ -185,21 +243,41 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
+static void sdhci_bcm2712_hs400_downgrade(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ /*
+ * The eMMC PHY and its internal controller parses and validates
+ * the uhs_mode, divisor, pin_sel, and sampling clock select
+ * output from the SD controller. It will refuse to update its
+ * config if HS timings are selected while the clock is >52MHz.
+ * so bump the clock down now before card/controller setup is
+ * performed.
+ */
+ sdhci_bcm2712_set_clock(host, 52000000);
+}
+
static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
u32 reg;
+ u32 uhs_mask = (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104);
+ u32 hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR |
+ MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V);
+ u32 base_clk_mhz;
/*
* If we support a speed that requires tuning,
* then select the delay line PHY as the clock source.
*/
- if ((host->mmc->caps & MMC_CAP_UHS_I_SDR_MASK) || (host->mmc->caps2 & MMC_CAP_HSE_MASK)) {
+ if ((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) {
reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE;
reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE;
writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
+
+ host->mmc_host_ops.hs400_downgrade = sdhci_bcm2712_hs400_downgrade;
}
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
@@ -210,6 +288,109 @@ static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN;
writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
}
+
+ /* Guesstimate the timer frequency (controller base clock) */
+ base_clk_mhz = max_t(u32, clk_get_rate(pltfm_host->clk) / (1000 * 1000), 1);
+ reg = (3 << SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT) | base_clk_mhz;
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CQ_CAPABILITY);
+}
+
+static int bcm2712_init_sd_express(struct sdhci_host *host, struct mmc_ios *ios)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
+ struct device *dev = host->mmc->parent;
+ u32 ctrl_val;
+ u32 present_state;
+ int ret;
+
+ if (!brcmstb_priv->sde_ioaddr || !brcmstb_priv->sde_ioaddr2)
+ return -EINVAL;
+
+ if (!brcmstb_priv->pinctrl)
+ return -EINVAL;
+
+ /* Turn off the SD clock first */
+ sdhci_set_clock(host, 0);
+
+ /* Disable SD DAT0-3 pulls */
+ pinctrl_select_state(brcmstb_priv->pinctrl, brcmstb_priv->pins_sdex);
+
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1 %08x\n", ctrl_val);
+
+ /* Tri-state the SD pins */
+ ctrl_val |= 0x1ff8;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
+ /* Let voltages settle */
+ udelay(100);
+
+ /* Enable the PCIe sideband pins */
+ ctrl_val &= ~0x6000;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
+ /* Let voltages settle */
+ udelay(100);
+
+ /* Turn on the 1v8 VDD2 regulator */
+ ret = regulator_enable(brcmstb_priv->sde_1v8);
+ if (ret)
+ return ret;
+
+ /* Wait for Tpvcrl */
+ msleep(1);
+
+ /* Sample DAT2 (CLKREQ#) - if low, card is in PCIe mode */
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ present_state = (present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT;
+ dev_dbg(dev, "state = 0x%08x\n", present_state);
+
+ if (present_state & BIT(2)) {
+ dev_err(dev, "DAT2 still high, abandoning SDex switch\n");
+ return -ENODEV;
+ }
+
+ /* Turn on the LCPLL PTEST mux */
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2 + 20); // misc5
+ ctrl_val &= ~(0x7 << 7);
+ ctrl_val |= 3 << 7;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2 + 20);
+ dev_dbg(dev, "misc 5->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2 + 20));
+
+ /* PTEST diff driver enable */
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2);
+ ctrl_val |= BIT(21);
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2);
+
+ dev_dbg(dev, "misc 0->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2));
+
+ /* Wait for more than the minimum Tpvpgl time */
+ msleep(100);
+
+ if (brcmstb_priv->sde_pcie) {
+ struct of_changeset changeset;
+ static struct property okay_property = {
+ .name = "status",
+ .value = "okay",
+ .length = 5,
+ };
+
+ /* Enable the pcie controller */
+ of_changeset_init(&changeset);
+ ret = of_changeset_update_property(&changeset,
+ brcmstb_priv->sde_pcie,
+ &okay_property);
+ if (ret) {
+ dev_err(dev, "%s: failed to update property - %d\n", __func__,
+ ret);
+ return -ENODEV;
+ }
+ ret = of_changeset_apply(&changeset);
+ }
+
+ dev_dbg(dev, "%s -> %d\n", __func__, ret);
+ return ret;
}
static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
@@ -220,6 +401,7 @@ static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
+ struct cqhci_host *cq_host = mmc->cqe_private;
u32 reg;
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
@@ -229,6 +411,22 @@ static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
}
sdhci_cqe_enable(mmc);
+
+ /*
+ * The controller resets this register to a very short default interval
+ * whenever CQHCI is disabled.
+ *
+ * For removable cards CBC needs to be clear or card removal can hang
+ * the CQE. In polling mode, a CIT of 0x4000 "cycles" seems to produce the best
+ * throughput.
+ *
+ * For nonremovable cards, the specification default of CBC=1 CIT=0x1000
+ * suffices.
+ */
+ if (mmc->caps & MMC_CAP_NONREMOVABLE)
+ cqhci_writel(cq_host, 0x00011000, CQHCI_SSC1);
+ else
+ cqhci_writel(cq_host, 0x00004000, CQHCI_SSC1);
}
static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = {
@@ -245,11 +443,12 @@ static struct sdhci_ops sdhci_brcmstb_ops = {
};
static struct sdhci_ops sdhci_brcmstb_ops_2712 = {
- .set_clock = sdhci_set_clock,
- .set_power = sdhci_set_power_and_bus_voltage,
+ .set_clock = sdhci_bcm2712_set_clock,
+ .set_power = sdhci_brcmstb_set_power,
.set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
+ .reset = brcmstb_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .init_sd_express = bcm2712_init_sd_express,
};
static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
@@ -267,6 +466,8 @@ static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
};
static const struct brcmstb_match_priv match_priv_2712 = {
+ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY,
+ .hs400es = sdhci_brcmstb_hs400es,
.cfginit = sdhci_brcmstb_cfginit_2712,
.ops = &sdhci_brcmstb_ops_2712,
};
@@ -370,8 +571,10 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
const struct of_device_id *match;
struct sdhci_brcmstb_priv *priv;
- u32 actual_clock_mhz;
+ u32 actual_clock_mhz, cqe;
struct sdhci_host *host;
+ struct resource *iomem;
+ bool no_pinctrl = false;
struct clk *clk;
struct clk *base_clk = NULL;
int res;
@@ -394,12 +597,21 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
+ pltfm_host->clk = clk;
+
priv = sdhci_pltfm_priv(pltfm_host);
- if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
+ cqe = 0;
+ device_property_read_u32(&pdev->dev, "supports-cqe", &cqe);
+ if (cqe > 0) {
priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
}
+ priv->sde_pcie = of_parse_phandle(pdev->dev.of_node,
+ "sde-pcie", 0);
+ if (priv->sde_pcie)
+ priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+
/* Map in the non-standard CFG registers */
priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(priv->cfg_regs)) {
@@ -412,6 +624,43 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
if (res)
goto err;
+ priv->sde_1v8 = devm_regulator_get_optional(&pdev->dev, "sde-1v8");
+ if (IS_ERR(priv->sde_1v8))
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (iomem) {
+ priv->sde_ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(priv->sde_ioaddr))
+ priv->sde_ioaddr = NULL;
+ }
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (iomem) {
+ priv->sde_ioaddr2 = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(priv->sde_ioaddr2))
+ priv->sde_ioaddr = NULL;
+ }
+
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(priv->pinctrl)) {
+ no_pinctrl = true;
+ }
+ priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default");
+ if (IS_ERR(priv->pins_default)) {
+ dev_dbg(&pdev->dev, "No pinctrl default state\n");
+ no_pinctrl = true;
+ }
+ priv->pins_sdex = pinctrl_lookup_state(priv->pinctrl, "sd-express");
+ if (IS_ERR(priv->pins_sdex)) {
+ dev_dbg(&pdev->dev, "No pinctrl sd-express state\n");
+ no_pinctrl = true;
+ }
+ if (no_pinctrl || !priv->sde_ioaddr || !priv->sde_ioaddr2) {
+ priv->pinctrl = NULL;
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+ }
+
/*
* Automatic clock gating does not work for SD cards that may
* voltage switch so only enable it for non-removable devices.
@@ -428,6 +677,10 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
(host->mmc->caps2 & MMC_CAP2_HS400_ES))
host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
+ if (host->ops->init_sd_express &&
+ (priv->flags & BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS))
+ host->mmc->caps2 |= MMC_CAP2_SD_EXP;
+
if (match_priv->cfginit)
match_priv->cfginit(host);
@@ -481,7 +734,6 @@ add_host:
if (res)
goto err;
- pltfm_host->clk = clk;
return res;
err:
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index 35ef5c5f5146..a2c5e886bd35 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -198,6 +198,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = {
.write_b = sdhci_iproc_writeb,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_iproc_get_max_clock,
+ .set_power = sdhci_set_power_and_bus_voltage,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index ee6b1096f709..4c1fccc03024 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -221,6 +221,7 @@ struct rk35xx_priv {
struct dwcmshc_priv {
struct clk *bus_clk;
+ struct clk *sdio_clk;
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */
int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */
@@ -289,6 +290,17 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
sdhci_adma_write_desc(host, desc, addr, len, cmd);
}
+static void dwcmshc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+
+ if (priv->sdio_clk)
+ clk_set_rate(priv->sdio_clk, clock);
+
+ sdhci_set_clock(host, clock);
+}
+
static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1096,10 +1108,11 @@ static int sg2042_init(struct device *dev, struct sdhci_host *host,
}
static const struct sdhci_ops sdhci_dwcmshc_ops = {
- .set_clock = sdhci_set_clock,
+ .set_clock = dwcmshc_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
.get_max_clock = dwcmshc_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_timeout_clock,
.reset = sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.irq = dwcmshc_cqe_irq_handler,
@@ -1172,8 +1185,10 @@ static const struct sdhci_ops sdhci_dwcmshc_sg2042_ops = {
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = {
.pdata = {
.ops = &sdhci_dwcmshc_ops,
- .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_BROKEN_HS200,
},
};
@@ -1188,13 +1203,26 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = {
};
#endif
+static const struct sdhci_pltfm_data sdhci_dwcmshc_rp1_pdata = {
+ .ops = &sdhci_dwcmshc_ops,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_BROKEN_HS200 |
+ SDHCI_QUIRK2_SPURIOUS_INT_RESP,
+};
+
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
.pdata = {
.ops = &sdhci_dwcmshc_rk35xx_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
- SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
+ SDHCI_QUIRK2_NO_SDR50 |
+ SDHCI_QUIRK2_NO_SDR104 |
+ SDHCI_QUIRK2_NO_SDR25,
+
},
.init = dwcmshc_rk35xx_init,
.postinit = dwcmshc_rk35xx_postinit,
@@ -1307,6 +1335,10 @@ dsbl_cqe_caps:
static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
{
+ .compatible = "raspberrypi,rp1-dwcmshc",
+ .data = &sdhci_dwcmshc_rp1_pdata,
+ },
+ {
.compatible = "rockchip,rk3588-dwcmshc",
.data = &sdhci_dwcmshc_rk35xx_pdata,
},
@@ -1398,13 +1430,32 @@ static int dwcmshc_probe(struct platform_device *pdev)
priv->bus_clk = devm_clk_get(dev, "bus");
if (!IS_ERR(priv->bus_clk))
clk_prepare_enable(priv->bus_clk);
+
+ pltfm_host->timeout_clk = devm_clk_get(dev, "timeout");
+ if (!IS_ERR(pltfm_host->timeout_clk))
+ err = clk_prepare_enable(pltfm_host->timeout_clk);
+ if (err)
+ goto free_pltfm;
+
+ priv->sdio_clk = devm_clk_get_optional(&pdev->dev, "sdio");
+ }
+
+ pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout");
+ if (IS_ERR(pltfm_host->timeout_clk)) {
+ err = PTR_ERR(pltfm_host->timeout_clk);
+ dev_err(&pdev->dev, "failed to get timeout clk: %d\n", err);
+ goto free_pltfm;
}
+ err = clk_prepare_enable(pltfm_host->timeout_clk);
+ if (err)
+ goto free_pltfm;
err = mmc_of_parse(host->mmc);
if (err)
goto err_clk;
sdhci_get_of_property(pdev);
+ sdhci_enable_v4_mode(host);
priv->vendor_specific_area1 =
sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
@@ -1464,6 +1515,7 @@ err_rpm:
pm_runtime_put_noidle(dev);
err_clk:
clk_disable_unprepare(pltfm_host->clk);
+ clk_disable_unprepare(pltfm_host->timeout_clk);
clk_disable_unprepare(priv->bus_clk);
clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
return err;
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 7f6ac636f040..ea58a8cdf33c 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -32,6 +32,14 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
+unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ return clk_get_rate(pltfm_host->timeout_clk);
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_timeout_clock);
+
static const struct sdhci_ops sdhci_pltfm_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 9c32e8a289d6..15d98c833c73 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -20,6 +20,7 @@ struct sdhci_pltfm_data {
struct sdhci_pltfm_host {
struct clk *clk;
+ struct clk *timeout_clk;
/* migrate from sdhci_of_host */
unsigned int clock;
@@ -105,6 +106,8 @@ extern void sdhci_pltfm_remove(struct platform_device *pdev);
extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
+extern unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host);
+
static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
{
return host->private;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ac7e11f37af7..65c1615f013c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -40,7 +40,7 @@
pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
#define SDHCI_DUMP(f, x...) \
- pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+ pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
#define MAX_TUNING_LOOP 40
@@ -1084,7 +1084,7 @@ void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
WARN_ON(host->data);
/* Sanity checks */
- BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz * data->blocks > host->mmc->max_req_size);
BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
@@ -1736,6 +1736,12 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (host->use_external_dma)
sdhci_external_dma_pre_transfer(host, cmd);
+ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) {
+ host->ier |= SDHCI_INT_RESPONSE;
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ }
+
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
return true;
@@ -3076,6 +3082,15 @@ static void sdhci_card_event(struct mmc_host *mmc)
spin_unlock_irqrestore(&host->lock, flags);
}
+static int sdhci_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (!host->ops->init_sd_express)
+ return -EOPNOTSUPP;
+ return host->ops->init_sd_express(host, ios);
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.post_req = sdhci_post_req,
@@ -3091,6 +3106,7 @@ static const struct mmc_host_ops sdhci_ops = {
.execute_tuning = sdhci_execute_tuning,
.card_event = sdhci_card_event,
.card_busy = sdhci_card_busy,
+ .init_sd_express = sdhci_init_sd_express,
};
/*****************************************************************************\
@@ -3245,7 +3261,7 @@ static void sdhci_timeout_timer(struct timer_list *t)
spin_lock_irqsave(&host->lock, flags);
if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
- pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
+ pr_debug("%s: Timeout waiting for hardware cmd interrupt.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, REQ_TIMEOUT);
sdhci_dumpregs(host);
@@ -3268,7 +3284,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
if (host->data || host->data_cmd ||
(host->cmd && sdhci_data_line_cmd(host->cmd))) {
- pr_err("%s: Timeout waiting for hardware interrupt.\n",
+ pr_debug("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, REQ_TIMEOUT);
sdhci_dumpregs(host);
@@ -3332,6 +3348,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
if (intmask & SDHCI_INT_TIMEOUT) {
host->cmd->error = -ETIMEDOUT;
sdhci_err_stats_inc(host, CMD_TIMEOUT);
+ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) {
+ host->ier &= ~SDHCI_INT_RESPONSE;
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ }
} else {
host->cmd->error = -EILSEQ;
if (!mmc_op_tuning(host->cmd->opcode))
@@ -4618,6 +4639,15 @@ int sdhci_setup_host(struct sdhci_host *host)
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
mmc->caps |= MMC_CAP_UHS_DDR50;
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR25)
+ mmc->caps &= ~MMC_CAP_UHS_SDR25;
+
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR50)
+ mmc->caps &= ~MMC_CAP_UHS_SDR50;
+
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR104)
+ mmc->caps &= ~MMC_CAP_UHS_SDR104;
+
/* Does the host need tuning for SDR50? */
if (host->caps1 & SDHCI_USE_SDR50_TUNING)
host->flags |= SDHCI_SDR50_NEEDS_TUNING;
@@ -4732,11 +4762,16 @@ int sdhci_setup_host(struct sdhci_host *host)
spin_lock_init(&host->lock);
/*
- * Maximum number of sectors in one transfer. Limited by SDMA boundary
- * size (512KiB). Note some tuning modes impose a 4MiB limit, but this
- * is less anyway.
+ * Maximum number of sectors in one transfer.
+ * 4MiB is preferred for multi-descriptor DMA as a) card sequential
+ * write speeds are only guaranteed with a 4MiB write length and
+ * b) most tuning modes require a 4MiB limit.
+ * SDMA has a 512KiB boundary size.
*/
- mmc->max_req_size = 524288;
+ if (host->flags & SDHCI_USE_ADMA)
+ mmc->max_req_size = SZ_4M;
+ else
+ mmc->max_req_size = SZ_512K;
/*
* Maximum number of segments. Depends on if the hardware
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 58fcbeaf281e..9d42eb94a1dc 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -537,6 +537,14 @@ struct sdhci_host {
/* Issue CMD and DATA reset together */
#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19)
+/* Quirks to ignore a speed if a that speed is unreliable */
+#define SDHCI_QUIRK2_NO_SDR25 (1<<19)
+#define SDHCI_QUIRK2_NO_SDR50 (1<<20)
+#define SDHCI_QUIRK2_NO_SDR104 (1<<21)
+
+/* Command timeouts may generate a trailing INT_RESPONSE later */
+#define SDHCI_QUIRK2_SPURIOUS_INT_RESP (1<<31)
+
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
phys_addr_t mapbase; /* physical address base */
@@ -724,6 +732,7 @@ struct sdhci_ops {
void (*dump_vendor_regs)(struct sdhci_host *host);
void (*dump_uhs2_regs)(struct sdhci_host *host);
void (*uhs2_pre_detect_init)(struct sdhci_host *host);
+ int (*init_sd_express)(struct sdhci_host *host, struct mmc_ios *ios);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS