Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 284531
b: refs/heads/master
c: a4924c7
h: refs/heads/master
i:
  284529: 9299f6d
  284527: dd009a2
v: v3
  • Loading branch information
Girish K S authored and Chris Ball committed Jan 12, 2012
1 parent c2a3711 commit 5329fee
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ee5d19b20a711dca3848450979e3cd20b6b795cc
refs/heads/master: a4924c71aa43d4f8a3f342b1f71788349472e684
3 changes: 2 additions & 1 deletion trunk/drivers/mmc/core/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_ddr_mode(card) ? "DDR " : "",
type);
} else {
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
pr_info("%s: new %s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_uhs(card) ? "ultra high speed " :
(mmc_card_highspeed(card) ? "high speed " : ""),
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
type, card->rca);
}
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/mmc/core/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
case MMC_TIMING_UHS_DDR50:
str = "sd uhs DDR50";
break;
case MMC_TIMING_MMC_HS200:
str = "mmc high-speed SDR200";
break;
default:
str = "invalid";
break;
Expand Down
162 changes: 153 additions & 9 deletions trunk/drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
case EXT_CSD_CARD_TYPE_SDR_ALL:
case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
card->ext_csd.hs_max_dtr = 200000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
break;
case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
card->ext_csd.hs_max_dtr = 200000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
break;
case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
card->ext_csd.hs_max_dtr = 200000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
break;
case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
Expand Down Expand Up @@ -699,6 +720,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
return err;
}

/*
* Selects the desired buswidth and switch to the HS200 mode
* if bus width set without error
*/
static int mmc_select_hs200(struct mmc_card *card)
{
int idx, err = 0;
struct mmc_host *host;
static unsigned ext_csd_bits[] = {
EXT_CSD_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_8,
};
static unsigned bus_widths[] = {
MMC_BUS_WIDTH_4,
MMC_BUS_WIDTH_8,
};

BUG_ON(!card);

host = card->host;

if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
err = mmc_set_signal_voltage(host,
MMC_SIGNAL_VOLTAGE_180, 0);

/* If fails try again during next card power cycle */
if (err)
goto err;

idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;

/*
* Unlike SD, MMC cards dont have a configuration register to notify
* supported bus width. So bus test command should be run to identify
* the supported bus width or compare the ext csd values of current
* bus width and ext csd values of 1 bit mode read earlier.
*/
for (; idx >= 0; idx--) {

/*
* Host is capable of 8bit transfer, then switch
* the device to work in 8bit transfer mode. If the
* mmc switch command returns error then switch to
* 4bit transfer mode. On success set the corresponding
* bus width on the host.
*/
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx],
card->ext_csd.generic_cmd6_time);
if (err)
continue;

mmc_set_bus_width(card->host, bus_widths[idx]);

if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
err = mmc_compare_ext_csds(card, bus_widths[idx]);
else
err = mmc_bus_test(card, bus_widths[idx]);
if (!err)
break;
}

/* switch to HS200 mode if bus width set successfully */
if (!err)
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 2, 0);
err:
return err;
}

/*
* Handle the detection and initialisation of a card.
*
Expand Down Expand Up @@ -905,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
/*
* Activate high speed (if supported)
*/
if ((card->ext_csd.hs_max_dtr != 0) &&
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1,
card->ext_csd.generic_cmd6_time);
if (card->ext_csd.hs_max_dtr != 0) {
err = 0;
if (card->ext_csd.hs_max_dtr > 52000000 &&
host->caps2 & MMC_CAP2_HS200)
err = mmc_select_hs200(card);
else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1, 0);

if (err && err != -EBADMSG)
goto free_card;

Expand All @@ -918,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_hostname(card->host));
err = 0;
} else {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
if (card->ext_csd.hs_max_dtr > 52000000 &&
host->caps2 & MMC_CAP2_HS200) {
mmc_card_set_hs200(card);
mmc_set_timing(card->host,
MMC_TIMING_MMC_HS200);
} else {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
}
}
}

Expand All @@ -944,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
max_dtr = (unsigned int)-1;

if (mmc_card_highspeed(card)) {
if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
} else if (max_dtr > card->csd.max_dtr) {
Expand All @@ -969,10 +1074,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
ddr = MMC_1_2V_DDR_MODE;
}

/*
* Indicate HS200 SDR mode (if supported).
*/
if (mmc_card_hs200(card)) {
u32 ext_csd_bits;
u32 bus_width = card->host->ios.bus_width;

/*
* For devices supporting HS200 mode, the bus width has
* to be set before executing the tuning function. If
* set before tuning, then device will respond with CRC
* errors for responses on CMD line. So for HS200 the
* sequence will be
* 1. set bus width 4bit / 8 bit (1 bit not supported)
* 2. switch to HS200 mode
* 3. set the clock to > 52Mhz <=200MHz and
* 4. execute tuning for HS200
*/
if ((host->caps2 & MMC_CAP2_HS200) &&
card->host->ops->execute_tuning)
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK_HS200);
if (err) {
pr_warning("%s: tuning execution failed\n",
mmc_hostname(card->host));
goto err;
}

ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
if (err) {
pr_err("%s: power class selection to bus width %d failed\n",
mmc_hostname(card->host), 1 << bus_width);
goto err;
}
}

/*
* Activate wide bus and DDR (if supported).
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
if (!mmc_card_hs200(card) &&
(card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
static unsigned ext_csd_bits[][2] = {
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
Expand Down
3 changes: 2 additions & 1 deletion trunk/drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)

/* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
err = card->host->ops->execute_tuning(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);

out:
kfree(status);
Expand Down
4 changes: 3 additions & 1 deletion trunk/drivers/mmc/core/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
Expand Down Expand Up @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)

/* Initialize and start re-tuning timer */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
err = card->host->ops->execute_tuning(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);

out:

Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/mmc/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ struct mmc_card {
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
Expand Down Expand Up @@ -374,6 +375,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
Expand All @@ -384,6 +386,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#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_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_hs200(c) ((c)->state |= MMC_STATE_HIGHSPEED_200)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
Expand Down
11 changes: 10 additions & 1 deletion trunk/include/linux/mmc/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ struct mmc_ios {
#define MMC_TIMING_UHS_SDR50 3
#define MMC_TIMING_UHS_SDR104 4
#define MMC_TIMING_UHS_DDR50 5
#define MMC_TIMING_MMC_HS200 6

#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
#define MMC_1_8V_DDR_MODE 2
#define MMC_1_2V_SDR_MODE 3
#define MMC_1_8V_SDR_MODE 4

unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */

Expand Down Expand Up @@ -148,7 +151,9 @@ struct mmc_host_ops {
void (*init_card)(struct mmc_host *host, struct mmc_card *card);

int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
int (*execute_tuning)(struct mmc_host *host);

/* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
Expand Down Expand Up @@ -248,6 +253,10 @@ struct mmc_host {
#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */
#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR)

mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
Expand Down
Loading

0 comments on commit 5329fee

Please sign in to comment.