diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mmc/core/block.c | 250 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 106 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.h | 14 | ||||
-rw-r--r-- | drivers/mmc/core/quirks.h | 22 | ||||
-rw-r--r-- | drivers/mmc/core/regulator.c | 8 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 137 | ||||
-rw-r--r-- | drivers/mmc/core/sd_ops.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 12 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/cqhci-core.c | 14 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-rockchip.c | 217 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/mtk-sd.c | 11 | ||||
-rw-r--r-- | drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-of-aspeed.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-of-dwcmshc.c | 478 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-of-ma35d1.c | 314 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pxav2.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci_am654.c | 54 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc_core.c | 7 |
21 files changed, 1304 insertions, 353 deletions
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index bf4e29ef023c..14d2ecbb04d3 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -37,6 +37,7 @@ config PWRSEQ_SIMPLE config MMC_BLOCK tristate "MMC block device driver" depends on BLOCK + depends on RPMB || !RPMB imply IOSCHED_BFQ default y help diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2c9963248fcb..f58bea534004 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -33,6 +33,7 @@ #include <linux/cdev.h> #include <linux/mutex.h> #include <linux/scatterlist.h> +#include <linux/string.h> #include <linux/string_helpers.h> #include <linux/delay.h> #include <linux/capability.h> @@ -40,6 +41,7 @@ #include <linux/pm_runtime.h> #include <linux/idr.h> #include <linux/debugfs.h> +#include <linux/rpmb.h> #include <linux/mmc/ioctl.h> #include <linux/mmc/card.h> @@ -76,6 +78,48 @@ MODULE_ALIAS("mmc:block"); #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) #define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8) +/** + * struct rpmb_frame - rpmb frame as defined by eMMC 5.1 (JESD84-B51) + * + * @stuff : stuff bytes + * @key_mac : The authentication key or the message authentication + * code (MAC) depending on the request/response type. + * The MAC will be delivered in the last (or the only) + * block of data. + * @data : Data to be written or read by signed access. + * @nonce : Random number generated by the host for the requests + * and copied to the response by the RPMB engine. + * @write_counter: Counter value for the total amount of the successful + * authenticated data write requests made by the host. + * @addr : Address of the data to be programmed to or read + * from the RPMB. Address is the serial number of + * the accessed block (half sector 256B). + * @block_count : Number of blocks (half sectors, 256B) requested to be + * read/programmed. + * @result : Includes information about the status of the write counter + * (valid, expired) and result of the access made to the RPMB. + * @req_resp : Defines the type of request and response to/from the memory. + * + * The stuff bytes and big-endian properties are modeled to fit to the spec. + */ +struct rpmb_frame { + u8 stuff[196]; + u8 key_mac[32]; + u8 data[256]; + u8 nonce[16]; + __be32 write_counter; + __be16 addr; + __be16 block_count; + __be16 result; + __be16 req_resp; +} __packed; + +#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */ +#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */ +#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */ +#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */ +#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */ + static DEFINE_MUTEX(block_mutex); /* @@ -155,6 +199,7 @@ static const struct bus_type mmc_rpmb_bus_type = { * @id: unique device ID number * @part_index: partition index (0 on first) * @md: parent MMC block device + * @rdev: registered RPMB device * @node: list item, so we can put this device on a list */ struct mmc_rpmb_data { @@ -163,6 +208,7 @@ struct mmc_rpmb_data { int id; unsigned int part_index; struct mmc_blk_data *md; + struct rpmb_dev *rdev; struct list_head node; }; @@ -307,10 +353,10 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; - char *end; struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - unsigned long set = simple_strtoul(buf, &end, 0); - if (end == buf) { + unsigned long set; + + if (kstrtoul(buf, 0, &set)) { ret = -EINVAL; goto out; } @@ -2484,7 +2530,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, return ERR_PTR(devidx); } - md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); + md = kzalloc(sizeof(*md), GFP_KERNEL); if (!md) { ret = -ENOMEM; goto out; @@ -2670,7 +2716,6 @@ static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp) get_device(&rpmb->dev); filp->private_data = rpmb; - mmc_blk_get(rpmb->md->disk); return nonseekable_open(inode, filp); } @@ -2680,7 +2725,6 @@ static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp) struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, struct mmc_rpmb_data, chrdev); - mmc_blk_put(rpmb->md); put_device(&rpmb->dev); return 0; @@ -2701,10 +2745,165 @@ static void mmc_blk_rpmb_device_release(struct device *dev) { struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev); + rpmb_dev_unregister(rpmb->rdev); + mmc_blk_put(rpmb->md); ida_free(&mmc_rpmb_ida, rpmb->id); kfree(rpmb); } +static void free_idata(struct mmc_blk_ioc_data **idata, unsigned int cmd_count) +{ + unsigned int n; + + for (n = 0; n < cmd_count; n++) + kfree(idata[n]); + kfree(idata); +} + +static struct mmc_blk_ioc_data **alloc_idata(struct mmc_rpmb_data *rpmb, + unsigned int cmd_count) +{ + struct mmc_blk_ioc_data **idata; + unsigned int n; + + idata = kcalloc(cmd_count, sizeof(*idata), GFP_KERNEL); + if (!idata) + return NULL; + + for (n = 0; n < cmd_count; n++) { + idata[n] = kcalloc(1, sizeof(**idata), GFP_KERNEL); + if (!idata[n]) { + free_idata(idata, n); + return NULL; + } + idata[n]->rpmb = rpmb; + } + + return idata; +} + +static void set_idata(struct mmc_blk_ioc_data *idata, u32 opcode, + int write_flag, u8 *buf, unsigned int buf_bytes) +{ + /* + * The size of an RPMB frame must match what's expected by the + * hardware. + */ + BUILD_BUG_ON(sizeof(struct rpmb_frame) != 512); + + idata->ic.opcode = opcode; + idata->ic.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + idata->ic.write_flag = write_flag; + idata->ic.blksz = sizeof(struct rpmb_frame); + idata->ic.blocks = buf_bytes / idata->ic.blksz; + idata->buf = buf; + idata->buf_bytes = buf_bytes; +} + +static int mmc_route_rpmb_frames(struct device *dev, u8 *req, + unsigned int req_len, u8 *resp, + unsigned int resp_len) +{ + struct rpmb_frame *frm = (struct rpmb_frame *)req; + struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev); + struct mmc_blk_data *md = rpmb->md; + struct mmc_blk_ioc_data **idata; + struct mmc_queue_req *mq_rq; + unsigned int cmd_count; + struct request *rq; + u16 req_type; + bool write; + int ret; + + if (IS_ERR(md->queue.card)) + return PTR_ERR(md->queue.card); + + if (req_len < sizeof(*frm)) + return -EINVAL; + + req_type = be16_to_cpu(frm->req_resp); + switch (req_type) { + case RPMB_PROGRAM_KEY: + if (req_len != sizeof(struct rpmb_frame) || + resp_len != sizeof(struct rpmb_frame)) + return -EINVAL; + write = true; + break; + case RPMB_GET_WRITE_COUNTER: + if (req_len != sizeof(struct rpmb_frame) || + resp_len != sizeof(struct rpmb_frame)) + return -EINVAL; + write = false; + break; + case RPMB_WRITE_DATA: + if (req_len % sizeof(struct rpmb_frame) || + resp_len != sizeof(struct rpmb_frame)) + return -EINVAL; + write = true; + break; + case RPMB_READ_DATA: + if (req_len != sizeof(struct rpmb_frame) || + resp_len % sizeof(struct rpmb_frame)) + return -EINVAL; + write = false; + break; + default: + return -EINVAL; + } + + if (write) + cmd_count = 3; + else + cmd_count = 2; + + idata = alloc_idata(rpmb, cmd_count); + if (!idata) + return -ENOMEM; + + if (write) { + struct rpmb_frame *frm = (struct rpmb_frame *)resp; + + /* Send write request frame(s) */ + set_idata(idata[0], MMC_WRITE_MULTIPLE_BLOCK, + 1 | MMC_CMD23_ARG_REL_WR, req, req_len); + + /* Send result request frame */ + memset(frm, 0, sizeof(*frm)); + frm->req_resp = cpu_to_be16(RPMB_RESULT_READ); + set_idata(idata[1], MMC_WRITE_MULTIPLE_BLOCK, 1, resp, + resp_len); + + /* Read response frame */ + set_idata(idata[2], MMC_READ_MULTIPLE_BLOCK, 0, resp, resp_len); + } else { + /* Send write request frame(s) */ + set_idata(idata[0], MMC_WRITE_MULTIPLE_BLOCK, 1, req, req_len); + + /* Read response frame */ + set_idata(idata[1], MMC_READ_MULTIPLE_BLOCK, 0, resp, resp_len); + } + + rq = blk_mq_alloc_request(md->queue.queue, REQ_OP_DRV_OUT, 0); + if (IS_ERR(rq)) { + ret = PTR_ERR(rq); + goto out; + } + + mq_rq = req_to_mmc_queue_req(rq); + mq_rq->drv_op = MMC_DRV_OP_IOCTL_RPMB; + mq_rq->drv_op_result = -EIO; + mq_rq->drv_op_data = idata; + mq_rq->ioc_count = cmd_count; + blk_execute_rq(rq, false); + ret = req_to_mmc_queue_req(rq)->drv_op_result; + + blk_mq_free_request(rq); + +out: + free_idata(idata, cmd_count); + return ret; +} + static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, struct mmc_blk_data *md, unsigned int part_index, @@ -2739,6 +2938,7 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, rpmb->dev.release = mmc_blk_rpmb_device_release; device_initialize(&rpmb->dev); dev_set_drvdata(&rpmb->dev, rpmb); + mmc_blk_get(md->disk); rpmb->md = md; cdev_init(&rpmb->chrdev, &mmc_rpmb_fileops); @@ -3000,6 +3200,42 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card, #endif /* CONFIG_DEBUG_FS */ +static void mmc_blk_rpmb_add(struct mmc_card *card) +{ + struct mmc_blk_data *md = dev_get_drvdata(&card->dev); + struct mmc_rpmb_data *rpmb; + struct rpmb_dev *rdev; + unsigned int n; + u32 cid[4]; + struct rpmb_descr descr = { + .type = RPMB_TYPE_EMMC, + .route_frames = mmc_route_rpmb_frames, + .reliable_wr_count = card->ext_csd.enhanced_rpmb_supported ? + 2 : 32, + .capacity = card->ext_csd.raw_rpmb_size_mult, + .dev_id = (void *)cid, + .dev_id_len = sizeof(cid), + }; + + /* + * Provice CID as an octet array. The CID needs to be interpreted + * when used as input to derive the RPMB key since some fields + * will change due to firmware updates. + */ + for (n = 0; n < 4; n++) + cid[n] = be32_to_cpu((__force __be32)card->raw_cid[n]); + + list_for_each_entry(rpmb, &md->rpmbs, node) { + rdev = rpmb_dev_register(&rpmb->dev, &descr); + if (IS_ERR(rdev)) { + pr_warn("%s: could not register RPMB device\n", + dev_name(&rpmb->dev)); + continue; + } + rpmb->rdev = rdev; + } +} + static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; @@ -3045,6 +3281,8 @@ static int mmc_blk_probe(struct mmc_card *card) pm_runtime_enable(&card->dev); } + mmc_blk_rpmb_add(card); + return 0; out: diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5b2f7c285461..6a23be214543 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -51,20 +51,6 @@ static const unsigned int taac_mant[] = { 35, 40, 45, 50, 55, 60, 70, 80, }; -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int __off = 3 - ((start) / 32); \ - const int __shft = (start) & 31; \ - u32 __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - /* * Given the decoded CSD structure, decode the raw CID to our CID structure. */ @@ -85,36 +71,36 @@ static int mmc_decode_cid(struct mmc_card *card) switch (card->csd.mmca_vsn) { case 0: /* MMC v1.0 - v1.2 */ case 1: /* MMC v1.4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); - card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); - card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); - card->cid.serial = UNSTUFF_BITS(resp, 16, 24); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + card->cid.manfid = unstuff_bits(resp, 104, 24); + card->cid.prod_name[0] = unstuff_bits(resp, 96, 8); + card->cid.prod_name[1] = unstuff_bits(resp, 88, 8); + card->cid.prod_name[2] = unstuff_bits(resp, 80, 8); + card->cid.prod_name[3] = unstuff_bits(resp, 72, 8); + card->cid.prod_name[4] = unstuff_bits(resp, 64, 8); + card->cid.prod_name[5] = unstuff_bits(resp, 56, 8); + card->cid.prod_name[6] = unstuff_bits(resp, 48, 8); + card->cid.hwrev = unstuff_bits(resp, 44, 4); + card->cid.fwrev = unstuff_bits(resp, 40, 4); + card->cid.serial = unstuff_bits(resp, 16, 24); + card->cid.month = unstuff_bits(resp, 12, 4); + card->cid.year = unstuff_bits(resp, 8, 4) + 1997; break; case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); - card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.prv = UNSTUFF_BITS(resp, 48, 8); - card->cid.serial = UNSTUFF_BITS(resp, 16, 32); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + card->cid.manfid = unstuff_bits(resp, 120, 8); + card->cid.oemid = unstuff_bits(resp, 104, 16); + card->cid.prod_name[0] = unstuff_bits(resp, 96, 8); + card->cid.prod_name[1] = unstuff_bits(resp, 88, 8); + card->cid.prod_name[2] = unstuff_bits(resp, 80, 8); + card->cid.prod_name[3] = unstuff_bits(resp, 72, 8); + card->cid.prod_name[4] = unstuff_bits(resp, 64, 8); + card->cid.prod_name[5] = unstuff_bits(resp, 56, 8); + card->cid.prv = unstuff_bits(resp, 48, 8); + card->cid.serial = unstuff_bits(resp, 16, 32); + card->cid.month = unstuff_bits(resp, 12, 4); + card->cid.year = unstuff_bits(resp, 8, 4) + 1997; break; default: @@ -161,43 +147,43 @@ static int mmc_decode_csd(struct mmc_card *card) * v1.2 has extra information in bits 15, 11 and 10. * We also support eMMC v4.4 & v4.41. */ - csd->structure = UNSTUFF_BITS(resp, 126, 2); + csd->structure = unstuff_bits(resp, 126, 2); if (csd->structure == 0) { pr_err("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd->structure); return -EINVAL; } - csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); + csd->mmca_vsn = unstuff_bits(resp, 122, 4); + m = unstuff_bits(resp, 115, 4); + e = unstuff_bits(resp, 112, 3); csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; - csd->taac_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + csd->taac_clks = unstuff_bits(resp, 104, 8) * 100; - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); + m = unstuff_bits(resp, 99, 4); + e = unstuff_bits(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + csd->cmdclass = unstuff_bits(resp, 84, 12); - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); + e = unstuff_bits(resp, 47, 3); + m = unstuff_bits(resp, 62, 12); csd->capacity = (1 + m) << (e + 2); - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + csd->read_blkbits = unstuff_bits(resp, 80, 4); + csd->read_partial = unstuff_bits(resp, 79, 1); + csd->write_misalign = unstuff_bits(resp, 78, 1); + csd->read_misalign = unstuff_bits(resp, 77, 1); + csd->dsr_imp = unstuff_bits(resp, 76, 1); + csd->r2w_factor = unstuff_bits(resp, 26, 3); + csd->write_blkbits = unstuff_bits(resp, 22, 4); + csd->write_partial = unstuff_bits(resp, 21, 1); if (csd->write_blkbits >= 9) { - a = UNSTUFF_BITS(resp, 42, 5); - b = UNSTUFF_BITS(resp, 37, 5); + a = unstuff_bits(resp, 42, 5); + b = unstuff_bits(resp, 37, 5); csd->erase_size = (a + 1) * (b + 1); csd->erase_size <<= csd->write_blkbits - 9; - csd->wp_grp_size = UNSTUFF_BITS(resp, 32, 5); + csd->wp_grp_size = unstuff_bits(resp, 32, 5); } return 0; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 92d4194c7893..06017110e1b0 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -56,5 +56,19 @@ int mmc_cmdq_enable(struct mmc_card *card); int mmc_cmdq_disable(struct mmc_card *card); int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms); +static inline u32 unstuff_bits(const u32 *resp, int start, int size) +{ + const int __size = size; + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; + const int __off = 3 - (start / 32); + const int __shft = start & 31; + u32 __res = resp[__off] >> __shft; + + if (__size + __shft > 32) + __res |= resp[__off - 1] << ((32 - __shft) % 32); + + return __res & __mask; +} + #endif diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index cca71867bc4a..92905fc46436 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -15,6 +15,19 @@ #include "card.h" +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. + */ + _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), + + 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 @@ -54,15 +67,6 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { MMC_QUIRK_BLK_NO_CMD23), /* - * 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. - */ - _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), - - /* * Some SD cards lockup while using CMD23 multiblock transfers. */ MMC_FIXUP("AF SD", CID_MANFID_ATP, CID_OEMID_ANY, add_quirk_sd, diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index 005247a49e51..01747ab1024e 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -255,7 +255,9 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, + "vmmc regulator not available\n"); + dev_dbg(dev, "No vmmc regulator found\n"); } else { ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); @@ -267,7 +269,9 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vqmmc)) { if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, + "vqmmc regulator not available\n"); + dev_dbg(dev, "No vqmmc regulator found\n"); } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 1c8148cdda50..12fe282bea77 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -26,6 +26,7 @@ #include "host.h" #include "bus.h" #include "mmc_ops.h" +#include "quirks.h" #include "sd.h" #include "sd_ops.h" @@ -55,20 +56,6 @@ static const unsigned int sd_au_size[] = { SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, }; -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int __off = 3 - ((start) / 32); \ - const int __shft = (start) & 31; \ - u32 __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - #define SD_POWEROFF_NOTIFY_TIMEOUT_MS 1000 #define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000 @@ -94,18 +81,18 @@ void mmc_decode_cid(struct mmc_card *card) * SD doesn't currently have a version field so we will * have to assume we can parse this. */ - card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); - card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4); - card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4); - card->cid.serial = UNSTUFF_BITS(resp, 24, 32); - card->cid.year = UNSTUFF_BITS(resp, 12, 8); - card->cid.month = UNSTUFF_BITS(resp, 8, 4); + card->cid.manfid = unstuff_bits(resp, 120, 8); + card->cid.oemid = unstuff_bits(resp, 104, 16); + card->cid.prod_name[0] = unstuff_bits(resp, 96, 8); + card->cid.prod_name[1] = unstuff_bits(resp, 88, 8); + card->cid.prod_name[2] = unstuff_bits(resp, 80, 8); + card->cid.prod_name[3] = unstuff_bits(resp, 72, 8); + card->cid.prod_name[4] = unstuff_bits(resp, 64, 8); + card->cid.hwrev = unstuff_bits(resp, 60, 4); + card->cid.fwrev = unstuff_bits(resp, 56, 4); + card->cid.serial = unstuff_bits(resp, 24, 32); + card->cid.year = unstuff_bits(resp, 12, 8); + card->cid.month = unstuff_bits(resp, 8, 4); card->cid.year += 2000; /* SD cards year offset */ } @@ -119,41 +106,41 @@ static int mmc_decode_csd(struct mmc_card *card) unsigned int e, m, csd_struct; u32 *resp = card->raw_csd; - csd_struct = UNSTUFF_BITS(resp, 126, 2); + csd_struct = unstuff_bits(resp, 126, 2); switch (csd_struct) { case 0: - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); + m = unstuff_bits(resp, 115, 4); + e = unstuff_bits(resp, 112, 3); csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; - csd->taac_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + csd->taac_clks = unstuff_bits(resp, 104, 8) * 100; - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); + m = unstuff_bits(resp, 99, 4); + e = unstuff_bits(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + csd->cmdclass = unstuff_bits(resp, 84, 12); - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); + e = unstuff_bits(resp, 47, 3); + m = unstuff_bits(resp, 62, 12); csd->capacity = (1 + m) << (e + 2); - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + csd->read_blkbits = unstuff_bits(resp, 80, 4); + csd->read_partial = unstuff_bits(resp, 79, 1); + csd->write_misalign = unstuff_bits(resp, 78, 1); + csd->read_misalign = unstuff_bits(resp, 77, 1); + csd->dsr_imp = unstuff_bits(resp, 76, 1); + csd->r2w_factor = unstuff_bits(resp, 26, 3); + csd->write_blkbits = unstuff_bits(resp, 22, 4); + csd->write_partial = unstuff_bits(resp, 21, 1); - if (UNSTUFF_BITS(resp, 46, 1)) { + if (unstuff_bits(resp, 46, 1)) { csd->erase_size = 1; } else if (csd->write_blkbits >= 9) { - csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1; + csd->erase_size = unstuff_bits(resp, 39, 7) + 1; csd->erase_size <<= csd->write_blkbits - 9; } - if (UNSTUFF_BITS(resp, 13, 1)) + if (unstuff_bits(resp, 13, 1)) mmc_card_set_readonly(card); break; case 1: @@ -168,17 +155,17 @@ static int mmc_decode_csd(struct mmc_card *card) csd->taac_ns = 0; /* Unused */ csd->taac_clks = 0; /* Unused */ - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); + m = unstuff_bits(resp, 99, 4); + e = unstuff_bits(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - csd->c_size = UNSTUFF_BITS(resp, 48, 22); + csd->cmdclass = unstuff_bits(resp, 84, 12); + csd->c_size = unstuff_bits(resp, 48, 22); /* SDXC cards have a minimum C_SIZE of 0x00FFFF */ if (csd->c_size >= 0xFFFF) mmc_card_set_ext_capacity(card); - m = UNSTUFF_BITS(resp, 48, 22); + m = unstuff_bits(resp, 48, 22); csd->capacity = (1 + m) << 10; csd->read_blkbits = 9; @@ -190,7 +177,7 @@ static int mmc_decode_csd(struct mmc_card *card) csd->write_partial = 0; csd->erase_size = 1; - if (UNSTUFF_BITS(resp, 13, 1)) + if (unstuff_bits(resp, 13, 1)) mmc_card_set_readonly(card); break; default: @@ -216,33 +203,33 @@ static int mmc_decode_scr(struct mmc_card *card) resp[3] = card->raw_scr[1]; resp[2] = card->raw_scr[0]; - scr_struct = UNSTUFF_BITS(resp, 60, 4); + scr_struct = unstuff_bits(resp, 60, 4); if (scr_struct != 0) { pr_err("%s: unrecognised SCR structure version %d\n", mmc_hostname(card->host), scr_struct); return -EINVAL; } - scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); - scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); + scr->sda_vsn = unstuff_bits(resp, 56, 4); + scr->bus_widths = unstuff_bits(resp, 48, 4); if (scr->sda_vsn == SCR_SPEC_VER_2) /* Check if Physical Layer Spec v3.0 is supported */ - scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1); + scr->sda_spec3 = unstuff_bits(resp, 47, 1); if (scr->sda_spec3) { - scr->sda_spec4 = UNSTUFF_BITS(resp, 42, 1); - scr->sda_specx = UNSTUFF_BITS(resp, 38, 4); + scr->sda_spec4 = unstuff_bits(resp, 42, 1); + scr->sda_specx = unstuff_bits(resp, 38, 4); } - if (UNSTUFF_BITS(resp, 55, 1)) + if (unstuff_bits(resp, 55, 1)) card->erased_byte = 0xFF; else card->erased_byte = 0x0; if (scr->sda_spec4) - scr->cmds = UNSTUFF_BITS(resp, 32, 4); + scr->cmds = unstuff_bits(resp, 32, 4); else if (scr->sda_spec3) - scr->cmds = UNSTUFF_BITS(resp, 32, 2); + scr->cmds = unstuff_bits(resp, 32, 2); /* SD Spec says: any SD Card shall set at least bits 0 and 2 */ if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || @@ -288,17 +275,17 @@ static int mmc_read_ssr(struct mmc_card *card) kfree(raw_ssr); /* - * UNSTUFF_BITS only works with four u32s so we have to offset the + * unstuff_bits only works with four u32s so we have to offset the * bitfield positions accordingly. */ - au = UNSTUFF_BITS(card->raw_ssr, 428 - 384, 4); + au = unstuff_bits(card->raw_ssr, 428 - 384, 4); if (au) { if (au <= 9 || card->scr.sda_spec3) { card->ssr.au = sd_au_size[au]; - es = UNSTUFF_BITS(card->raw_ssr, 408 - 384, 16); - et = UNSTUFF_BITS(card->raw_ssr, 402 - 384, 6); + es = unstuff_bits(card->raw_ssr, 408 - 384, 16); + et = unstuff_bits(card->raw_ssr, 402 - 384, 6); if (es && et) { - eo = UNSTUFF_BITS(card->raw_ssr, 400 - 384, 2); + eo = unstuff_bits(card->raw_ssr, 400 - 384, 2); card->ssr.erase_timeout = (et * 1000) / es; card->ssr.erase_offset = eo * 1000; } @@ -312,7 +299,7 @@ static int mmc_read_ssr(struct mmc_card *card) * starting SD5.1 discard is supported if DISCARD_SUPPORT (b313) is set */ resp[3] = card->raw_ssr[6]; - discard_support = UNSTUFF_BITS(resp, 313 - 288, 1); + discard_support = unstuff_bits(resp, 313 - 288, 1); card->erase_arg = (card->scr.sda_specx && discard_support) ? SD_DISCARD_ARG : SD_ERASE_ARG; @@ -345,7 +332,7 @@ static int mmc_read_switch(struct mmc_card *card) * The argument does not matter, as the support bits do not * change with the arguments. */ - err = mmc_sd_switch(card, 0, 0, 0, status); + err = mmc_sd_switch(card, SD_SWITCH_CHECK, 0, 0, status); if (err) { /* * If the host or the card can't do the switch, @@ -401,7 +388,8 @@ int mmc_sd_switch_hs(struct mmc_card *card) if (!status) return -ENOMEM; - err = mmc_sd_switch(card, 1, 0, HIGH_SPEED_BUS_SPEED, status); + err = mmc_sd_switch(card, SD_SWITCH_SET, 0, + HIGH_SPEED_BUS_SPEED, status); if (err) goto out; @@ -433,7 +421,8 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) card_drv_type, &drv_type); if (drive_strength) { - err = mmc_sd_switch(card, 1, 2, drive_strength, status); + err = mmc_sd_switch(card, SD_SWITCH_SET, 2, + drive_strength, status); if (err) return err; if ((status[15] & 0xF) != drive_strength) { @@ -513,7 +502,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) return 0; } - err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status); + err = mmc_sd_switch(card, SD_SWITCH_SET, 0, card->sd_bus_speed, status); if (err) return err; @@ -604,7 +593,8 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status) current_limit = SD_SET_CURRENT_LIMIT_200; if (current_limit != SD_SET_CURRENT_NO_CHANGE) { - err = mmc_sd_switch(card, 1, 3, current_limit, status); + err = mmc_sd_switch(card, SD_SWITCH_SET, 3, + current_limit, status); if (err) return err; @@ -1475,6 +1465,9 @@ retry: goto free_card; } + /* Apply quirks prior to card setup */ + mmc_fixup_device(card, mmc_sd_fixups); + err = mmc_sd_setup_card(host, card, oldcard != NULL); if (err) goto free_card; diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 8b9b34286ef3..f93c392040ae 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -336,14 +336,13 @@ int mmc_app_send_scr(struct mmc_card *card) return 0; } -int mmc_sd_switch(struct mmc_card *card, int mode, int group, +int mmc_sd_switch(struct mmc_card *card, bool mode, int group, u8 value, u8 *resp) { u32 cmd_args; /* NOTE: caller guarantees resp is heap-allocated */ - mode = !!mode; value &= 0xF; cmd_args = mode << 31 | 0x00FFFFFF; cmd_args &= ~(0xF << (group * 4)); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index eb3ecfe05591..7199cb0bd0b9 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -252,6 +252,18 @@ config MMC_SDHCI_OF_SPARX5 If unsure, say N. +config MMC_SDHCI_OF_MA35D1 + tristate "SDHCI OF support for the MA35D1 SDHCI controller" + depends on ARCH_MA35 || COMPILE_TEST + depends on MMC_SDHCI_PLTFM + help + This selects the MA35D1 Secure Digital Host Controller Interface. + The controller supports SD/MMC/SDIO devices. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_CADENCE tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index f53f86d200ac..3ccffebbe59b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o +obj-$(CONFIG_MMC_SDHCI_OF_MA35D1) += sdhci-of-ma35d1.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_NPCM) += sdhci-npcm.o diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index c14d7251d0bb..178277d90c31 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -33,6 +33,11 @@ struct cqhci_slot { #define CQHCI_HOST_OTHER BIT(4) }; +static bool cqhci_halted(struct cqhci_host *cq_host) +{ + return cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT; +} + static inline u8 *get_desc(struct cqhci_host *cq_host, u8 tag) { return cq_host->desc_base + (tag * cq_host->slot_sz); @@ -282,7 +287,7 @@ static void __cqhci_enable(struct cqhci_host *cq_host) cqhci_writel(cq_host, cqcfg, CQHCI_CFG); - if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) + if (cqhci_halted(cq_host)) cqhci_writel(cq_host, 0, CQHCI_CTL); mmc->cqe_on = true; @@ -617,7 +622,7 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) cqhci_writel(cq_host, 0, CQHCI_CTL); mmc->cqe_on = true; pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc)); - if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) { + if (cqhci_halted(cq_host)) { pr_err("%s: cqhci: CQE failed to exit halt state\n", mmc_hostname(mmc)); } @@ -953,11 +958,6 @@ static bool cqhci_clear_all_tasks(struct mmc_host *mmc, unsigned int timeout) return ret; } -static bool cqhci_halted(struct cqhci_host *cq_host) -{ - return cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT; -} - static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout) { struct cqhci_host *cq_host = mmc->cqe_private; diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index b07190ba4b7a..f96260fd143b 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -15,7 +15,17 @@ #include "dw_mmc.h" #include "dw_mmc-pltfm.h" -#define RK3288_CLKGEN_DIV 2 +#define RK3288_CLKGEN_DIV 2 +#define SDMMC_TIMING_CON0 0x130 +#define SDMMC_TIMING_CON1 0x134 +#define ROCKCHIP_MMC_DELAY_SEL BIT(10) +#define ROCKCHIP_MMC_DEGREE_MASK 0x3 +#define ROCKCHIP_MMC_DEGREE_OFFSET 1 +#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 +#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) +#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) static const unsigned int freqs[] = { 100000, 200000, 300000, 400000 }; @@ -24,8 +34,143 @@ struct dw_mci_rockchip_priv_data { struct clk *sample_clk; int default_sample_phase; int num_phases; + bool internal_phase; }; +/* + * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. + */ +static int rockchip_mmc_get_internal_phase(struct dw_mci *host, bool sample) +{ + unsigned long rate = clk_get_rate(host->ciu_clk); + u32 raw_value; + u16 degrees; + u32 delay_num = 0; + + /* Constant signal, no measurable phase shift */ + if (!rate) + return 0; + + if (sample) + raw_value = mci_readl(host, TIMING_CON1); + else + raw_value = mci_readl(host, TIMING_CON0); + + raw_value >>= ROCKCHIP_MMC_DEGREE_OFFSET; + degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; + + if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { + /* degrees/delaynum * 1000000 */ + unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * + 36 * (rate / 10000); + + delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); + delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; + degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000); + } + + return degrees % 360; +} + +static int rockchip_mmc_get_phase(struct dw_mci *host, bool sample) +{ + struct dw_mci_rockchip_priv_data *priv = host->priv; + struct clk *clock = sample ? priv->sample_clk : priv->drv_clk; + + if (priv->internal_phase) + return rockchip_mmc_get_internal_phase(host, sample); + else + return clk_get_phase(clock); +} + +static int rockchip_mmc_set_internal_phase(struct dw_mci *host, bool sample, int degrees) +{ + unsigned long rate = clk_get_rate(host->ciu_clk); + u8 nineties, remainder; + u8 delay_num; + u32 raw_value; + u32 delay; + + /* + * The below calculation is based on the output clock from + * MMC host to the card, which expects the phase clock inherits + * the clock rate from its parent, namely the output clock + * provider of MMC host. However, things may go wrong if + * (1) It is orphan. + * (2) It is assigned to the wrong parent. + * + * This check help debug the case (1), which seems to be the + * most likely problem we often face and which makes it difficult + * for people to debug unstable mmc tuning results. + */ + if (!rate) { + dev_err(host->dev, "%s: invalid clk rate\n", __func__); + return -EINVAL; + } + + nineties = degrees / 90; + remainder = (degrees % 90); + + /* + * Due to the inexact nature of the "fine" delay, we might + * actually go non-monotonic. We don't go _too_ monotonic + * though, so we should be OK. Here are options of how we may + * work: + * + * Ideally we end up with: + * 1.0, 2.0, ..., 69.0, 70.0, ..., 89.0, 90.0 + * + * On one extreme (if delay is actually 44ps): + * .73, 1.5, ..., 50.6, 51.3, ..., 65.3, 90.0 + * The other (if delay is actually 77ps): + * 1.3, 2.6, ..., 88.6. 89.8, ..., 114.0, 90 + * + * It's possible we might make a delay that is up to 25 + * degrees off from what we think we're making. That's OK + * though because we should be REALLY far from any bad range. + */ + + /* + * Convert to delay; do a little extra work to make sure we + * don't overflow 32-bit / 64-bit numbers. + */ + delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ + delay *= remainder; + delay = DIV_ROUND_CLOSEST(delay, + (rate / 1000) * 36 * + (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); + + delay_num = (u8) min_t(u32, delay, 255); + + raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; + raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; + raw_value |= nineties; + + if (sample) + mci_writel(host, TIMING_CON1, HIWORD_UPDATE(raw_value, 0x07ff, 1)); + else + mci_writel(host, TIMING_CON0, HIWORD_UPDATE(raw_value, 0x07ff, 1)); + + dev_dbg(host->dev, "set %s_phase(%d) delay_nums=%u actual_degrees=%d\n", + sample ? "sample" : "drv", degrees, delay_num, + rockchip_mmc_get_phase(host, sample) + ); + + return 0; +} + +static int rockchip_mmc_set_phase(struct dw_mci *host, bool sample, int degrees) +{ + struct dw_mci_rockchip_priv_data *priv = host->priv; + struct clk *clock = sample ? priv->sample_clk : priv->drv_clk; + + if (priv->internal_phase) + return rockchip_mmc_set_internal_phase(host, sample, degrees); + else + return clk_set_phase(clock, degrees); +} + static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) { struct dw_mci_rockchip_priv_data *priv = host->priv; @@ -64,7 +209,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) /* Make sure we use phases which we can enumerate with */ if (!IS_ERR(priv->sample_clk) && ios->timing <= MMC_TIMING_SD_HS) - clk_set_phase(priv->sample_clk, priv->default_sample_phase); + rockchip_mmc_set_phase(host, true, priv->default_sample_phase); /* * Set the drive phase offset based on speed mode to achieve hold times. @@ -127,7 +272,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) break; } - clk_set_phase(priv->drv_clk, phase); + rockchip_mmc_set_phase(host, false, phase); } } @@ -151,6 +296,7 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) int longest_range_len = -1; int longest_range = -1; int middle_phase; + int phase; if (IS_ERR(priv->sample_clk)) { dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n"); @@ -164,8 +310,10 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) /* Try each phase and extract good ranges */ for (i = 0; i < priv->num_phases; ) { - clk_set_phase(priv->sample_clk, - TUNING_ITERATION_TO_PHASE(i, priv->num_phases)); + rockchip_mmc_set_phase(host, true, + TUNING_ITERATION_TO_PHASE( + i, + priv->num_phases)); v = !mmc_send_tuning(mmc, opcode, NULL); @@ -211,7 +359,8 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) } if (ranges[0].start == 0 && ranges[0].end == priv->num_phases - 1) { - clk_set_phase(priv->sample_clk, priv->default_sample_phase); + rockchip_mmc_set_phase(host, true, priv->default_sample_phase); + dev_info(host->dev, "All phases work, using default phase %d.", priv->default_sample_phase); goto free; @@ -248,19 +397,17 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) middle_phase = ranges[longest_range].start + longest_range_len / 2; middle_phase %= priv->num_phases; - dev_info(host->dev, "Successfully tuned phase to %d\n", - TUNING_ITERATION_TO_PHASE(middle_phase, priv->num_phases)); + phase = TUNING_ITERATION_TO_PHASE(middle_phase, priv->num_phases); + dev_info(host->dev, "Successfully tuned phase to %d\n", phase); - clk_set_phase(priv->sample_clk, - TUNING_ITERATION_TO_PHASE(middle_phase, - priv->num_phases)); + rockchip_mmc_set_phase(host, true, phase); free: kfree(ranges); return ret; } -static int dw_mci_rk3288_parse_dt(struct dw_mci *host) +static int dw_mci_common_parse_dt(struct dw_mci *host) { struct device_node *np = host->dev->of_node; struct dw_mci_rockchip_priv_data *priv; @@ -270,13 +417,29 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host) return -ENOMEM; if (of_property_read_u32(np, "rockchip,desired-num-phases", - &priv->num_phases)) + &priv->num_phases)) priv->num_phases = 360; if (of_property_read_u32(np, "rockchip,default-sample-phase", - &priv->default_sample_phase)) + &priv->default_sample_phase)) priv->default_sample_phase = 0; + host->priv = priv; + + return 0; +} + +static int dw_mci_rk3288_parse_dt(struct dw_mci *host) +{ + struct dw_mci_rockchip_priv_data *priv; + int err; + + err = dw_mci_common_parse_dt(host); + if (err) + return err; + + priv = host->priv; + priv->drv_clk = devm_clk_get(host->dev, "ciu-drive"); if (IS_ERR(priv->drv_clk)) dev_dbg(host->dev, "ciu-drive not available\n"); @@ -285,7 +448,21 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host) if (IS_ERR(priv->sample_clk)) dev_dbg(host->dev, "ciu-sample not available\n"); - host->priv = priv; + priv->internal_phase = false; + + return 0; +} + +static int dw_mci_rk3576_parse_dt(struct dw_mci *host) +{ + struct dw_mci_rockchip_priv_data *priv; + int err = dw_mci_common_parse_dt(host); + if (err) + return err; + + priv = host->priv; + + priv->internal_phase = true; return 0; } @@ -331,11 +508,21 @@ static const struct dw_mci_drv_data rk3288_drv_data = { .init = dw_mci_rockchip_init, }; +static const struct dw_mci_drv_data rk3576_drv_data = { + .common_caps = MMC_CAP_CMD23, + .set_ios = dw_mci_rk3288_set_ios, + .execute_tuning = dw_mci_rk3288_execute_tuning, + .parse_dt = dw_mci_rk3576_parse_dt, + .init = dw_mci_rockchip_init, +}; + static const struct of_device_id dw_mci_rockchip_match[] = { { .compatible = "rockchip,rk2928-dw-mshc", .data = &rk2928_drv_data }, { .compatible = "rockchip,rk3288-dw-mshc", .data = &rk3288_drv_data }, + { .compatible = "rockchip,rk3576-dw-mshc", + .data = &rk3576_drv_data }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e9f6e4e62290..41e451235f63 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2957,8 +2957,8 @@ static int dw_mci_init_slot(struct dw_mci *host) if (host->use_dma == TRANS_MODE_IDMAC) { mmc->max_segs = host->ring_size; mmc->max_blk_size = 65535; - mmc->max_seg_size = 0x1000; - mmc->max_req_size = mmc->max_seg_size * host->ring_size; + mmc->max_req_size = DW_MCI_DESC_DATA_LENGTH * host->ring_size; + mmc->max_seg_size = mmc->max_req_size; mmc->max_blk_count = mmc->max_req_size / 512; } else if (host->use_dma == TRANS_MODE_EDMAC) { mmc->max_segs = 64; diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index e386f78e3267..89018b6c97b9 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -795,14 +795,13 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_data *data) static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks) { struct mmc_host *mmc = mmc_from_priv(host); - u64 timeout, clk_ns; - u32 mode = 0; + u64 timeout; + u32 clk_ns, mode = 0; if (mmc->actual_clock == 0) { timeout = 0; } else { - clk_ns = 1000000000ULL; - do_div(clk_ns, mmc->actual_clock); + clk_ns = 1000000000U / mmc->actual_clock; timeout = ns + clk_ns - 1; do_div(timeout, clk_ns); timeout += clks; @@ -831,7 +830,7 @@ static void msdc_set_timeout(struct msdc_host *host, u64 ns, u64 clks) timeout = msdc_timeout_cal(host, ns, clks); sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, - (u32)(timeout > 255 ? 255 : timeout)); + min_t(u32, timeout, 255)); } static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks) @@ -840,7 +839,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks) timeout = msdc_timeout_cal(host, ns, clks); sdr_set_field(host->base + SDC_CFG, SDC_CFG_WRDTOC, - (u32)(timeout > 8191 ? 8191 : timeout)); + min_t(u32, timeout, 8191)); } static void msdc_gate_clock(struct msdc_host *host) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index caf1d2e23343..1dcaa050f264 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -285,6 +285,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, }, + { .compatible = "renesas,sdhi-r9a09g057", .data = &of_rzg2l_compatible, }, { .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index 430c1f90037b..37240895ffaa 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -510,6 +510,7 @@ static const struct of_device_id aspeed_sdhci_of_match[] = { { .compatible = "aspeed,ast2600-sdhci", .data = &ast2600_sdhci_pdata, }, { } }; +MODULE_DEVICE_TABLE(of, aspeed_sdhci_of_match); static struct platform_driver aspeed_sdhci_driver = { .driver = { diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index e79aa4b3b6c3..8999b97263af 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -8,6 +8,7 @@ */ #include <linux/acpi.h> +#include <linux/arm-smccc.h> #include <linux/bitfield.h> #include <linux/clk.h> #include <linux/dma-mapping.h> @@ -108,18 +109,20 @@ #define DLL_LOCK_WO_TMOUT(x) \ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) -#define RK35xx_MAX_CLKS 3 /* PHY register area pointer */ #define DWC_MSHC_PTR_PHY_R 0x300 /* PHY general configuration */ -#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) -#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ -#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */ -#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ -#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */ -#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ +#define PHY_CNFG_PHY_PWRGOOD_MASK BIT_MASK(1) /* bit [1] */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SP_SG2042 0x09 /* PMOS TX drive strength for SG2042 */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_SG2042 0x08 /* NMOS TX drive strength for SG2042 */ /* PHY command/response pad settings */ #define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04) @@ -148,10 +151,12 @@ #define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */ #define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits [12:9] */ #define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */ +#define PHY_PAD_TXSLEW_CTRL_N_SG2042 0x2 /* Slew control for N-Type pad TX for SG2042 */ /* PHY CLK delay line settings */ #define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) -#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ +#define PHY_SDCLKDL_CNFG_EXTDLY_EN BIT(0) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ /* PHY CLK delay line delay code */ #define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e) @@ -159,10 +164,14 @@ #define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */ #define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */ +#define PHY_SMPLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x20) +#define PHY_SMPLDL_CNFG_BYPASS_EN BIT(1) + /* PHY drift_cclk_rx delay line configuration setting */ #define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21) #define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits [3:2] */ #define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */ +#define PHY_ATDL_CNFG_INPSEL_SG2042 0x2 /* delay line input source for SG2042 */ /* PHY DLL control settings */ #define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24) @@ -193,29 +202,69 @@ SDHCI_TRNS_BLK_CNT_EN | \ SDHCI_TRNS_DMA) +/* SMC call for BlueField-3 eMMC RST_N */ +#define BLUEFIELD_SMC_SET_EMMC_RST_N 0x82000007 + enum dwcmshc_rk_type { DWCMSHC_RK3568, DWCMSHC_RK3588, }; struct rk35xx_priv { - /* Rockchip specified optional clocks */ - struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS]; struct reset_control *reset; enum dwcmshc_rk_type devtype; u8 txclk_tapnum; }; +#define DWCMSHC_MAX_OTHER_CLKS 3 + struct dwcmshc_priv { struct clk *bus_clk; int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */ int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */ + int num_other_clks; + struct clk_bulk_data other_clks[DWCMSHC_MAX_OTHER_CLKS]; + void *priv; /* pointer to SoC private stuff */ u16 delay_line; u16 flags; }; +struct dwcmshc_pltfm_data { + const struct sdhci_pltfm_data pdata; + int (*init)(struct device *dev, struct sdhci_host *host, struct dwcmshc_priv *dwc_priv); + void (*postinit)(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv); +}; + +static int dwcmshc_get_enable_other_clks(struct device *dev, + struct dwcmshc_priv *priv, + int num_clks, + const char * const clk_ids[]) +{ + int err; + + if (num_clks > DWCMSHC_MAX_OTHER_CLKS) + return -EINVAL; + + for (int i = 0; i < num_clks; i++) + priv->other_clks[i].id = clk_ids[i]; + + err = devm_clk_bulk_get_optional(dev, num_clks, priv->other_clks); + if (err) { + dev_err(dev, "failed to get clocks %d\n", err); + return err; + } + + err = clk_bulk_prepare_enable(num_clks, priv->other_clks); + if (err) + dev_err(dev, "failed to enable clocks %d\n", err); + + priv->num_other_clks = num_clks; + + return err; +} + /* * If DMA addr spans 128MB boundary, we split the DMA transfer into two * so that each DMA transfer doesn't exceed the boundary. @@ -681,6 +730,63 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_reset(host, mask); } +static int dwcmshc_rk35xx_init(struct device *dev, struct sdhci_host *host, + struct dwcmshc_priv *dwc_priv) +{ + static const char * const clk_ids[] = {"axi", "block", "timer"}; + struct rk35xx_priv *priv; + int err; + + priv = devm_kzalloc(dev, sizeof(struct rk35xx_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (of_device_is_compatible(dev->of_node, "rockchip,rk3588-dwcmshc")) + priv->devtype = DWCMSHC_RK3588; + else + priv->devtype = DWCMSHC_RK3568; + + priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); + if (IS_ERR(priv->reset)) { + err = PTR_ERR(priv->reset); + dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); + return err; + } + + err = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv, + ARRAY_SIZE(clk_ids), clk_ids); + if (err) + return err; + + if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", + &priv->txclk_tapnum)) + priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + + /* Disable cmd conflict check */ + sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); + /* Reset previous settings */ + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); + + dwc_priv->priv = priv; + + return 0; +} + +static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) +{ + /* + * Don't support highspeed bus mode with low clk speed as we + * cannot use DLL for this condition. + */ + if (host->mmc->f_max <= 52000000) { + dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n", + host->mmc->f_max); + host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); + } +} + static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -755,6 +861,35 @@ static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) } } +static int th1520_init(struct device *dev, + struct sdhci_host *host, + struct dwcmshc_priv *dwc_priv) +{ + dwc_priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; + + if (device_property_read_bool(dev, "mmc-ddr-1_8v") || + device_property_read_bool(dev, "mmc-hs200-1_8v") || + device_property_read_bool(dev, "mmc-hs400-1_8v")) + dwc_priv->flags |= FLAG_IO_FIXED_1V8; + else + dwc_priv->flags &= ~FLAG_IO_FIXED_1V8; + + /* + * start_signal_voltage_switch() will try 3.3V first + * then 1.8V. Use SDHCI_SIGNALING_180 rather than + * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V + * in sdhci_start_signal_voltage_switch(). + */ + if (dwc_priv->flags & FLAG_IO_FIXED_1V8) { + host->flags &= ~SDHCI_SIGNALING_330; + host->flags |= SDHCI_SIGNALING_180; + } + + sdhci_enable_v4_mode(host); + + return 0; +} + static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -891,6 +1026,85 @@ static int cv18xx_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) return ret; } +static inline void sg2042_sdhci_phy_init(struct sdhci_host *host) +{ + u32 val; + + /* Asset phy reset & set tx drive strength */ + val = sdhci_readl(host, PHY_CNFG_R); + val &= ~PHY_CNFG_RSTN_DEASSERT; + val |= FIELD_PREP(PHY_CNFG_PHY_PWRGOOD_MASK, 1); + val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP_SG2042); + val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN_SG2042); + sdhci_writel(host, val, PHY_CNFG_R); + + /* Configure phy pads */ + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_SG2042); + sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); + sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); + sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); + + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_SG2042); + sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); + + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N_SG2042); + sdhci_writew(host, val, PHY_STBPAD_CNFG_R); + + /* Configure delay line */ + /* Enable fixed delay */ + sdhci_writeb(host, PHY_SDCLKDL_CNFG_EXTDLY_EN, PHY_SDCLKDL_CNFG_R); + /* + * Set delay line. + * Its recommended that bit UPDATE_DC[4] is 1 when SDCLKDL_DC is being written. + * Ensure UPDATE_DC[4] is '0' when not updating code. + */ + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val |= PHY_SDCLKDL_CNFG_UPDATE; + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + /* Add 10 * 70ps = 0.7ns for output delay */ + sdhci_writeb(host, 10, PHY_SDCLKDL_DC_R); + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE); + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + + /* Set SMPLDL_CNFG, Bypass */ + sdhci_writeb(host, PHY_SMPLDL_CNFG_BYPASS_EN, PHY_SMPLDL_CNFG_R); + + /* Set ATDL_CNFG, tuning clk not use for init */ + val = FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL_SG2042); + sdhci_writeb(host, val, PHY_ATDL_CNFG_R); + + /* Deasset phy reset */ + val = sdhci_readl(host, PHY_CNFG_R); + val |= PHY_CNFG_RSTN_DEASSERT; + sdhci_writel(host, val, PHY_CNFG_R); +} + +static void sg2042_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + sdhci_reset(host, mask); + + if (mask & SDHCI_RESET_ALL) + sg2042_sdhci_phy_init(host); +} + +static int sg2042_init(struct device *dev, struct sdhci_host *host, + struct dwcmshc_priv *dwc_priv) +{ + static const char * const clk_ids[] = {"timer"}; + + return dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv, + ARRAY_SIZE(clk_ids), clk_ids); +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -901,6 +1115,29 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { .irq = dwcmshc_cqe_irq_handler, }; +#ifdef CONFIG_ACPI +static void dwcmshc_bf3_hw_reset(struct sdhci_host *host) +{ + struct arm_smccc_res res = { 0 }; + + arm_smccc_smc(BLUEFIELD_SMC_SET_EMMC_RST_N, 0, 0, 0, 0, 0, 0, 0, &res); + + if (res.a0) + pr_err("%s: RST_N failed.\n", mmc_hostname(host->mmc)); +} + +static const struct sdhci_ops sdhci_dwcmshc_bf3_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .reset = sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .irq = dwcmshc_cqe_irq_handler, + .hw_reset = dwcmshc_bf3_hw_reset, +}; +#endif + static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { .set_clock = dwcmshc_rk3568_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -932,39 +1169,71 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .platform_execute_tuning = cv18xx_sdhci_execute_tuning, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +static const struct sdhci_ops sdhci_dwcmshc_sg2042_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .reset = sg2042_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .platform_execute_tuning = th1520_execute_tuning, +}; + +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, + }, }; #ifdef CONFIG_ACPI -static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_ACMD23_BROKEN, +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_bf3_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_ACMD23_BROKEN, + }, }; #endif -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_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, +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, + }, + .init = dwcmshc_rk35xx_init, + .postinit = dwcmshc_rk35xx_postinit, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { - .ops = &sdhci_dwcmshc_th1520_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_th1520_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, + .init = th1520_init, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { - .ops = &sdhci_dwcmshc_cv18xx_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_cv18xx_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, +}; + +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_sg2042_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_sg2042_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, + .init = sg2042_init, }; static const struct cqhci_host_ops dwcmshc_cqhci_ops = { @@ -1034,61 +1303,6 @@ dsbl_cqe_caps: host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD); } -static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) -{ - int err; - struct rk35xx_priv *priv = dwc_priv->priv; - - priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); - if (IS_ERR(priv->reset)) { - err = PTR_ERR(priv->reset); - dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); - return err; - } - - priv->rockchip_clks[0].id = "axi"; - priv->rockchip_clks[1].id = "block"; - priv->rockchip_clks[2].id = "timer"; - err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS, - priv->rockchip_clks); - if (err) { - dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); - return err; - } - - err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks); - if (err) { - dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); - return err; - } - - if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", - &priv->txclk_tapnum)) - priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; - - /* Disable cmd conflict check */ - sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); - /* Reset previous settings */ - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); - - return 0; -} - -static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) -{ - /* - * Don't support highspeed bus mode with low clk speed as we - * cannot use DLL for this condition. - */ - if (host->mmc->f_max <= 52000000) { - dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n", - host->mmc->f_max); - host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); - host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); - } -} - static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible = "rockchip,rk3588-dwcmshc", @@ -1114,6 +1328,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "thead,th1520-dwcmshc", .data = &sdhci_dwcmshc_th1520_pdata, }, + { + .compatible = "sophgo,sg2042-dwcmshc", + .data = &sdhci_dwcmshc_sg2042_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); @@ -1135,8 +1353,7 @@ static int dwcmshc_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; struct dwcmshc_priv *priv; - struct rk35xx_priv *rk_priv = NULL; - const struct sdhci_pltfm_data *pltfm_data; + const struct dwcmshc_pltfm_data *pltfm_data; int err; u32 extra, caps; @@ -1146,7 +1363,7 @@ static int dwcmshc_probe(struct platform_device *pdev) return -ENODEV; } - host = sdhci_pltfm_init(pdev, pltfm_data, + host = sdhci_pltfm_init(pdev, &pltfm_data->pdata, sizeof(struct dwcmshc_priv)); if (IS_ERR(host)) return PTR_ERR(host); @@ -1191,49 +1408,12 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; - if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) { - rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); - if (!rk_priv) { - err = -ENOMEM; - goto err_clk; - } - - if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc")) - rk_priv->devtype = DWCMSHC_RK3588; - else - rk_priv->devtype = DWCMSHC_RK3568; - - priv->priv = rk_priv; - - err = dwcmshc_rk35xx_init(host, priv); + if (pltfm_data->init) { + err = pltfm_data->init(&pdev->dev, host, priv); if (err) goto err_clk; } - if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { - priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; - - if (device_property_read_bool(dev, "mmc-ddr-1_8v") || - device_property_read_bool(dev, "mmc-hs200-1_8v") || - device_property_read_bool(dev, "mmc-hs400-1_8v")) - priv->flags |= FLAG_IO_FIXED_1V8; - else - priv->flags &= ~FLAG_IO_FIXED_1V8; - - /* - * start_signal_voltage_switch() will try 3.3V first - * then 1.8V. Use SDHCI_SIGNALING_180 rather than - * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V - * in sdhci_start_signal_voltage_switch(). - */ - if (priv->flags & FLAG_IO_FIXED_1V8) { - host->flags &= ~SDHCI_SIGNALING_330; - host->flags |= SDHCI_SIGNALING_180; - } - - sdhci_enable_v4_mode(host); - } - #ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) sdhci_enable_v4_mode(host); @@ -1261,8 +1441,8 @@ static int dwcmshc_probe(struct platform_device *pdev) dwcmshc_cqhci_init(host, pdev); } - if (rk_priv) - dwcmshc_rk35xx_postinit(host, priv); + if (pltfm_data->postinit) + pltfm_data->postinit(host, priv); err = __sdhci_add_host(host); if (err) @@ -1280,9 +1460,7 @@ err_rpm: err_clk: clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); - if (rk_priv) - clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); + clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); free_pltfm: sdhci_pltfm_free(pdev); return err; @@ -1304,7 +1482,6 @@ static void dwcmshc_remove(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); - struct rk35xx_priv *rk_priv = priv->priv; pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1316,9 +1493,7 @@ static void dwcmshc_remove(struct platform_device *pdev) clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); - if (rk_priv) - clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); + clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); sdhci_pltfm_free(pdev); } @@ -1328,7 +1503,6 @@ static int dwcmshc_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); - struct rk35xx_priv *rk_priv = priv->priv; int ret; pm_runtime_resume(dev); @@ -1347,9 +1521,7 @@ static int dwcmshc_suspend(struct device *dev) if (!IS_ERR(priv->bus_clk)) clk_disable_unprepare(priv->bus_clk); - if (rk_priv) - clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); + clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); return ret; } @@ -1359,7 +1531,6 @@ static int dwcmshc_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); - struct rk35xx_priv *rk_priv = priv->priv; int ret; ret = clk_prepare_enable(pltfm_host->clk); @@ -1372,29 +1543,24 @@ static int dwcmshc_resume(struct device *dev) goto disable_clk; } - if (rk_priv) { - ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); - if (ret) - goto disable_bus_clk; - } + ret = clk_bulk_prepare_enable(priv->num_other_clks, priv->other_clks); + if (ret) + goto disable_bus_clk; ret = sdhci_resume_host(host); if (ret) - goto disable_rockchip_clks; + goto disable_other_clks; if (host->mmc->caps2 & MMC_CAP2_CQE) { ret = cqhci_resume(host->mmc); if (ret) - goto disable_rockchip_clks; + goto disable_other_clks; } return 0; -disable_rockchip_clks: - if (rk_priv) - clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, - rk_priv->rockchip_clks); +disable_other_clks: + clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); disable_bus_clk: if (!IS_ERR(priv->bus_clk)) clk_disable_unprepare(priv->bus_clk); diff --git a/drivers/mmc/host/sdhci-of-ma35d1.c b/drivers/mmc/host/sdhci-of-ma35d1.c new file mode 100644 index 000000000000..b84c2927bd4a --- /dev/null +++ b/drivers/mmc/host/sdhci-of-ma35d1.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Nuvoton Technology Corp. + * + * Author: Shan-Chun Hung <shanchun1218@gmail.com> + */ + +#include <linux/align.h> +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/build_bug.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/math.h> +#include <linux/mfd/syscon.h> +#include <linux/minmax.h> +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <linux/sizes.h> +#include <linux/types.h> + +#include "sdhci-pltfm.h" +#include "sdhci.h" + +#define MA35_SYS_MISCFCR0 0x070 +#define MA35_SDHCI_MSHCCTL 0x508 +#define MA35_SDHCI_MBIUCTL 0x510 + +#define MA35_SDHCI_CMD_CONFLICT_CHK BIT(0) +#define MA35_SDHCI_INCR_MSK GENMASK(3, 0) +#define MA35_SDHCI_INCR16 BIT(3) +#define MA35_SDHCI_INCR8 BIT(2) + +struct ma35_priv { + struct reset_control *rst; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_uhs; + struct pinctrl_state *pins_default; +}; + +struct ma35_restore_data { + u32 reg; + u32 width; +}; + +static const struct ma35_restore_data restore_data[] = { + { SDHCI_CLOCK_CONTROL, sizeof(u32)}, + { SDHCI_BLOCK_SIZE, sizeof(u32)}, + { SDHCI_INT_ENABLE, sizeof(u32)}, + { SDHCI_SIGNAL_ENABLE, sizeof(u32)}, + { SDHCI_AUTO_CMD_STATUS, sizeof(u32)}, + { SDHCI_HOST_CONTROL, sizeof(u32)}, + { SDHCI_TIMEOUT_CONTROL, sizeof(u8) }, + { MA35_SDHCI_MSHCCTL, sizeof(u16)}, + { MA35_SDHCI_MBIUCTL, sizeof(u16)}, +}; + +/* + * If DMA addr spans 128MB boundary, we split the DMA transfer into two + * so that each DMA transfer doesn't exceed the boundary. + */ +static void ma35_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len, + unsigned int cmd) +{ + int tmplen, offset; + + if (likely(!len || (ALIGN(addr, SZ_128M) == ALIGN(addr + len - 1, SZ_128M)))) { + sdhci_adma_write_desc(host, desc, addr, len, cmd); + return; + } + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); + + addr += tmplen; + len -= tmplen; + sdhci_adma_write_desc(host, desc, addr, len, cmd); +} + +static void ma35_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u32 ctl; + + /* + * If the clock frequency exceeds MMC_HIGH_52_MAX_DTR, + * disable command conflict check. + */ + ctl = sdhci_readw(host, MA35_SDHCI_MSHCCTL); + if (clock > MMC_HIGH_52_MAX_DTR) + ctl &= ~MA35_SDHCI_CMD_CONFLICT_CHK; + else + ctl |= MA35_SDHCI_CMD_CONFLICT_CHK; + sdhci_writew(host, ctl, MA35_SDHCI_MSHCCTL); + + sdhci_set_clock(host, clock); +} + +static int ma35_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct ma35_priv *priv = sdhci_pltfm_priv(pltfm_host); + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_180: + if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_uhs)) + pinctrl_select_state(priv->pinctrl, priv->pins_uhs); + break; + case MMC_SIGNAL_VOLTAGE_330: + if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_default)) + pinctrl_select_state(priv->pinctrl, priv->pins_default); + break; + default: + dev_err(mmc_dev(host->mmc), "Unsupported signal voltage!\n"); + return -EINVAL; + } + + return sdhci_start_signal_voltage_switch(mmc, ios); +} + +static void ma35_voltage_switch(struct sdhci_host *host) +{ + /* Wait for 5ms after set 1.8V signal enable bit */ + fsleep(5000); +} + +static int ma35_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct ma35_priv *priv = sdhci_pltfm_priv(pltfm_host); + int idx; + u32 regs[ARRAY_SIZE(restore_data)] = {}; + + /* + * Limitations require a reset of SD/eMMC before tuning and + * saving the registers before resetting, then restoring + * after the reset. + */ + for (idx = 0; idx < ARRAY_SIZE(restore_data); idx++) { + if (restore_data[idx].width == sizeof(u32)) + regs[idx] = sdhci_readl(host, restore_data[idx].reg); + else if (restore_data[idx].width == sizeof(u16)) + regs[idx] = sdhci_readw(host, restore_data[idx].reg); + else if (restore_data[idx].width == sizeof(u8)) + regs[idx] = sdhci_readb(host, restore_data[idx].reg); + } + + reset_control_assert(priv->rst); + reset_control_deassert(priv->rst); + + for (idx = 0; idx < ARRAY_SIZE(restore_data); idx++) { + if (restore_data[idx].width == sizeof(u32)) + sdhci_writel(host, regs[idx], restore_data[idx].reg); + else if (restore_data[idx].width == sizeof(u16)) + sdhci_writew(host, regs[idx], restore_data[idx].reg); + else if (restore_data[idx].width == sizeof(u8)) + sdhci_writeb(host, regs[idx], restore_data[idx].reg); + } + + return sdhci_execute_tuning(mmc, opcode); +} + +static const struct sdhci_ops sdhci_ma35_ops = { + .set_clock = ma35_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .reset = sdhci_reset, + .adma_write_desc = ma35_adma_write_desc, + .voltage_switch = ma35_voltage_switch, +}; + +static const struct sdhci_pltfm_data sdhci_ma35_pdata = { + .ops = &sdhci_ma35_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_BROKEN_DDR50 | + SDHCI_QUIRK2_ACMD23_BROKEN, +}; + +static int ma35_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + struct ma35_priv *priv; + int err; + u32 extra, ctl; + + host = sdhci_pltfm_init(pdev, &sdhci_ma35_pdata, sizeof(struct ma35_priv)); + if (IS_ERR(host)) + return PTR_ERR(host); + + /* Extra adma table cnt for cross 128M boundary handling. */ + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M); + extra = min(extra, SDHCI_MAX_SEGS); + + host->adma_table_cnt += extra; + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + + pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(pltfm_host->clk)) { + err = dev_err_probe(dev, PTR_ERR(pltfm_host->clk), "failed to get clk\n"); + goto err_sdhci; + } + + err = mmc_of_parse(host->mmc); + if (err) + goto err_sdhci; + + priv->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(priv->rst)) { + err = dev_err_probe(dev, PTR_ERR(priv->rst), "failed to get reset control\n"); + goto err_sdhci; + } + + sdhci_get_of_property(pdev); + + priv->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR(priv->pinctrl)) { + priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default"); + priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, "state_uhs"); + pinctrl_select_state(priv->pinctrl, priv->pins_default); + } + + if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)) { + struct regmap *regmap; + u32 reg; + + regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sys"); + if (!IS_ERR(regmap)) { + /* Enable SDHCI voltage stable for 1.8V */ + regmap_read(regmap, MA35_SYS_MISCFCR0, ®); + reg |= BIT(17); + regmap_write(regmap, MA35_SYS_MISCFCR0, reg); + } + + host->mmc_host_ops.start_signal_voltage_switch = + ma35_start_signal_voltage_switch; + } + + host->mmc_host_ops.execute_tuning = ma35_execute_tuning; + + err = sdhci_add_host(host); + if (err) + goto err_sdhci; + + /* + * Split data into chunks of 16 or 8 bytes for transmission. + * Each chunk transfer is guaranteed to be uninterrupted on the bus. + * This likely corresponds to the AHB bus DMA burst size. + */ + ctl = sdhci_readw(host, MA35_SDHCI_MBIUCTL); + ctl &= ~MA35_SDHCI_INCR_MSK; + ctl |= MA35_SDHCI_INCR16 | MA35_SDHCI_INCR8; + sdhci_writew(host, ctl, MA35_SDHCI_MBIUCTL); + + return 0; + +err_sdhci: + sdhci_pltfm_free(pdev); + return err; +} + +static void ma35_disable_card_clk(struct sdhci_host *host) +{ + u16 ctrl; + + ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (ctrl & SDHCI_CLOCK_CARD_EN) { + ctrl &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL); + } +} + +static void ma35_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + + sdhci_remove_host(host, 0); + ma35_disable_card_clk(host); + sdhci_pltfm_free(pdev); +} + +static const struct of_device_id sdhci_ma35_dt_ids[] = { + { .compatible = "nuvoton,ma35d1-sdhci" }, + {} +}; + +static struct platform_driver sdhci_ma35_driver = { + .driver = { + .name = "sdhci-ma35", + .of_match_table = sdhci_ma35_dt_ids, + }, + .probe = ma35_probe, + .remove_new = ma35_remove, +}; +module_platform_driver(sdhci_ma35_driver); + +MODULE_DESCRIPTION("SDHCI platform driver for Nuvoton MA35"); +MODULE_AUTHOR("Shan-Chun Hung <shanchun1218@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index b75cbea88b40..7b957f6d5588 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -126,7 +126,7 @@ static void pxav1_request_done(struct sdhci_host *host, struct mmc_request *mrq) struct sdhci_pxav2_host *pxav2_host; /* If this is an SDIO command, perform errata workaround for silicon bug */ - if (mrq->cmd && !mrq->cmd->error && + if (!mrq->cmd->error && (mrq->cmd->opcode == SD_IO_RW_DIRECT || mrq->cmd->opcode == SD_IO_RW_EXTENDED)) { /* Reset data port */ diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 64e10f7c9faa..0aa3c40ea6ed 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -86,6 +86,7 @@ #define CLOCK_TOO_SLOW_HZ 50000000 #define SDHCI_AM654_AUTOSUSPEND_DELAY -1 +#define RETRY_TUNING_MAX 10 /* Command Queue Host Controller Interface Base address */ #define SDHCI_AM654_CQE_BASE_ADDR 0x200 @@ -151,6 +152,7 @@ struct sdhci_am654_data { u32 flags; u32 quirks; bool dll_enable; + u32 tuning_loop; #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) }; @@ -443,7 +445,7 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) #define ITAPDLY_LENGTH 32 #define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1) -static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window +static int sdhci_am654_calculate_itap(struct sdhci_host *host, struct window *fail_window, u8 num_fails, bool circular_buffer) { u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0; @@ -453,12 +455,16 @@ static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window int prev_fail_end = -1; u8 i; - if (!num_fails) - return ITAPDLY_LAST_INDEX >> 1; + if (!num_fails) { + /* Retry tuning */ + dev_dbg(dev, "No failing region found, retry tuning\n"); + return -1; + } if (fail_window->length == ITAPDLY_LENGTH) { - dev_err(dev, "No passing ITAPDLY, return 0\n"); - return 0; + /* Retry tuning */ + dev_dbg(dev, "No passing itapdly, retry tuning\n"); + return -1; } first_fail_start = fail_window->start; @@ -494,13 +500,14 @@ static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap; } -static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, - u32 opcode) +static int sdhci_am654_do_tuning(struct sdhci_host *host, + u32 opcode) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; struct window fail_window[ITAPDLY_LENGTH]; + struct device *dev = mmc_dev(host->mmc); u8 curr_pass, itap; u8 fail_index = 0; u8 prev_pass = 1; @@ -521,6 +528,7 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, if (!curr_pass) { fail_window[fail_index].end = itap; fail_window[fail_index].length++; + dev_dbg(dev, "Failed itapdly=%d\n", itap); } if (curr_pass && !prev_pass) @@ -532,13 +540,34 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, if (fail_window[fail_index].length != 0) fail_index++; - itap = sdhci_am654_calculate_itap(host, fail_window, fail_index, - sdhci_am654->dll_enable); + return sdhci_am654_calculate_itap(host, fail_window, fail_index, + sdhci_am654->dll_enable); +} - sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); +static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, + u32 opcode) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + unsigned char timing = host->mmc->ios.timing; + struct device *dev = mmc_dev(host->mmc); + int itapdly; + + do { + itapdly = sdhci_am654_do_tuning(host, opcode); + if (itapdly >= 0) + break; + } while (++sdhci_am654->tuning_loop < RETRY_TUNING_MAX); + + if (itapdly < 0) { + dev_err(dev, "Failed to find itapdly, fail tuning\n"); + return -1; + } + dev_dbg(dev, "Passed tuning, final itapdly=%d\n", itapdly); + sdhci_am654_write_itapdly(sdhci_am654, itapdly, sdhci_am654->itap_del_ena[timing]); /* Save ITAPDLY */ - sdhci_am654->itap_del_sel[timing] = itap; + sdhci_am654->itap_del_sel[timing] = itapdly; return 0; } @@ -742,6 +771,9 @@ static int sdhci_am654_init(struct sdhci_host *host) regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, TUNINGFORSDR50_MASK); + /* Use to re-execute tuning */ + sdhci_am654->tuning_loop = 0; + ret = sdhci_setup_host(host); if (ret) return ret; diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index b359876cc33d..45a474ccab1c 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -895,8 +895,8 @@ static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd) * It seems, VccQ should be switched on after Vcc, this is also what the * omap_hsmmc.c driver does. */ - if (!IS_ERR(mmc->supply.vqmmc) && !ret) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!ret) { + ret = mmc_regulator_enable_vqmmc(mmc); usleep_range(200, 300); } @@ -909,8 +909,7 @@ static void tmio_mmc_power_off(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; - if (!IS_ERR(mmc->supply.vqmmc)) - regulator_disable(mmc->supply.vqmmc); + mmc_regulator_disable_vqmmc(mmc); if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); |