Commit 1c8cde92 authored by Pierre Ossman's avatar Pierre Ossman Committed by Russell King

[MMC] sdhci: proper timeout handling

Use the give timeout clock and calculate a proper timeout instead of using the
maximum at all times.
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e16514d8
...@@ -128,9 +128,6 @@ static void sdhci_init(struct sdhci_host *host) ...@@ -128,9 +128,6 @@ static void sdhci_init(struct sdhci_host *host)
writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
/* This is unknown magic. */
writeb(0xE, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
} }
static void sdhci_activate_led(struct sdhci_host *host) static void sdhci_activate_led(struct sdhci_host *host)
...@@ -274,6 +271,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host) ...@@ -274,6 +271,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
{ {
u16 mode; u16 mode;
u8 count;
unsigned target_timeout, current_timeout;
WARN_ON(host->data); WARN_ON(host->data);
...@@ -287,6 +286,37 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) ...@@ -287,6 +286,37 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
DBG("tsac %d ms nsac %d clk\n", DBG("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks); data->timeout_ns / 1000000, data->timeout_clks);
/* timeout in us */
target_timeout = data->timeout_ns / 1000 +
data->timeout_clks / host->clock;
/*
* Figure out needed cycles.
* We do this in steps in order to fit inside a 32 bit int.
* The first step is the minimum timeout, which will have a
* minimum resolution of 6 bits:
* (1) 2^13*1000 > 2^22,
* (2) host->timeout_clk < 2^16
* =>
* (1) / (2) > 2^6
*/
count = 0;
current_timeout = (1 << 13) * 1000 / host->timeout_clk;
while (current_timeout < target_timeout) {
count++;
current_timeout <<= 1;
if (count >= 0xF)
break;
}
if (count >= 0xF) {
printk(KERN_WARNING "%s: Too large timeout requested!\n",
mmc_hostname(host->mmc));
count = 0xE;
}
writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
mode = SDHCI_TRNS_BLK_CNT_EN; mode = SDHCI_TRNS_BLK_CNT_EN;
if (data->blocks > 1) if (data->blocks > 1)
mode |= SDHCI_TRNS_MULTI; mode |= SDHCI_TRNS_MULTI;
...@@ -1096,6 +1126,17 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1096,6 +1126,17 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
} }
host->max_clk *= 1000000; host->max_clk *= 1000000;
host->timeout_clk =
(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
if (host->timeout_clk == 0) {
printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
"frequency.\n", host->slot_descr);
ret = -ENODEV;
goto unmap;
}
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
/* /*
* Set host parameters. * Set host parameters.
*/ */
......
...@@ -125,6 +125,9 @@ ...@@ -125,6 +125,9 @@
/* 3E-3F reserved */ /* 3E-3F reserved */
#define SDHCI_CAPABILITIES 0x40 #define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
#define SDHCI_TIMEOUT_CLK_SHIFT 0
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
#define SDHCI_CLOCK_BASE_MASK 0x00003F00 #define SDHCI_CLOCK_BASE_MASK 0x00003F00
#define SDHCI_CLOCK_BASE_SHIFT 8 #define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_CAN_DO_DMA 0x00400000 #define SDHCI_CAN_DO_DMA 0x00400000
...@@ -156,6 +159,7 @@ struct sdhci_host { ...@@ -156,6 +159,7 @@ struct sdhci_host {
#define SDHCI_USE_DMA (1<<0) #define SDHCI_USE_DMA (1<<0)
unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */ unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */ unsigned short power; /* Current voltage */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment