GIT 1cc36746c383a35553e848d930ebae30516c1470 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc.git#for-andrew commit Author: Philip Langdale Date: Sun Oct 29 10:14:19 2006 +0100 mmc: Add support for mmc v4 wide-bus modes This change adds support for the mmc4 4-bit wide-bus mode. The mmc4 spec defines 8-bit and 4-bit transfer modes. As we do not support any 8-bit hardware, this patch only adds support for the 4-bit mode, but it can easily be built upon when the time comes. The 4-bit mode is electrically compatible with SD's 4-bit mode but the procedure for turning it on is different. This patch implements only the essential parts of the procedure as defined by the spec. Two additional steps are recommended but not compulsory. I am documenting them here so that there's a record. 1) A bus-test mechanism is implemented using dedicated mmc commands which allow for testing the functionality of the data bus at the electrical level. This is pretty paranoid and they way the commands work is not compatible with the mmc subsystem (they don't set valid CRC values). 2) MMC v4 cards can indicate they would like to draw more than the default amount of current in wide-bus modes. We currently will never switch the card into a higher draw mode. Supposedly, allowing the card to draw more current will let it perform better, but the specs seem to indicate that the card will function correctly without the mode change. Empirical testing supports this interpretation. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman commit ddd3825f3957738cdae70a2accae22b50ed34af0 Author: Philip Langdale Date: Thu Oct 26 09:45:47 2006 +0200 This patch just makes some very minor cleanups to the high-speed mmc4 support. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman commit 2840c841b4f390b9f5cc5d3a348ddb6ca4a1b54c Author: Timo Teras Date: Wed Oct 25 09:37:41 2006 +0300 MMC: Poll card status after rescanning cards Some broken cards seem to process CMD1 even in stand-by state. The result is that the card replies with ILLEGAL_COMMAND error for the next command sent after rescanning. Currently the next command is select card, which would return the error. But CMD7 does actually succeed and retries of the command will timeout. The workaround is to poll card status after CMD1 to clear the pending error. Signed-off-by: Timo Teras Signed-off-by: Pierre Ossman commit 5aa30cd42ccc2b52f749af0673c0099fa104fd00 Author: Andrew Victor Date: Mon Oct 23 14:53:20 2006 +0200 AT91 MMC 5 : Minor cleanups A number of small cleanups to the AT91RM9200 MMC driver: - fix warnings generated by pr_debug(). - prepend "AT91 MMC:" to printk() messages. Signed-off-by: Andrew Victor Signed-off-by: Pierre Ossman commit 23a7e05f9b33b648d9572289257b2a130760520e Author: Andrew Victor Date: Mon Oct 23 14:50:09 2006 +0200 AT91 MMC 4 : Interrupt handler cleanup This patch simplifies the AT91RM9200 MMC interrupt handler code so that it doesn't re-read the Interrupt Status and Interrupt Mask registers multiple times. Also defined AT91_MCI_ERRORS instead of using the hard-coded 0xffff0000. Signed-off-by: Andrew Victor Signed-off-by: Pierre Ossman commit 87eddee8a9d2d1bbfe34f14854cc87839c14db45 Author: Andrew Victor Date: Mon Oct 23 14:46:54 2006 +0200 AT91 MMC 3 : Move global mci_clk variable Move the global 'mci_clk' variable into the local 'at91mci_host' structure. Signed-off-by: Andrew Victor Signed-off-by: Pierre Ossman commit ae929a8dd901037a554f19fca4ad8151441becbb Author: Andrew Victor Date: Mon Oct 23 14:44:40 2006 +0200 AT91 MMC 2 : Use platform resources Use the I/O base-address and IRQ passed to the driver via the platform_device resources instead of using hardcoded values. Signed-off-by: Andrew Victor Signed-off-by: Pierre Ossman commit 26bf3fa5ab33a4c981843b27ac0f69d735dd5216 Author: Andrew Victor Date: Wed Oct 25 19:42:38 2006 +0200 AT91 MMC 1: Pass host structure. The I/O base address is now stored in the 'at91mci_host' structure. We therefore have to pass this structure to at91_mci_read() and at91_mci_write(). Signed-off-by: Andrew Victor Signed-off-by: Pierre Ossman commit ffcfc8aee8c3b33e1d51302b68997805efdc5c14 Author: Pierre Ossman Date: Sun Oct 22 22:13:10 2006 +0200 mmc: Fix mmc_delay() function Several fixes for mmc_delay(): * Repair if-clause that was supposed to detect sub-hz delays. * Change yield() to cond_resched() as yield() no longer has the semantics we desire. * mmc_delay() is used to guarantee protocol delays, so we cannot return early (i.e. use _interruptable). Based on patch by Amol Lad. Signed-off-by: Pierre Ossman (cherry picked from 6bcd6eef1688df42be7e960be5a0befedbee04ca commit) commit 8fd2e276d998ca332b421fc3de6edef2026b35b5 Author: Philip Langdale Date: Sat Oct 21 12:35:02 2006 +0200 [PATCH] mmc: Add support for mmc v4 high speed mode This adds support for the high-speed modes defined by mmc v4 (assuming the host controller is up to it). On a TI sdhci controller, it improves read speed from 1.3MBps to 2.3MBps. The TI controller can only go up to 24MHz, but everything helps. Another person has taken this basic patch and used it on a Nokia 770 to get a bigger boost because that controller can run at 48MHZ. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman drivers/mmc/at91_mci.c | 309 ++++++++++++++++++++++-------------------- drivers/mmc/mmc.c | 186 +++++++++++++++++++++++-- include/linux/mmc/card.h | 8 + include/linux/mmc/protocol.h | 52 +++++++ 4 files changed, 386 insertions(+), 169 deletions(-) diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 494b23f..9910769 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -80,34 +80,18 @@ #define DRIVER_NAME "at91_mci" #undef SUPPORT_4WIRE -static struct clk *mci_clk; +#define FL_SENT_COMMAND (1 << 0) +#define FL_SENT_STOP (1 << 1) -#define FL_SENT_COMMAND (1 << 0) -#define FL_SENT_STOP (1 << 1) +#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \ + | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \ + | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE) +#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg)) +#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg)) /* - * Read from a MCI register. - */ -static inline unsigned long at91_mci_read(unsigned int reg) -{ - void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; - - return __raw_readl(mci_base + reg); -} - -/* - * Write to a MCI register. - */ -static inline void at91_mci_write(unsigned int reg, unsigned long value) -{ - void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; - - __raw_writel(value, mci_base + reg); -} - -/* * Low level type for this driver */ struct at91mci_host @@ -116,9 +100,14 @@ struct at91mci_host struct mmc_command *cmd; struct mmc_request *request; + void __iomem *baseaddr; + int irq; + struct at91_mmc_data *board; int present; + struct clk *mci_clk; + /* * Flag indicating when the command has been sent. This is used to * work out whether or not to send the stop @@ -217,13 +206,13 @@ static void at91mci_pre_dma_read(struct /* Check to see if this needs filling */ if (i == 0) { - if (at91_mci_read(AT91_PDC_RCR) != 0) { + if (at91_mci_read(host, AT91_PDC_RCR) != 0) { pr_debug("Transfer active in current\n"); continue; } } else { - if (at91_mci_read(AT91_PDC_RNCR) != 0) { + if (at91_mci_read(host, AT91_PDC_RNCR) != 0) { pr_debug("Transfer active in next\n"); continue; } @@ -240,12 +229,12 @@ static void at91mci_pre_dma_read(struct pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length); if (i == 0) { - at91_mci_write(AT91_PDC_RPR, sg->dma_address); - at91_mci_write(AT91_PDC_RCR, sg->length / 4); + at91_mci_write(host, AT91_PDC_RPR, sg->dma_address); + at91_mci_write(host, AT91_PDC_RCR, sg->length / 4); } else { - at91_mci_write(AT91_PDC_RNPR, sg->dma_address); - at91_mci_write(AT91_PDC_RNCR, sg->length / 4); + at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address); + at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4); } } @@ -308,8 +297,8 @@ static void at91mci_post_dma_read(struct if (host->transfer_index < data->sg_len) at91mci_pre_dma_read(host); else { - at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF); - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); } pr_debug("post dma read done\n"); @@ -326,11 +315,11 @@ static void at91_mci_handle_transmitted( pr_debug("Handling the transmit\n"); /* Disable the transfer */ - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); /* Now wait for cmd ready */ - at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE); - at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY); + at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); cmd = host->cmd; if (!cmd) return; @@ -344,21 +333,21 @@ static void at91_mci_handle_transmitted( /* * Enable the controller */ -static void at91_mci_enable(void) +static void at91_mci_enable(struct at91mci_host *host) { - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF); - at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); - at91_mci_write(AT91_MCI_MR, 0x834A); - at91_mci_write(AT91_MCI_SDCR, 0x0); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); + at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a); + at91_mci_write(host, AT91_MCI_SDCR, 0); } /* * Disable the controller */ -static void at91_mci_disable(void) +static void at91_mci_disable(struct at91mci_host *host) { - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); } /* @@ -378,13 +367,13 @@ static unsigned int at91_mci_send_comman /* Not sure if this is needed */ #if 0 - if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { + if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { pr_debug("Clearing timeout\n"); - at91_mci_write(AT91_MCI_ARGR, 0); - at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD); - while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) { + at91_mci_write(host, AT91_MCI_ARGR, 0); + at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); + while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { /* spin */ - pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR)); + pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); } } #endif @@ -431,32 +420,32 @@ #endif /* * Set the arguments and send the command */ - pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n", - cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR)); + pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", + cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); if (!data) { - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); - at91_mci_write(AT91_PDC_RPR, 0); - at91_mci_write(AT91_PDC_RCR, 0); - at91_mci_write(AT91_PDC_RNPR, 0); - at91_mci_write(AT91_PDC_RNCR, 0); - at91_mci_write(AT91_PDC_TPR, 0); - at91_mci_write(AT91_PDC_TCR, 0); - at91_mci_write(AT91_PDC_TNPR, 0); - at91_mci_write(AT91_PDC_TNCR, 0); - - at91_mci_write(AT91_MCI_ARGR, cmd->arg); - at91_mci_write(AT91_MCI_CMDR, cmdr); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); + at91_mci_write(host, AT91_PDC_RPR, 0); + at91_mci_write(host, AT91_PDC_RCR, 0); + at91_mci_write(host, AT91_PDC_RNPR, 0); + at91_mci_write(host, AT91_PDC_RNCR, 0); + at91_mci_write(host, AT91_PDC_TPR, 0); + at91_mci_write(host, AT91_PDC_TCR, 0); + at91_mci_write(host, AT91_PDC_TNPR, 0); + at91_mci_write(host, AT91_PDC_TNCR, 0); + + at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); + at91_mci_write(host, AT91_MCI_CMDR, cmdr); return AT91_MCI_CMDRDY; } - mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ - at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); + mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ + at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); /* * Disable the PDC controller */ - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; @@ -485,8 +474,8 @@ #endif pr_debug("Transmitting %d bytes\n", host->total_length); - at91_mci_write(AT91_PDC_TPR, host->physical_address); - at91_mci_write(AT91_PDC_TCR, host->total_length / 4); + at91_mci_write(host, AT91_PDC_TPR, host->physical_address); + at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4); ier = AT91_MCI_TXBUFE; } } @@ -496,14 +485,14 @@ #endif * the data sheet says */ - at91_mci_write(AT91_MCI_ARGR, cmd->arg); - at91_mci_write(AT91_MCI_CMDR, cmdr); + at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); + at91_mci_write(host, AT91_MCI_CMDR, cmdr); if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN); else - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN); } return ier; } @@ -520,7 +509,7 @@ static void at91mci_process_command(stru pr_debug("setting ier to %08X\n", ier); /* Stop on errors or the required value */ - at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); } /* @@ -548,19 +537,19 @@ static void at91mci_completed_command(st struct mmc_command *cmd = host->cmd; unsigned int status; - at91_mci_write(AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0)); - cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1)); - cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2)); - cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3)); + cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); + cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); + cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); + cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); if (host->buffer) { dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); host->buffer = NULL; } - status = at91_mci_read(AT91_MCI_SR); + status = at91_mci_read(host, AT91_MCI_SR); pr_debug("Status = %08X [%08X %08X %08X %08X]\n", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); @@ -611,18 +600,18 @@ static void at91_mci_set_ios(struct mmc_ { int clkdiv; struct at91mci_host *host = mmc_priv(mmc); - unsigned long at91_master_clock = clk_get_rate(mci_clk); + unsigned long at91_master_clock = clk_get_rate(host->mci_clk); host->bus_mode = ios->bus_mode; if (ios->clock == 0) { /* Disable the MCI controller */ - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); clkdiv = 0; } else { /* Enable the MCI controller */ - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); if ((at91_master_clock % (ios->clock * 2)) == 0) clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; @@ -634,15 +623,15 @@ static void at91_mci_set_ios(struct mmc_ } if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { pr_debug("MMC: Setting controller bus width to 4\n"); - at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS); + at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS); } else { pr_debug("MMC: Setting controller bus width to 1\n"); - at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); + at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); } /* Set the clock divider */ - at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); + at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); /* maybe switch power to the card */ if (host->board->vcc_pin) { @@ -665,39 +654,40 @@ static irqreturn_t at91_mci_irq(int irq, { struct at91mci_host *host = devid; int completed = 0; + unsigned int int_status, int_mask; - unsigned int int_status; + int_status = at91_mci_read(host, AT91_MCI_SR); + int_mask = at91_mci_read(host, AT91_MCI_IMR); + + pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, + int_status & int_mask); + + int_status = int_status & int_mask; - int_status = at91_mci_read(AT91_MCI_SR); - pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR), - int_status & at91_mci_read(AT91_MCI_IMR)); - - if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000) + if (int_status & AT91_MCI_ERRORS) { completed = 1; + + if (int_status & AT91_MCI_UNRE) + pr_debug("MMC: Underrun error\n"); + if (int_status & AT91_MCI_OVRE) + pr_debug("MMC: Overrun error\n"); + if (int_status & AT91_MCI_DTOE) + pr_debug("MMC: Data timeout\n"); + if (int_status & AT91_MCI_DCRCE) + pr_debug("MMC: CRC error in data\n"); + if (int_status & AT91_MCI_RTOE) + pr_debug("MMC: Response timeout\n"); + if (int_status & AT91_MCI_RENDE) + pr_debug("MMC: Response end bit error\n"); + if (int_status & AT91_MCI_RCRCE) + pr_debug("MMC: Response CRC error\n"); + if (int_status & AT91_MCI_RDIRE) + pr_debug("MMC: Response direction error\n"); + if (int_status & AT91_MCI_RINDE) + pr_debug("MMC: Response index error\n"); + } else { + /* Only continue processing if no errors */ - int_status &= at91_mci_read(AT91_MCI_IMR); - - if (int_status & AT91_MCI_UNRE) - pr_debug("MMC: Underrun error\n"); - if (int_status & AT91_MCI_OVRE) - pr_debug("MMC: Overrun error\n"); - if (int_status & AT91_MCI_DTOE) - pr_debug("MMC: Data timeout\n"); - if (int_status & AT91_MCI_DCRCE) - pr_debug("MMC: CRC error in data\n"); - if (int_status & AT91_MCI_RTOE) - pr_debug("MMC: Response timeout\n"); - if (int_status & AT91_MCI_RENDE) - pr_debug("MMC: Response end bit error\n"); - if (int_status & AT91_MCI_RCRCE) - pr_debug("MMC: Response CRC error\n"); - if (int_status & AT91_MCI_RDIRE) - pr_debug("MMC: Response direction error\n"); - if (int_status & AT91_MCI_RINDE) - pr_debug("MMC: Response index error\n"); - - /* Only continue processing if no errors */ - if (!completed) { if (int_status & AT91_MCI_TXBUFE) { pr_debug("TX buffer empty\n"); at91_mci_handle_transmitted(host); @@ -705,12 +695,11 @@ static irqreturn_t at91_mci_irq(int irq, if (int_status & AT91_MCI_RXBUFF) { pr_debug("RX buffer full\n"); - at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); } - if (int_status & AT91_MCI_ENDTX) { + if (int_status & AT91_MCI_ENDTX) pr_debug("Transmit has ended\n"); - } if (int_status & AT91_MCI_ENDRX) { pr_debug("Receive has ended\n"); @@ -719,37 +708,33 @@ static irqreturn_t at91_mci_irq(int irq, if (int_status & AT91_MCI_NOTBUSY) { pr_debug("Card is ready\n"); - at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); } - if (int_status & AT91_MCI_DTIP) { + if (int_status & AT91_MCI_DTIP) pr_debug("Data transfer in progress\n"); - } - if (int_status & AT91_MCI_BLKE) { + if (int_status & AT91_MCI_BLKE) pr_debug("Block transfer has ended\n"); - } - if (int_status & AT91_MCI_TXRDY) { + if (int_status & AT91_MCI_TXRDY) pr_debug("Ready to transmit\n"); - } - if (int_status & AT91_MCI_RXRDY) { + if (int_status & AT91_MCI_RXRDY) pr_debug("Ready to receive\n"); - } if (int_status & AT91_MCI_CMDRDY) { pr_debug("Command ready\n"); completed = 1; } } - at91_mci_write(AT91_MCI_IDR, int_status); if (completed) { pr_debug("Completed command\n"); - at91_mci_write(AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); at91mci_completed_command(host); - } + } else + at91_mci_write(host, AT91_MCI_IDR, int_status); return IRQ_HANDLED; } @@ -769,7 +754,7 @@ static irqreturn_t at91_mmc_det_irq(int present ? "insert" : "remove"); if (!present) { pr_debug("****** Resetting SD-card bus width ******\n"); - at91_mci_write(AT91_MCI_SDCR, 0); + at91_mci_write(host, AT91_MCI_SDCR, 0); } mmc_detect_change(host->mmc, msecs_to_jiffies(100)); } @@ -806,15 +791,22 @@ static int at91_mci_probe(struct platfor { struct mmc_host *mmc; struct at91mci_host *host; + struct resource *res; int ret; pr_debug("Probe MCI devices\n"); - at91_mci_disable(); - at91_mci_enable(); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME)) + return -EBUSY; mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); if (!mmc) { pr_debug("Failed to allocate mmc host\n"); + release_mem_region(res->start, res->end - res->start + 1); return -ENOMEM; } @@ -833,30 +825,51 @@ static int at91_mci_probe(struct platfor #ifdef SUPPORT_4WIRE mmc->caps |= MMC_CAP_4_BIT_DATA; #else - printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); + printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); #endif } /* * Get Clock */ - mci_clk = clk_get(&pdev->dev, "mci_clk"); - if (IS_ERR(mci_clk)) { + host->mci_clk = clk_get(&pdev->dev, "mci_clk"); + if (IS_ERR(host->mci_clk)) { printk(KERN_ERR "AT91 MMC: no clock defined.\n"); mmc_free_host(mmc); + release_mem_region(res->start, res->end - res->start + 1); return -ENODEV; } - clk_enable(mci_clk); /* Enable the peripheral clock */ + + /* + * Map I/O region + */ + host->baseaddr = ioremap(res->start, res->end - res->start + 1); + if (!host->baseaddr) { + clk_put(host->mci_clk); + mmc_free_host(mmc); + release_mem_region(res->start, res->end - res->start + 1); + return -ENOMEM; + } + + /* + * Reset hardware + */ + clk_enable(host->mci_clk); /* Enable the peripheral clock */ + at91_mci_disable(host); + at91_mci_enable(host); /* * Allocate the MCI interrupt */ - ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); + host->irq = platform_get_irq(pdev, 0); + ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); if (ret) { - printk(KERN_ERR "Failed to request MCI interrupt\n"); - clk_disable(mci_clk); - clk_put(mci_clk); + printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n"); + clk_disable(host->mci_clk); + clk_put(host->mci_clk); mmc_free_host(mmc); + iounmap(host->baseaddr); + release_mem_region(res->start, res->end - res->start + 1); return ret; } @@ -879,10 +892,10 @@ #endif ret = request_irq(host->board->det_pin, at91_mmc_det_irq, 0, DRIVER_NAME, host); if (ret) - printk(KERN_ERR "couldn't allocate MMC detect irq\n"); + printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n"); } - pr_debug(KERN_INFO "Added MCI driver\n"); + pr_debug("Added MCI driver\n"); return 0; } @@ -894,6 +907,7 @@ static int at91_mci_remove(struct platfo { struct mmc_host *mmc = platform_get_drvdata(pdev); struct at91mci_host *host; + struct resource *res; if (!mmc) return -1; @@ -905,16 +919,19 @@ static int at91_mci_remove(struct platfo cancel_delayed_work(&host->mmc->detect); } + at91_mci_disable(host); mmc_remove_host(mmc); - at91_mci_disable(); - free_irq(AT91RM9200_ID_MCI, host); - mmc_free_host(mmc); + free_irq(host->irq, host); - clk_disable(mci_clk); /* Disable the peripheral clock */ - clk_put(mci_clk); + clk_disable(host->mci_clk); /* Disable the peripheral clock */ + clk_put(host->mci_clk); - platform_set_drvdata(pdev, NULL); + iounmap(host->baseaddr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + mmc_free_host(mmc); + platform_set_drvdata(pdev, NULL); pr_debug("MCI Removed\n"); return 0; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ee8863c..23613d2 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -4,6 +4,7 @@ * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -396,23 +397,23 @@ static int mmc_select_card(struct mmc_ho return err; /* - * Default bus width is 1 bit. - */ - host->ios.bus_width = MMC_BUS_WIDTH_1; - - /* - * We can only change the bus width of the selected - * card so therefore we have to put the handling + * We can only change the bus width of SD cards when + * they are selected so we have to put the handling * here. + * + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. */ - if (host->caps & MMC_CAP_4_BIT_DATA) { + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + /* - * The card is in 1 bit mode by default so - * we only need to change if it supports the - * wider version. - */ - if (mmc_card_sd(card) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + if (host->caps & MMC_CAP_4_BIT_DATA) { struct mmc_command cmd; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.arg = SD_BUS_WIDTH_4; @@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mm static inline void mmc_delay(unsigned int ms) { - if (ms < HZ / 1000) { - yield(); + if (ms < 1000 / HZ) { + cond_resched(); mdelay(ms); } else { - msleep_interruptible (ms); + msleep(ms); } } @@ -953,6 +954,128 @@ static void mmc_read_csds(struct mmc_hos } } +static void mmc_process_ext_csds(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + u8 ext_csd[512]; + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (mmc_card_sd(card)) + continue; + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 512; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, &ext_csd, 512); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; + case EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 26000000; + break; + default: + /* MMC v4 spec says this cannot happen */ + printk("%s: card is mmc v4 but doesn't support " + "any high-speed modes.\n", + mmc_hostname(card->host)); + mmc_card_set_bad(card); + continue; + } + + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } + + mmc_card_set_highspeed(card); + + /* Check for host support for wide-bus modes. */ + if (!(host->caps & MMC_CAP_4_BIT_DATA)) { + continue; + } + + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } + + host->ios.bus_width = MMC_BUS_WIDTH_4; + } + + mmc_deselect_cards(host); +} + static void mmc_read_scrs(struct mmc_host *host) { int err; @@ -1031,8 +1154,14 @@ static unsigned int mmc_calculate_clock( unsigned int max_dtr = host->f_max; list_for_each_entry(card, &host->cards, node) - if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) - max_dtr = card->csd.max_dtr; + if (!mmc_card_dead(card)) { + if (mmc_card_highspeed(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) { + max_dtr = card->csd.max_dtr; + } + } pr_debug("%s: selected %d.%03dMHz transfer rate\n", mmc_hostname(host), @@ -1152,6 +1281,8 @@ static void mmc_setup(struct mmc_host *h if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); + else + mmc_process_ext_csds(host); } @@ -1178,14 +1309,29 @@ static void mmc_rescan(void *data) { struct mmc_host *host = data; struct list_head *l, *n; + unsigned char power_mode; mmc_claim_host(host); - if (host->ios.power_mode == MMC_POWER_ON) + /* + * Check for removed cards and newly inserted ones. We check for + * removed cards first so we can intelligently re-select the VDD. + */ + power_mode = host->ios.power_mode; + if (power_mode == MMC_POWER_ON) mmc_check_cards(host); mmc_setup(host); + /* + * Some broken cards process CMD1 even in stand-by state. There is + * no reply, but an ILLEGAL_COMMAND error is cached and returned + * after next command. We poll for card status here to clear any + * possibly pending error. + */ + if (power_mode == MMC_POWER_ON) + mmc_check_cards(host); + if (!list_empty(&host->cards)) { /* * (Re-)calculate the fastest clock rate which the diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 991a373..ce25256 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -39,6 +39,10 @@ struct mmc_csd { write_misalign:1; }; +struct mmc_ext_csd { + unsigned int hs_max_dtr; +}; + struct sd_scr { unsigned char sda_vsn; unsigned char bus_widths; @@ -62,11 +66,13 @@ #define MMC_STATE_DEAD (1<<1) /* devic #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ struct mmc_cid cid; /* card identification */ struct mmc_csd csd; /* card specific */ + struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ }; @@ -75,12 +81,14 @@ #define mmc_card_dead(c) ((c)->state & M #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #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_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 08dec8d..45c51fd 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -25,14 +25,16 @@ #ifndef MMC_MMC_PROTOCOL_H #define MMC_MMC_PROTOCOL_H -/* Standard MMC commands (3.1) type argument response */ +/* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ @@ -88,6 +90,17 @@ #define SD_APP_OP_COND 41 /* #define SD_APP_SEND_SCR 51 /* adtc R1 */ /* + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ + +/* MMC status in R1 Type e : error bit @@ -230,13 +243,46 @@ #define CCC_SWITCH (1<<10) /* (10) High #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ -#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ #define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ #define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ -#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ + +/* + * MMC_SWITCH access modes + */ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ /* * SD bus widths