Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdhci-bcm2708 performance, compatibility and reliability improvements #36

Merged
merged 9 commits into from
Jun 13, 2012
8 changes: 8 additions & 0 deletions drivers/mmc/card/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,14 @@ static const struct mmc_fixup blk_fixups[] =
MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23),

/*
* Some Micron MMC cards needs longer data read timeout than
* indicated in CSD.
*/
MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc,
MMC_QUIRK_LONG_READ_TIME),

END_FIXUP
};

Expand Down
30 changes: 22 additions & 8 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,14 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)

if (data->flags & MMC_DATA_WRITE)
/*
* The limit is really 250 ms, but that is
* insufficient for some crappy cards.
* The MMC spec "It is strongly recommended
* for hosts to implement more than 500ms
* timeout value even if the card indicates
* the 250ms maximum busy length." Even the
* previous value of 300ms is known to be
* insufficient for some cards.
*/
limit_us = 300000;
limit_us = 3000000;
else
limit_us = 100000;

Expand All @@ -411,6 +415,18 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
data->timeout_clks = 0;
}
}

/*
* Some cards require longer data read timeout than indicated in CSD.
* Address this by setting the read timeout to a "reasonably high"
* value. For the cards tested, 300ms has proven enough. If necessary,
* this value can be increased if other problematic cards require this.
*/
if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) {
data->timeout_ns = 300000000;
data->timeout_clks = 0;
}

/*
* Some cards need very high timeouts if driven in SPI mode.
* The worst observed timeout was 900ms after writing a
Expand Down Expand Up @@ -1119,13 +1135,11 @@ static void mmc_power_up(struct mmc_host *host)
bit = fls(host->ocr_avail) - 1;

host->ios.vdd = bit;
if (mmc_host_is_spi(host)) {
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
} else {
else
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
}
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
Expand Down
8 changes: 8 additions & 0 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
BUG_ON(!host);
WARN_ON(!host->claimed);

/* Set correct bus mode for MMC before attempting init */
if (!mmc_host_is_spi(host))
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);

/*
* Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle
Expand Down Expand Up @@ -1019,6 +1023,10 @@ int mmc_attach_mmc(struct mmc_host *host)
BUG_ON(!host);
WARN_ON(!host->claimed);

/* Set correct bus mode for MMC before attempting attach */
if (!mmc_host_is_spi(host))
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);

err = mmc_send_op_cond(host, 0, &ocr);
if (err)
return err;
Expand Down
8 changes: 3 additions & 5 deletions drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ static int mmc_read_switch(struct mmc_card *card)
goto out;
}

if (status[13] & UHS_SDR50_BUS_SPEED)
card->sw_caps.hs_max_dtr = 50000000;

if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13];

Expand Down Expand Up @@ -348,9 +351,6 @@ static int mmc_read_switch(struct mmc_card *card)
}

card->sw_caps.sd3_curr_limit = status[7];
} else {
if (status[13] & 0x02)
card->sw_caps.hs_max_dtr = 50000000;
}

out:
Expand Down Expand Up @@ -929,8 +929,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
err = mmc_send_relative_addr(host, &card->rca);
if (err)
return err;

mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
}

if (!oldcard) {
Expand Down
2 changes: 0 additions & 2 deletions drivers/mmc/core/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
*/
if (oldcard)
oldcard->rca = card->rca;

mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
}

/*
Expand Down
82 changes: 14 additions & 68 deletions drivers/mmc/host/sdhci-bcm2708.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
#define BCM2708_SDHCI_SLEEP_TIMEOUT 1000 /* msecs */

/* Mhz clock that the EMMC core is running at. Should match the platform clockman settings */
#define BCM2708_EMMC_CLOCK_FREQ 80000000
#define BCM2708_EMMC_CLOCK_FREQ 50000000

#define POWER_OFF 0
#define POWER_LAZY_OFF 1
Expand Down Expand Up @@ -135,6 +135,8 @@ static inline unsigned long int since_ns(hptime_t t)
return (unsigned long)((hptime() - t) * HPTIME_CLK_NS);
}

