From patchwork Sat Nov 27 19:00:19 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip Rakity X-Patchwork-Id: 361602 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oARJ0P1Y015584 for ; Sat, 27 Nov 2010 19:00:26 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752217Ab0K0TAZ (ORCPT ); Sat, 27 Nov 2010 14:00:25 -0500 Received: from na3sys009aog113.obsmtp.com ([74.125.149.209]:41267 "HELO na3sys009aog113.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752130Ab0K0TAY convert rfc822-to-8bit (ORCPT ); Sat, 27 Nov 2010 14:00:24 -0500 Received: from source ([65.219.4.129]) (using TLSv1) by na3sys009aob113.postini.com ([74.125.148.12]) with SMTP ID DSNKTPFVRfK1DlVQSb1ashVG+3N+BctpS1NW@postini.com; Sat, 27 Nov 2010 11:00:24 PST Received: from SC-vEXCH3.marvell.com ([10.93.76.133]) by SC-OWA01.marvell.com ([10.93.76.21]) with mapi; Sat, 27 Nov 2010 11:00:20 -0800 From: Philip Rakity To: linux-mmc CC: Takashi Iwai Date: Sat, 27 Nov 2010 11:00:19 -0800 Subject: [PATCH] mmc: Resubmit: Bus Width testing for eMMC and MMC Cards Thread-Topic: [PATCH] mmc: Resubmit: Bus Width testing for eMMC and MMC Cards Thread-Index: AcuOZVaNJBvZZm7LTWG/qtns48zveQ== Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Sat, 27 Nov 2010 19:00:26 +0000 (UTC) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 77f93c3..d20237b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -531,12 +531,57 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Activate wide bus and DDR (if supported). + * Determine mmc bus width supported by probing card (if supported) */ if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { unsigned ext_csd_bit, bus_width; + int temp_caps = host->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA); - if (host->caps & MMC_CAP_8_BIT_DATA) { + do { + if (temp_caps & MMC_CAP_8_BIT_DATA) { + ext_csd_bit = EXT_CSD_BUS_WIDTH_8; + bus_width = MMC_BUS_WIDTH_8; + } else { + ext_csd_bit = EXT_CSD_BUS_WIDTH_4; + bus_width = MMC_BUS_WIDTH_4; + } + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, ext_csd_bit); + if (err) { + printk(KERN_WARNING "%s: switch to bus width %d ddr %d " + "failed\n", mmc_hostname(card->host), + 1 << bus_width, ddr); + err = 0; + } else { + mmc_set_bus_width_ddr(card->host, bus_width, MMC_SDR_MODE); + /* + * if controller can't handle bus width test + * try to use the highest bus width to + * maintain compatibility with previous linux + */ + if ((host->caps & MMC_CAP_BUS_WIDTH_WORKS) == 0) + break; + if (mmc_test_bus_width (card, 1<host, &mrq); + + if (cmd.error || data.error ) { + printk(KERN_INFO "%s: Failed to send (BUSTEST_W) CMD19: %d %d\n", + mmc_hostname(card->host), cmd.error, data.error); + } + + /* Now read back */ + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + memset (&test_data_read, 0, sizeof(test_data_read)); + + cmd.opcode = MMC_BUSTEST_R; + cmd.arg = 0; + + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.flags = MMC_DATA_READ; + data.blksz = len; + data.blocks = 1; + data.sg = &sg; + data.sg_len = 1; + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, &test_data_read, len); + + data.timeout_ns = 0; + data.timeout_clks = 64; + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) { + printk(KERN_INFO "%s: Failed to send CMD14: %d %d\n", + mmc_hostname(card->host), cmd.error, data.error); + return 0; + } + +#if 0 +#warning PRINT RESULTS FROM CMD14 + printk (KERN_INFO "%s: Bits = %d, Got %02X %02X %02X %02X\n", __FUNCTION__, + bits, + test_data_read[0], + test_data_read[1], + test_data_read[2], + test_data_read[3]); +#endif + + switch (bits) { + case 8: + return (test_data_read[0] == 0xaa && test_data_read[1] == 0x55); + case 4: + return (test_data_read[0] == 0xa5); + case 1: + return (test_data_read[0] == 0x80); + } + return 0; +} + static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 653eb8e..c08b9ad 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -26,6 +26,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); +int mmc_test_bus_width(struct mmc_card *card, int bits); #endif diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 53496bb..1e3d9d2 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -169,6 +169,7 @@ struct mmc_host { #define MMC_CAP_1_2V_DDR (1 << 12) /* can support */ /* DDR mode at 1.2V */ +#define MMC_CAP_BUS_WIDTH_WORKS (1 << 13) /* CMD14/CMD19 bus width ok */ mmc_pm_flag_t pm_caps; /* supported pm features */ #ifdef CONFIG_MMC_CLKGATE diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 956fbd8..8e0d047 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -40,7 +40,9 @@ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUSTEST_R 14 /* adtc R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUSTEST_W 19 /* adtc R1 */ #define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ #define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */