According SD spec (5.2[2]) to do SDUC support 1)Mutual identification of SDUC in ACMD41 initialization (5.2.1[2]) sd.c mmc_sd_get_cid(): if the host support SDUC set HO2T to ocr mmc_sd_init_card(): if the card rsp support SDUC by CO2T, do mmc_card_set_ultra_capacity() 2)SDUC card user area capacity calculation (5.2.2[2]) sd.c mmc_decode_csd(): Add the SDUC card csd parser 3)Memory read/write commands sequence (5.2.3[2]) block.c mmc_blk_rw_rq_prep(): Prepare CMD22 for the SDUC card R/W 4)Erase Commands Sequence (5.2.4[2]) core.c Add CMD22 to erase flow for the SDUC card 5)Card type bus.c mmc_add_card(): Add SDUC to type if the card is SDUC card Signed-off-by: Ricky Wu <ricky_wu@xxxxxxxxxxx> --- drivers/mmc/core/block.c | 13 +++++++++-- drivers/mmc/core/bus.c | 4 +++- drivers/mmc/core/core.c | 38 ++++++++++++++++++++++---------- drivers/mmc/core/sd.c | 47 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 367509b5b646..45c06055882a 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1153,7 +1153,7 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - unsigned int from, nr; + unsigned long long from, nr; int err = 0; blk_status_t status = BLK_STS_OK; @@ -1208,7 +1208,7 @@ static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - unsigned int from, nr, arg; + unsigned long long from, nr, arg; int err = 0, type = MMC_BLK_SECDISCARD; blk_status_t status = BLK_STS_OK; @@ -1713,6 +1713,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; brq->mrq.sbc = &brq->sbc; } + + if (mmc_card_ultra_capacity(card)) { + brq->ae.opcode = SD_ADDR_EXT; + brq->ae.arg = (blk_rq_pos(req) >> 32) & 0x3F; + brq->ae.flags = MMC_RSP_R1 | MMC_CMD_AC; + brq->mrq.ae = &brq->ae; + } else { + brq->mrq.ae = NULL; + } } #define MMC_MAX_RETRIES 5 diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 0ddaee0eae54..2356f404374c 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -321,7 +321,9 @@ int mmc_add_card(struct mmc_card *card) case MMC_TYPE_SD: type = "SD"; if (mmc_card_blockaddr(card)) { - if (mmc_card_ext_capacity(card)) + if (mmc_card_ultra_capacity(card)) + type = "SDUC"; + else if (mmc_card_ext_capacity(card)) type = "SDXC"; else type = "SDHC"; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a8c17b4cd737..23effc691833 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1598,8 +1598,8 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card, return mmc_mmc_erase_timeout(card, arg, qty); } -static int mmc_do_erase(struct mmc_card *card, unsigned int from, - unsigned int to, unsigned int arg) +static int mmc_do_erase(struct mmc_card *card, unsigned long long from, + unsigned long long to, unsigned int arg) { struct mmc_command cmd = {}; unsigned int qty = 0, busy_timeout = 0; @@ -1638,6 +1638,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, to <<= 9; } + if (mmc_card_ultra_capacity(card)) { + cmd.opcode = SD_ADDR_EXT; + cmd.arg = (from >> 32) & 0x3F; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, 0); + } + + memset(&cmd, 0, sizeof(struct mmc_command)); if (mmc_card_sd(card)) cmd.opcode = SD_ERASE_WR_BLK_START; else @@ -1652,6 +1660,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, goto out; } + memset(&cmd, 0, sizeof(struct mmc_command)); + if (mmc_card_ultra_capacity(card)) { + cmd.opcode = SD_ADDR_EXT; + cmd.arg = (to >> 32) & 0x3F; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, 0); + } + memset(&cmd, 0, sizeof(struct mmc_command)); if (mmc_card_sd(card)) cmd.opcode = SD_ERASE_WR_BLK_END; @@ -1700,18 +1716,18 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, } static unsigned int mmc_align_erase_size(struct mmc_card *card, - unsigned int *from, - unsigned int *to, - unsigned int nr) + unsigned long long *from, + unsigned long long *to, + unsigned long long nr) { - unsigned int from_new = *from, nr_new = nr, rem; + unsigned long long from_new = *from, nr_new = nr, rem; /* * When the 'card->erase_size' is power of 2, we can use round_up/down() * to align the erase size efficiently. */ if (is_power_of_2(card->erase_size)) { - unsigned int temp = from_new; + unsigned long long temp = from_new; from_new = round_up(temp, card->erase_size); rem = from_new - temp; @@ -1756,10 +1772,10 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, * * Caller must claim host before calling this function. */ -int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, +int mmc_erase(struct mmc_card *card, unsigned long long from, unsigned long long nr, unsigned int arg) { - unsigned int rem, to = from + nr; + unsigned long long rem, to = from + nr; int err; if (!(card->csd.cmdclass & CCC_ERASE)) @@ -1863,8 +1879,8 @@ int mmc_can_secure_erase_trim(struct mmc_card *card) } EXPORT_SYMBOL(mmc_can_secure_erase_trim); -int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, - unsigned int nr) +int mmc_erase_group_aligned(struct mmc_card *card, unsigned long long from, + unsigned long long nr) { if (!card->erase_size) return 0; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 1c8148cdda50..7eacfd912dff 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -121,6 +121,12 @@ static int mmc_decode_csd(struct mmc_card *card) csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 2 && mmc_card_ultra_capacity(card)) { + pr_err("%s: invalid CSD structure version %d on SDUC\n", + mmc_hostname(card->host), csd_struct); + return -EINVAL; + } + switch (csd_struct) { case 0: m = UNSTUFF_BITS(resp, 115, 4); @@ -190,6 +196,35 @@ static int mmc_decode_csd(struct mmc_card *card) csd->write_partial = 0; csd->erase_size = 1; + if (UNSTUFF_BITS(resp, 13, 1)) + mmc_card_set_readonly(card); + break; + case 2: + /* + * This is a block-addressed SDUC card. + */ + mmc_card_set_blockaddr(card); + + csd->taac_ns = 0; /* Unused */ + csd->taac_clks = 0; /* Unused */ + + 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, 28); + m = UNSTUFF_BITS(resp, 48, 28); + csd->capacity = (unsigned long long)(1 + m) << 10; + + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; + csd->read_misalign = 0; + csd->r2w_factor = 4; /* Unused */ + csd->write_blkbits = 9; + csd->write_partial = 0; + csd->erase_size = 1; + if (UNSTUFF_BITS(resp, 13, 1)) mmc_card_set_readonly(card); break; @@ -859,6 +894,14 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) if (max_current > 150) ocr |= SD_OCR_XPC; + /* + * To avoid data corruption via address space mismatch, mutual + * recognition mechanism is implemented via ACMD41 initialization, + * If the host support SDUC card, HO2T should be set to 1. + */ + if (mmc_host_sduc(host)) + ocr |= SD_OCR_HO2T; + err = mmc_send_app_op_cond(host, ocr, rocr); if (err) return err; @@ -1433,6 +1476,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, card->ocr = ocr; card->type = MMC_TYPE_SD; + + if (!mmc_host_is_spi(host) && (rocr & SD_ROCR_CO2T)) + mmc_card_set_ultra_capacity(card); + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); } -- 2.25.1