static bool allow_highspeed = 1;

#if 0
static void hptime_test(void)
{
Expand Down Expand Up @@ -359,68 +361,9 @@ void sdhci_bcm2708_writeb(struct sdhci_host *host, u8 val, int reg)

static unsigned int sdhci_bcm2708_get_max_clock(struct sdhci_host *host)
{
return 20000000; // this value is in Hz (20MHz)
}

static unsigned int sdhci_bcm2708_get_timeout_clock(struct sdhci_host *host)
{
if(host->clock)
return (host->clock / 1000); // this value is in kHz (100MHz)
else
return (sdhci_bcm2708_get_max_clock(host) / 1000);
return BCM2708_EMMC_CLOCK_FREQ;
}

static void sdhci_bcm2708_set_clock(struct sdhci_host *host, unsigned int clock)
{
int div = 0;
u16 clk = 0;
unsigned long timeout;

if (clock == host->clock)
return;

sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);

if (clock == 0)
goto out;

if (BCM2708_EMMC_CLOCK_FREQ <= clock)
div = 1;
else {
for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
if ((BCM2708_EMMC_CLOCK_FREQ / div) <= clock)
break;
}
}

DBG( "desired SD clock: %d, actual: %d\n",
clock, BCM2708_EMMC_CLOCK_FREQ / div);

clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;

sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

timeout = 20;
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
printk(KERN_ERR "%s: Internal clock never "
"stabilised.\n", mmc_hostname(host->mmc));
return;
}
timeout--;
mdelay(1);
}

clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
out:
host->clock = clock;
}

/*****************************************************************************\
* *
* DMA Operation *
Expand Down Expand Up @@ -907,7 +850,7 @@ static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host,
while (0 != (sdhci_bcm2708_raw_readl(host, SDHCI_PRESENT_STATE)
& state_mask) && --timeout > 0)
{
udelay(100);
udelay(30);
continue;
}
if (timeout <= 0)
Expand Down Expand Up @@ -1307,11 +1250,7 @@ static struct sdhci_ops sdhci_bcm2708_ops = {
#else
#error The BCM2708 SDHCI driver needs CONFIG_MMC_SDHCI_IO_ACCESSORS to be set
#endif
//.enable_dma = NULL,
.set_clock = sdhci_bcm2708_set_clock,
.get_max_clock = sdhci_bcm2708_get_max_clock,
//.get_min_clock = NULL,
.get_timeout_clock = sdhci_bcm2708_get_timeout_clock,

.enable = sdhci_bcm2708_enable,
.disable = sdhci_bcm2708_disable,
Expand Down Expand Up @@ -1374,7 +1313,9 @@ static int __devinit sdhci_bcm2708_probe(struct platform_device *pdev)
host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_NONSTANDARD_CLOCK;
SDHCI_QUIRK_MISSING_CAPS |
SDHCI_QUIRK_NO_HISPD_BIT;

#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
host->flags = SDHCI_USE_PLATDMA;
#endif
Expand Down Expand Up @@ -1442,7 +1383,8 @@ static int __devinit sdhci_bcm2708_probe(struct platform_device *pdev)
host_priv->dma_chan, host_priv->dma_chan_base,
host_priv->dma_irq);

host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if (allow_highspeed)
host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
#endif

ret = sdhci_add_host(host);
Expand Down Expand Up @@ -1548,8 +1490,12 @@ static void __exit sdhci_drv_exit(void)
module_init(sdhci_drv_init);
module_exit(sdhci_drv_exit);

module_param(allow_highspeed, bool, 0444);

MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
MODULE_AUTHOR("Broadcom <[email protected]>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:"DRIVER_NAME);

MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes");

6 changes: 6 additions & 0 deletions include/linux/mmc/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ struct mmc_card {
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
#define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */
#define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */

unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
Expand Down Expand Up @@ -377,6 +378,11 @@ static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
}

static inline int mmc_card_long_read_time(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_LONG_READ_TIME;
}

#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) (dev_name(&(c)->dev))

Expand Down