From 98d5fd391544e21bbf13174f4ac1cc372ee7d604 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Fri, 10 Jan 2014 10:05:32 +0100 Subject: mci: Support the correct version for eMMC eMMC is available up to version 4.5 but the correct version is not decoded. Change version definitions to support more minor verions, add missing versions and parse the minor versions from ext_csd. After this, card detection code and devinfo reports correct versions. Handling is inspired by u-boot code. Signed-off-by: Markus Niebel Signed-off-by: Sascha Hauer --- drivers/mci/mci-core.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index a232679571..9bdcdbec6c 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -695,7 +695,6 @@ static void mci_set_bus_width(struct mci *mci, unsigned width) static void mci_detect_version_from_csd(struct mci *mci) { int version; - char *vstr; if (mci->version == MMC_VERSION_UNKNOWN) { /* the version is coded in the bits 127:126 (left aligned) */ @@ -703,32 +702,52 @@ static void mci_detect_version_from_csd(struct mci *mci) switch (version) { case 0: - vstr = "1.2"; mci->version = MMC_VERSION_1_2; break; case 1: - vstr = "1.4"; mci->version = MMC_VERSION_1_4; break; case 2: - vstr = "2.2"; mci->version = MMC_VERSION_2_2; break; case 3: - vstr = "3.0"; mci->version = MMC_VERSION_3; break; case 4: - vstr = "4.0"; mci->version = MMC_VERSION_4; break; default: - vstr = "unknown, fallback to 1.2"; + printf("unknown card version, fallback to 1.2\n"); mci->version = MMC_VERSION_1_2; break; } + } +} - dev_info(&mci->dev, "detected card version %s\n", vstr); +/** + * correct the version from ext_csd data if it's not an SD-card, detected + * version is at least 4 and we have ext_csd data + */ +static void mci_correct_version_from_ext_csd(struct mci *mci) +{ + if (!IS_SD(mci) && (mci->version >= MMC_VERSION_4) && mci->ext_csd) { + switch (mci->ext_csd[EXT_CSD_REV]) { + case 1: + mci->version = MMC_VERSION_4_1; + break; + case 2: + mci->version = MMC_VERSION_4_2; + break; + case 3: + mci->version = MMC_VERSION_4_3; + break; + case 5: + mci->version = MMC_VERSION_4_41; + break; + case 6: + mci->version = MMC_VERSION_4_5; + break; + } } } @@ -1093,6 +1112,9 @@ static int mci_startup(struct mci *mci) if (err) return err; + mci_correct_version_from_ext_csd(mci); + printf("detected %s card version %d.%d\n", IS_SD(mci) ? "SD" : "MMC", + (mci->version >> 8) & 0xf, mci->version & 0xff); mci_extract_card_capacity_from_csd(mci); if (IS_SD(mci)) -- cgit v1.2.3 From 96da2169915df634e113e444c357d0cde7c054b8 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Fri, 10 Jan 2014 10:05:33 +0100 Subject: mci: production year for eMMC 4.41 and later Year is coded in 4 bits of CID. eMMC 4.41 adds a new interpretation rule: production year for 4.41 cards and newer is between 2010 and 2025 with 0 corresponding to 2013. This fix was inspired by currect kernel code. Signed-off-by: Markus Niebel Signed-off-by: Sascha Hauer --- drivers/mci/mci-core.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 9bdcdbec6c..7161af10e6 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -717,7 +717,7 @@ static void mci_detect_version_from_csd(struct mci *mci) mci->version = MMC_VERSION_4; break; default: - printf("unknown card version, fallback to 1.2\n"); + printf("unknown card version, fallback to 1.02\n"); mci->version = MMC_VERSION_1_2; break; } @@ -1398,10 +1398,17 @@ static unsigned extract_mtd_month(struct mci *mci) */ static unsigned extract_mtd_year(struct mci *mci) { + unsigned year; if (IS_SD(mci)) - return UNSTUFF_BITS(mci->cid, 12, 8) + 2000; - else + year = UNSTUFF_BITS(mci->cid, 12, 8) + 2000; + else if (mci->version < MMC_VERSION_4_41) return UNSTUFF_BITS(mci->cid, 8, 4) + 1997; + else { + year = UNSTUFF_BITS(mci->cid, 8, 4) + 1997; + if (year < 2010) + year += 16; + } + return year; } static void mci_print_caps(unsigned caps) @@ -1448,7 +1455,7 @@ static void mci_info(struct device_d *dev) (mci->version >> 4) & 0xf, mci->version & 0xf); } else { printf(" Attached is an SD Card (Version: %u.%u)\n", - (mci->version >> 4) & 0xf, mci->version & 0xf); + (mci->version >> 8) & 0xf, mci->version & 0xff); } printf(" Capacity: %u MiB\n", (unsigned)(mci->capacity >> 20)); -- cgit v1.2.3 From 78b9e4e041461047ffb27f4a12c8c7346ca34149 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Tue, 14 Jan 2014 09:23:34 +0100 Subject: mci: add DSR support The eMMC and the SD-Card specifications describe the optional SET_DSR command. During measurements at our lab we found that some cards implementing this feature having really strong driver strengts per default. This can lead to voltage peaks above the specification of the host on signal edges for data sent from a card to the host. Since availability of a given card type may be shorter than the time a certain hardware will be produced it is useful to have support for this command (Alternative would be changing termination resistors and adapting the driver strength of the host to the used card.) Signed-off-by: Markus Niebel Signed-off-by: Sascha Hauer --- drivers/mci/mci-core.c | 27 +++++++++++++++++++++++++++ include/mci.h | 3 +++ 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 7161af10e6..12611090ff 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -101,6 +101,20 @@ static void mci_setup_cmd(struct mci_cmd *p, unsigned cmd, unsigned arg, unsigne p->resp_type = response; } +/** + * configure optional DSR value + * @param mci_dev MCI instance + * @return Transaction status (0 on success) + */ +static int mci_set_dsr(struct mci *mci) +{ + struct mci_cmd cmd; + + mci_setup_cmd(&cmd, MMC_CMD_SET_DSR, + (mci->host->dsr_val >> 16) | 0xffff, MMC_RSP_NONE); + return mci_send_cmd(mci, &cmd, NULL); +} + /** * Setup SD/MMC card's blocklength to be used for future transmitts * @param mci_dev MCI instance @@ -855,6 +869,15 @@ static void mci_extract_card_capacity_from_csd(struct mci *mci) dev_dbg(&mci->dev, "Capacity: %u MiB\n", (unsigned)(mci->capacity >> 20)); } +/** + * Extract card's DSR implementation state from CSD + * @param mci MCI instance + */ +static void mci_extract_card_dsr_imp_from_csd(struct mci *mci) +{ + mci->dsr_imp = UNSTUFF_BITS(mci->csd, 76, 1); +} + static int mmc_compare_ext_csds(struct mci *mci, unsigned bus_width) { u8 *bw_ext_csd; @@ -1077,6 +1100,7 @@ static int mci_startup(struct mci *mci) mci_detect_version_from_csd(mci); mci_extract_max_tran_speed_from_csd(mci); mci_extract_block_lengths_from_csd(mci); + mci_extract_card_dsr_imp_from_csd(mci); /* sanitiy? */ if (mci->read_bl_len > SECTOR_SIZE) { @@ -1093,6 +1117,9 @@ static int mci_startup(struct mci *mci) dev_dbg(&mci->dev, "Read block length: %u, Write block length: %u\n", mci->read_bl_len, mci->write_bl_len); + if (mci->dsr_imp && mci->host->use_dsr) + mci_set_dsr(mci); + if (!mmc_host_is_spi(host)) { /* cmd not supported in spi */ dev_dbg(&mci->dev, "Select the card, and put it into Transfer Mode\n"); /* Select the card, and put it into Transfer Mode */ diff --git a/include/mci.h b/include/mci.h index 65f90ca34e..40a712b4dc 100644 --- a/include/mci.h +++ b/include/mci.h @@ -299,6 +299,8 @@ struct mci_host { unsigned clock; /**< Current clock used to talk to the card */ unsigned bus_width; /**< used data bus width to the card */ unsigned max_req_size; + unsigned dsr_val; /**< optional dsr value */ + int use_dsr; /**< optional dsr usage flag */ /** init the host interface */ int (*init)(struct mci_host*, struct device_d*); @@ -349,6 +351,7 @@ struct mci { unsigned write_bl_len; uint64_t capacity; /**< Card's data capacity in bytes */ int ready_for_use; /** true if already probed */ + int dsr_imp; /**< DSR implementation state from CSD */ char *ext_csd; int probe; struct param_d *param_probe; -- cgit v1.2.3 From f11668fee725f59ab13e40f58f46ab7e65205457 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Tue, 14 Jan 2014 09:23:35 +0100 Subject: mci: add device tree support for DSR add optional DSR support. This should go into the kernel, too Signed-off-by: Markus Niebel Signed-off-by: Sascha Hauer --- drivers/mci/mci-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 12611090ff..cf38a88a9b 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -1775,6 +1775,7 @@ void mci_of_parse(struct mci_host *host) { struct device_node *np; u32 bus_width; + u32 dsr_val; if (!IS_ENABLED(CONFIG_OFDEVICE)) return; @@ -1807,4 +1808,11 @@ void mci_of_parse(struct mci_host *host) /* f_max is obtained from the optional "max-frequency" property */ of_property_read_u32(np, "max-frequency", &host->f_max); + + if (!of_property_read_u32(np, "dsr", &dsr_val)) { + if (dsr_val < 0x10000) { + host->use_dsr = 1; + host->dsr_val = dsr_val; + } + } } -- cgit v1.2.3 From fa5bdb30ee38f815a979182bc6efa5e0791dadc6 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Tue, 14 Jan 2014 09:23:36 +0100 Subject: mci: imx-esdhc: add DSR support having DSR support in mci-core we need a way to forward the DSR value to the driver. Add it to platform data for imx-esdhc TODO: implement the same for other host controller drivers Signed-off-by: Markus Niebel Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/include/mach/esdhc.h | 2 ++ drivers/mci/imx-esdhc.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/arch/arm/mach-imx/include/mach/esdhc.h b/arch/arm/mach-imx/include/mach/esdhc.h index add1691c4b..fb7380a182 100644 --- a/arch/arm/mach-imx/include/mach/esdhc.h +++ b/arch/arm/mach-imx/include/mach/esdhc.h @@ -42,5 +42,7 @@ struct esdhc_platform_data { enum cd_types cd_type; unsigned caps; char *devname; + unsigned dsr_val; + int use_dsr; }; #endif /* __ASM_ARCH_IMX_ESDHC_H */ diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 7664e7be4c..4c7a45e722 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -582,6 +582,10 @@ static int fsl_esdhc_probe(struct device_d *dev) if (host->mci.f_min < 200000) host->mci.f_min = 200000; host->mci.f_max = rate; + if (pdata) { + host->mci.use_dsr = pdata->use_dsr; + host->mci.dsr_val = pdata->dsr_val; + } mci_of_parse(&host->mci); -- cgit v1.2.3