mmc: sd: SDUC Support Recognition

[ Upstream commit fce2ce78af1e14dc1316aaddb5b3308be05cf452 ]

Ultra Capacity SD cards (SDUC) was already introduced in SD7.0.  Those
cards support capacity larger than 2TB and up to including 128TB.

ACMD41 was extended to support the host-card handshake during
initialization.  The card expects that the HCS & HO2T bits to be set in
the command argument, and sets the applicable bits in the R3 returned
response.  On the contrary, if a SDUC card is inserted to a
non-supporting host, it will never respond to this ACMD41 until
eventually, the host will timed out and give up.

Also, add SD CSD version 3.0 - designated for SDUC, and properly parse
the csd register as the c_size field got expanded to 28 bits.

Do not enable SDUC for now - leave it to the last patch in the series.

Tested-by: Ricky WU <ricky_wu@realtek.com>
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Avri Altman <avri.altman@wdc.com>
Link: https://lore.kernel.org/r/20241006051148.160278-2-avri.altman@wdc.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Stable-dep-of: 869d37475788 ("mmc: core: Use GFP_NOIO in ACMD22")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Avri Altman
2024-10-06 08:11:39 +03:00
committed by Greg Kroah-Hartman
parent f42e0656d4
commit c00372e41b
7 changed files with 27 additions and 15 deletions

View File

@@ -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_ult_capacity(card))
type = "SDUC";
else if (mmc_card_ext_capacity(card))
type = "SDXC";
else
type = "SDHC";

View File

@@ -23,6 +23,7 @@
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */
#define MMC_CARD_SDUC (1<<6) /* card is SDUC */
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
@@ -30,11 +31,13 @@
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
#define mmc_card_ult_capacity(c) ((c)->state & MMC_CARD_SDUC)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_ult_capacity(c) ((c)->state |= MMC_CARD_SDUC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)

View File

@@ -100,7 +100,7 @@ void mmc_decode_cid(struct mmc_card *card)
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
static int mmc_decode_csd(struct mmc_card *card)
static int mmc_decode_csd(struct mmc_card *card, bool is_sduc)
{
struct mmc_csd *csd = &card->csd;
unsigned int e, m, csd_struct;
@@ -144,9 +144,10 @@ static int mmc_decode_csd(struct mmc_card *card)
mmc_card_set_readonly(card);
break;
case 1:
case 2:
/*
* This is a block-addressed SDHC or SDXC card. Most
* interesting fields are unused and have fixed
* This is a block-addressed SDHC, SDXC or SDUC card.
* Most interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards,
* we assume those fixed values ourselves.
*/
@@ -159,14 +160,19 @@ static int mmc_decode_csd(struct mmc_card *card)
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);
/* SDXC cards have a minimum C_SIZE of 0x00FFFF */
if (csd->c_size >= 0xFFFF)
if (csd_struct == 1)
m = unstuff_bits(resp, 48, 22);
else
m = unstuff_bits(resp, 48, 28);
csd->c_size = m;
if (csd->c_size >= 0x400000 && is_sduc)
mmc_card_set_ult_capacity(card);
else if (csd->c_size >= 0xFFFF)
mmc_card_set_ext_capacity(card);
m = unstuff_bits(resp, 48, 22);
csd->capacity = (1 + m) << 10;
csd->capacity = (1 + (typeof(sector_t))m) << 10;
csd->read_blkbits = 9;
csd->read_partial = 0;
@@ -876,7 +882,7 @@ try_again:
return err;
}
int mmc_sd_get_csd(struct mmc_card *card)
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc)
{
int err;
@@ -887,7 +893,7 @@ int mmc_sd_get_csd(struct mmc_card *card)
if (err)
return err;
err = mmc_decode_csd(card);
err = mmc_decode_csd(card, is_sduc);
if (err)
return err;
@@ -1442,7 +1448,7 @@ retry:
}
if (!oldcard) {
err = mmc_sd_get_csd(card);
err = mmc_sd_get_csd(card, false);
if (err)
goto free_card;

View File

@@ -10,7 +10,7 @@ struct mmc_host;
struct mmc_card;
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
int mmc_sd_get_csd(struct mmc_card *card);
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc);
void mmc_decode_cid(struct mmc_card *card);
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
bool reinit);

View File

@@ -769,7 +769,7 @@ try_again:
* Read CSD, before selecting the card
*/
if (!oldcard && mmc_card_sd_combo(card)) {
err = mmc_sd_get_csd(card);
err = mmc_sd_get_csd(card, false);
if (err)
goto remove;

View File

@@ -35,7 +35,7 @@ struct mmc_csd {
unsigned int wp_grp_size;
unsigned int read_blkbits;
unsigned int write_blkbits;
unsigned int capacity;
sector_t capacity;
unsigned int read_partial:1,
read_misalign:1,
write_partial:1,

View File

@@ -36,6 +36,7 @@
/* OCR bit definitions */
#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
#define SD_OCR_2T (1 << 27) /* HO2T/CO2T - SDUC support */
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */