diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-12-18 11:03:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-12-18 11:03:01 -0500 |
commit | d55653377df36f8c04a966f3420335f1a0eb4d83 (patch) | |
tree | a986fbd0e8310b1fec44886001f8aeecce32f42a /drivers | |
parent | c63a1190368771b8207d86c4217ae4afdf1cbd5e (diff) | |
parent | cc3000e4ef13fa9f388f5a37f11c0fa3cc68112b (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
mmc: remove unused 'mode' from the mmc_host structure
sdhci: support JMicron JMB38x chips
sdhci: use PIO when DMA can't satisfy the request
sdhci: don't warn about sdhci 2.0 controllers
sdhci: describe quirks
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 63 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 |
2 files changed, 60 insertions, 6 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ff59d2e0475b..785bbdcf4a58 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -7,6 +7,10 @@ | |||
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or (at | 8 | * the Free Software Foundation; either version 2 of the License, or (at |
9 | * your option) any later version. | 9 | * your option) any later version. |
10 | * | ||
11 | * Thanks to the following companies for their support: | ||
12 | * | ||
13 | * - JMicron (hardware and technical support) | ||
10 | */ | 14 | */ |
11 | 15 | ||
12 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
@@ -26,13 +30,29 @@ | |||
26 | 30 | ||
27 | static unsigned int debug_quirks = 0; | 31 | static unsigned int debug_quirks = 0; |
28 | 32 | ||
33 | /* | ||
34 | * Different quirks to handle when the hardware deviates from a strict | ||
35 | * interpretation of the SDHCI specification. | ||
36 | */ | ||
37 | |||
38 | /* Controller doesn't honor resets unless we touch the clock register */ | ||
29 | #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) | 39 | #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) |
40 | /* Controller has bad caps bits, but really supports DMA */ | ||
30 | #define SDHCI_QUIRK_FORCE_DMA (1<<1) | 41 | #define SDHCI_QUIRK_FORCE_DMA (1<<1) |
31 | /* Controller doesn't like some resets when there is no card inserted. */ | 42 | /* Controller doesn't like some resets when there is no card inserted. */ |
32 | #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) | 43 | #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) |
44 | /* Controller doesn't like clearing the power reg before a change */ | ||
33 | #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) | 45 | #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) |
46 | /* Controller has flaky internal state so reset it on each ios change */ | ||
34 | #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) | 47 | #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) |
48 | /* Controller has an unusable DMA engine */ | ||
35 | #define SDHCI_QUIRK_BROKEN_DMA (1<<5) | 49 | #define SDHCI_QUIRK_BROKEN_DMA (1<<5) |
50 | /* Controller can only DMA from 32-bit aligned addresses */ | ||
51 | #define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<6) | ||
52 | /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ | ||
53 | #define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<7) | ||
54 | /* Controller needs to be reset after each request to stay stable */ | ||
55 | #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) | ||
36 | 56 | ||
37 | static const struct pci_device_id pci_ids[] __devinitdata = { | 57 | static const struct pci_device_id pci_ids[] __devinitdata = { |
38 | { | 58 | { |
@@ -97,6 +117,16 @@ static const struct pci_device_id pci_ids[] __devinitdata = { | |||
97 | SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, | 117 | SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, |
98 | }, | 118 | }, |
99 | 119 | ||
120 | { | ||
121 | .vendor = PCI_VENDOR_ID_JMICRON, | ||
122 | .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD, | ||
123 | .subvendor = PCI_ANY_ID, | ||
124 | .subdevice = PCI_ANY_ID, | ||
125 | .driver_data = SDHCI_QUIRK_32BIT_DMA_ADDR | | ||
126 | SDHCI_QUIRK_32BIT_DMA_SIZE | | ||
127 | SDHCI_QUIRK_RESET_AFTER_REQUEST, | ||
128 | }, | ||
129 | |||
100 | { /* Generic SD host controller */ | 130 | { /* Generic SD host controller */ |
101 | PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) | 131 | PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) |
102 | }, | 132 | }, |
@@ -419,7 +449,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
419 | 449 | ||
420 | writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); | 450 | writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); |
421 | 451 | ||
422 | if (host->flags & SDHCI_USE_DMA) { | 452 | if (host->flags & SDHCI_USE_DMA) |
453 | host->flags |= SDHCI_REQ_USE_DMA; | ||
454 | |||
455 | if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && | ||
456 | (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && | ||
457 | ((data->blksz * data->blocks) & 0x3))) { | ||
458 | DBG("Reverting to PIO because of transfer size (%d)\n", | ||
459 | data->blksz * data->blocks); | ||
460 | host->flags &= ~SDHCI_REQ_USE_DMA; | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * The assumption here being that alignment is the same after | ||
465 | * translation to device address space. | ||
466 | */ | ||
467 | if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && | ||
468 | (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && | ||
469 | (data->sg->offset & 0x3))) { | ||
470 | DBG("Reverting to PIO because of bad alignment\n"); | ||
471 | host->flags &= ~SDHCI_REQ_USE_DMA; | ||
472 | } | ||
473 | |||
474 | if (host->flags & SDHCI_REQ_USE_DMA) { | ||
423 | int count; | 475 | int count; |
424 | 476 | ||
425 | count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, | 477 | count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, |
@@ -456,7 +508,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, | |||
456 | mode |= SDHCI_TRNS_MULTI; | 508 | mode |= SDHCI_TRNS_MULTI; |
457 | if (data->flags & MMC_DATA_READ) | 509 | if (data->flags & MMC_DATA_READ) |
458 | mode |= SDHCI_TRNS_READ; | 510 | mode |= SDHCI_TRNS_READ; |
459 | if (host->flags & SDHCI_USE_DMA) | 511 | if (host->flags & SDHCI_REQ_USE_DMA) |
460 | mode |= SDHCI_TRNS_DMA; | 512 | mode |= SDHCI_TRNS_DMA; |
461 | 513 | ||
462 | writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); | 514 | writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); |
@@ -472,7 +524,7 @@ static void sdhci_finish_data(struct sdhci_host *host) | |||
472 | data = host->data; | 524 | data = host->data; |
473 | host->data = NULL; | 525 | host->data = NULL; |
474 | 526 | ||
475 | if (host->flags & SDHCI_USE_DMA) { | 527 | if (host->flags & SDHCI_REQ_USE_DMA) { |
476 | pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, | 528 | pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, |
477 | (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); | 529 | (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); |
478 | } | 530 | } |
@@ -886,7 +938,8 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
886 | */ | 938 | */ |
887 | if (mrq->cmd->error || | 939 | if (mrq->cmd->error || |
888 | (mrq->data && (mrq->data->error || | 940 | (mrq->data && (mrq->data->error || |
889 | (mrq->data->stop && mrq->data->stop->error)))) { | 941 | (mrq->data->stop && mrq->data->stop->error))) || |
942 | (host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { | ||
890 | 943 | ||
891 | /* Some controllers need this kick or reset won't work here */ | 944 | /* Some controllers need this kick or reset won't work here */ |
892 | if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { | 945 | if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { |
@@ -1284,7 +1337,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1284 | 1337 | ||
1285 | version = readw(host->ioaddr + SDHCI_HOST_VERSION); | 1338 | version = readw(host->ioaddr + SDHCI_HOST_VERSION); |
1286 | version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; | 1339 | version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; |
1287 | if (version != 0) { | 1340 | if (version > 1) { |
1288 | printk(KERN_ERR "%s: Unknown controller version (%d). " | 1341 | printk(KERN_ERR "%s: Unknown controller version (%d). " |
1289 | "You may experience problems.\n", host->slot_descr, | 1342 | "You may experience problems.\n", host->slot_descr, |
1290 | version); | 1343 | version); |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 05195ea900f4..e4d77b038bfa 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -171,7 +171,8 @@ struct sdhci_host { | |||
171 | spinlock_t lock; /* Mutex */ | 171 | spinlock_t lock; /* Mutex */ |
172 | 172 | ||
173 | int flags; /* Host attributes */ | 173 | int flags; /* Host attributes */ |
174 | #define SDHCI_USE_DMA (1<<0) | 174 | #define SDHCI_USE_DMA (1<<0) /* Host is DMA capable */ |
175 | #define SDHCI_REQ_USE_DMA (1<<1) /* Use DMA for this req. */ | ||
175 | 176 | ||
176 | unsigned int max_clk; /* Max possible freq (MHz) */ | 177 | unsigned int max_clk; /* Max possible freq (MHz) */ |
177 | unsigned int timeout_clk; /* Timeout freq (KHz) */ | 178 | unsigned int timeout_clk; /* Timeout freq (KHz) */ |