From 2971944582ff43b7dedbb460777052243ac9915a Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:54:43 +0100 Subject: ARM: 6307/1: mmci: allow the card detect GPIO value not to be inverted On some platforms, the GPIO value from the gpio_cd pin doesn't need to be inverted to get it active high. Add a cd_invert platform data parameter and change existing platforms using GPIO for CD (only Realview) to enable it. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 840b301b5671..9a9aeac50a6c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -570,12 +570,13 @@ static int mmci_get_ro(struct mmc_host *mmc) static int mmci_get_cd(struct mmc_host *mmc) { struct mmci_host *host = mmc_priv(mmc); + struct mmci_platform_data *plat = host->plat; unsigned int status; if (host->gpio_cd == -ENOSYS) - status = host->plat->status(mmc_dev(host->mmc)); + status = plat->status(mmc_dev(host->mmc)); else - status = !gpio_get_value(host->gpio_cd); + status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; /* * Use positive logic throughout - status is zero for no card, -- cgit v1.2.2 From 8301bb68c6bb9836889641a47443aeb97b763f6c Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:57:30 +0100 Subject: ARM: 6310/1: mmci: support different FIFO sizes The Ux500 variant has a 32-word FIFO (TXFIFOEMPTY is asserted when it has 2 left) and TXFIFOHALFEMPTY is repurposed as TXFIFOBURSTWRITEABLE, with a burst being defined as 8-words. Likewise for RX. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 9a9aeac50a6c..1932e9cc8f52 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -41,23 +41,35 @@ static unsigned int fmax = 515633; * @clkreg: default value for MCICLOCK register * @clkreg_enable: enable value for MMCICLOCK register * @datalength_bits: number of bits in the MMCIDATALENGTH register + * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY + * is asserted (likewise for RX) + * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY + * is asserted (likewise for RX) */ struct variant_data { unsigned int clkreg; unsigned int clkreg_enable; unsigned int datalength_bits; + unsigned int fifosize; + unsigned int fifohalfsize; }; static struct variant_data variant_arm = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .datalength_bits = 16, }; static struct variant_data variant_u300 = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, }; static struct variant_data variant_ux500 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, @@ -138,6 +150,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { + struct variant_data *variant = host->variant; unsigned int datactrl, timeout, irqmask; unsigned long long clks; void __iomem *base; @@ -173,7 +186,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) * If we have less than a FIFOSIZE of bytes to transfer, * trigger a PIO interrupt as soon as any data is available. */ - if (host->size < MCI_FIFOSIZE) + if (host->size < variant->fifosize) irqmask |= MCI_RXDATAAVLBLMASK; } else { /* @@ -332,13 +345,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) { + struct variant_data *variant = host->variant; void __iomem *base = host->base; char *ptr = buffer; do { unsigned int count, maxcnt; - maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; + maxcnt = status & MCI_TXFIFOEMPTY ? + variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); writesl(base + MMCIFIFO, ptr, count >> 2); @@ -362,6 +377,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; struct sg_mapping_iter *sg_miter = &host->sg_miter; + struct variant_data *variant = host->variant; void __iomem *base = host->base; unsigned long flags; u32 status; @@ -420,7 +436,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * If we're nearing the end of the read, switch to * "any data available" mode. */ - if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) + if (status & MCI_RXACTIVE && host->size < variant->fifosize) writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); /* -- cgit v1.2.2 From 148b8b39c156424da22693d26adcb69800faf95e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:55:48 +0100 Subject: ARM: 6308/1: mmci: support card detection interrupts If an IRQ can be requested on the card detected GPIO, use it instead of polling. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 1932e9cc8f52..a922a0028836 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -601,6 +601,15 @@ static int mmci_get_cd(struct mmc_host *mmc) return status; } +static irqreturn_t mmci_cd_irq(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + + return IRQ_HANDLED; +} + static const struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, @@ -637,6 +646,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_wp = -ENOSYS; host->gpio_cd = -ENOSYS; + host->gpio_cd_irq = -1; host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); @@ -716,7 +726,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; - mmc->caps |= MMC_CAP_NEEDS_POLL; /* * We can do SGIO @@ -761,6 +770,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_cd = plat->gpio_cd; else if (ret != -ENOSYS) goto err_gpio_cd; + + ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), + mmci_cd_irq, 0, + DRIVER_NAME " (cd)", host); + if (ret >= 0) + host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } if (gpio_is_valid(plat->gpio_wp)) { ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); @@ -772,6 +787,9 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto err_gpio_wp; } + if (host->gpio_cd_irq < 0) + mmc->caps |= MMC_CAP_NEEDS_POLL; + ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto unmap; @@ -798,6 +816,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); err_gpio_wp: + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); err_gpio_cd: @@ -836,6 +856,8 @@ static int __devexit mmci_remove(struct amba_device *dev) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); -- cgit v1.2.2 From 4b8caec09562ce7e6e3aaf2954eef8ea73ba67b8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:56:40 +0100 Subject: ARM: 6309/1: mmci: allow neither ->status nor gpio_cd to be specified The card may be always present on the board, and for these cases neither a status callback nor a card detect GPIO is required, and card detection polling can be disabled. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index a922a0028836..fd89d9230928 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -589,9 +589,12 @@ static int mmci_get_cd(struct mmc_host *mmc) struct mmci_platform_data *plat = host->plat; unsigned int status; - if (host->gpio_cd == -ENOSYS) + if (host->gpio_cd == -ENOSYS) { + if (!plat->status) + return 1; /* Assume always present */ + status = plat->status(mmc_dev(host->mmc)); - else + } else status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; /* @@ -787,7 +790,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto err_gpio_wp; } - if (host->gpio_cd_irq < 0) + if ((host->plat->status || host->gpio_cd != -ENOSYS) + && host->gpio_cd_irq < 0) mmc->caps |= MMC_CAP_NEEDS_POLL; ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); -- cgit v1.2.2 From 18a06301158b5e4e9fae29e477f468e23f3eda90 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 12 Sep 2010 12:56:44 +0100 Subject: ARM: 6370/1: mmci: use _cansleep GPIO functions Currently the kernel is screaming about slowpath at me for the wp/cd callbacks. Switch to the _cansleep variants so as to silence this. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fd89d9230928..f2e02d7d9f3d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -580,7 +580,7 @@ static int mmci_get_ro(struct mmc_host *mmc) if (host->gpio_wp == -ENOSYS) return -ENOSYS; - return gpio_get_value(host->gpio_wp); + return gpio_get_value_cansleep(host->gpio_wp); } static int mmci_get_cd(struct mmc_host *mmc) @@ -595,7 +595,8 @@ static int mmci_get_cd(struct mmc_host *mmc) status = plat->status(mmc_dev(host->mmc)); } else - status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; + status = !!gpio_get_value_cansleep(host->gpio_cd) + ^ plat->cd_invert; /* * Use positive logic throughout - status is zero for no card, -- cgit v1.2.2 From a36274e0184193e393fb82957925c3981a6b0477 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 10 Sep 2010 01:33:59 -0400 Subject: mmc: Remove distinction between hw and phys segments We have deprecated the distinction between hardware and physical segments in the block layer. Consolidate the two limits into one in drivers/mmc/. Signed-off-by: Martin K. Petersen Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index f2e02d7d9f3d..5f2e72d38b5d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -734,8 +734,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) /* * We can do SGIO */ - mmc->max_hw_segs = 16; - mmc->max_phys_segs = NR_SG; + mmc->max_segs = NR_SG; /* * Since only a certain number of bits are valid in the data length -- cgit v1.2.2 From 99fc5131018cbdc3cf42ce09fb394a4e8b053c74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Sep 2010 01:08:27 -0400 Subject: mmc: Move regulator handling closer to core After discovering a problem in regulator reference counting I took Mark Brown's advice to move the reference count into the MMC core by making the regulator status a member of struct mmc_host. I took this opportunity to also implement NULL versions of the regulator functions so as to rid the driver code from some ugly #ifdef CONFIG_REGULATOR clauses. Signed-off-by: Linus Walleij Reviewed-by: Mark Brown Cc: Liam Girdwood Cc: Tony Lindgren Cc: Adrian Hunter Cc: Robert Jarzmik Cc: Sundar Iyer Cc: Daniel Mack Cc: Pierre Ossman Cc: Matt Fleming Cc: David Brownell Cc: Russell King Cc: Eric Miao Cc: Cliff Brake Cc: Jarkko Lavinen Cc: Signed-off-by: Andrew Morton Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5f2e72d38b5d..87b4fc6c98c2 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -523,19 +523,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct mmci_host *host = mmc_priv(mmc); u32 pwr = 0; unsigned long flags; + int ret; switch (ios->power_mode) { case MMC_POWER_OFF: - if(host->vcc && - regulator_is_enabled(host->vcc)) - regulator_disable(host->vcc); + if (host->vcc) + ret = mmc_regulator_set_ocr(mmc, host->vcc, 0); break; case MMC_POWER_UP: -#ifdef CONFIG_REGULATOR - if (host->vcc) - /* This implicitly enables the regulator */ - mmc_regulator_set_ocr(host->vcc, ios->vdd); -#endif + if (host->vcc) { + ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd); + if (ret) { + dev_err(mmc_dev(mmc), "unable to set OCR\n"); + /* + * The .set_ios() function in the mmc_host_ops + * struct return void, and failing to set the + * power should be rare so we print an error + * and return here. + */ + return; + } + } if (host->plat->vdd_handler) pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, ios->power_mode); @@ -869,8 +877,8 @@ static int __devexit mmci_remove(struct amba_device *dev) clk_disable(host->clk); clk_put(host->clk); - if (regulator_is_enabled(host->vcc)) - regulator_disable(host->vcc); + if (host->vcc) + mmc_regulator_set_ocr(mmc, host->vcc, 0); regulator_put(host->vcc); mmc_free_host(mmc); -- cgit v1.2.2 From 2686b4b408c25349aee7b35558722d5730d67224 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 12:39:48 +0100 Subject: ARM: 6311/2: mmci: work with only one irq The DBx500 variants have only one IRQ line hooked up. Allow these (and any other implementations which choose to use only one irq) to work by directing the PIO interrupts also to the first IRQ line. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 50 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87b4fc6c98c2..ed700a5b03ae 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -129,10 +129,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) spin_lock(&host->lock); } +static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +{ + void __iomem *base = host->base; + + if (host->singleirq) { + unsigned int mask0 = readl(base + MMCIMASK0); + + mask0 &= ~MCI_IRQ1MASK; + mask0 |= mask; + + writel(mask0, base + MMCIMASK0); + } + + writel(mask, base + MMCIMASK1); +} + static void mmci_stop_data(struct mmci_host *host) { writel(0, host->base + MMCIDATACTRL); - writel(0, host->base + MMCIMASK1); + mmci_set_mask1(host, 0); host->data = NULL; } @@ -198,7 +214,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); - writel(irqmask, base + MMCIMASK1); + mmci_set_mask1(host, irqmask); } static void @@ -437,7 +453,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * "any data available" mode. */ if (status & MCI_RXACTIVE && host->size < variant->fifosize) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* * If we run out of data, disable the data IRQs; this @@ -446,7 +462,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * stops us racing with our data end IRQ. */ if (host->size == 0) { - writel(0, base + MMCIMASK1); + mmci_set_mask1(host, 0); writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); } @@ -469,6 +485,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) struct mmc_data *data; status = readl(host->base + MMCISTATUS); + + if (host->singleirq) { + if (status & readl(host->base + MMCIMASK1)) + mmci_pio_irq(irq, dev_id); + + status &= ~MCI_IRQ1MASK; + } + status &= readl(host->base + MMCIMASK0); writel(status, host->base + MMCICLEAR); @@ -635,6 +659,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; + unsigned int mask; int ret; /* must have platform data */ @@ -806,11 +831,17 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (ret) goto unmap; - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); - if (ret) - goto irq0_free; + if (dev->irq[1] == NO_IRQ) + host->singleirq = true; + else { + ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, + DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mask = MCI_IRQENABLE; + writel(mask, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); @@ -864,7 +895,8 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); free_irq(dev->irq[0], host); - free_irq(dev->irq[1], host); + if (!host->singleirq) + free_irq(dev->irq[1], host); if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); -- cgit v1.2.2 From f20f8f21e0402c785c342547f7e49eafc42cfb52 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 13:41:24 +0100 Subject: ARM: 6399/3: mmci: handle broken MCI_DATABLOCKEND hardware On the U300 the MCI_DATAEND and MCI_DATABLOCKEND IRQs can arrive out-of-order. Replace an ugly #ifdef hack with a proper runtime solution which models what is really happening. In the U300 DMA mode and on all Ux500 models, the MCI_DATABLOCKEND flag isn't properly cleared in hardware following and ACK leading to all kind of weird behaviour when the flag is still up in subsequent interrupts, so we add two flags indicating the error and handle this runtime. Cc: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 93 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 16 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ed700a5b03ae..976c9d0e8080 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -45,6 +45,10 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) + * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware + * and will not work at all. + * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when + * using DMA. */ struct variant_data { unsigned int clkreg; @@ -52,6 +56,8 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; + bool broken_blockend; + bool broken_blockend_dma; }; static struct variant_data variant_arm = { @@ -65,6 +71,7 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, + .broken_blockend_dma = true, }; static struct variant_data variant_ux500 = { @@ -73,6 +80,7 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, + .broken_blockend = true, }; /* * This must be called with host->lock held @@ -178,6 +186,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; + host->blockend = false; + host->dataend = false; mmci_init_sg(host, data); @@ -249,20 +259,9 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - if (status & MCI_DATABLOCKEND) { - host->data_xfered += data->blksz; -#ifdef CONFIG_ARCH_U300 - /* - * On the U300 some signal or other is - * badly routed so that a data write does - * not properly terminate with a MCI_DATAEND - * status flag. This quirk will make writes - * work again. - */ - if (data->flags & MMC_DATA_WRITE) - status |= MCI_DATAEND; -#endif - } + struct variant_data *variant = host->variant; + + /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) @@ -271,7 +270,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = -EIO; - status |= MCI_DATAEND; + + /* Force-complete the transaction */ + host->blockend = true; + host->dataend = true; /* * We hit an error condition. Ensure that any data @@ -289,9 +291,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, local_irq_restore(flags); } } - if (status & MCI_DATAEND) { + + /* + * On ARM variants in PIO mode, MCI_DATABLOCKEND + * is always sent first, and we increase the + * transfered number of bytes for that IRQ. Then + * MCI_DATAEND follows and we conclude the transaction. + * + * On the Ux500 single-IRQ variant MCI_DATABLOCKEND + * doesn't seem to immediately clear from the status, + * so we can't use it keep count when only one irq is + * used because the irq will hit for other reasons, and + * then the flag is still up. So we use the MCI_DATAEND + * IRQ at the end of the entire transfer because + * MCI_DATABLOCKEND is broken. + * + * In the U300, the IRQs can arrive out-of-order, + * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, + * so for this case we use the flags "blockend" and + * "dataend" to make sure both IRQs have arrived before + * concluding the transaction. (This does not apply + * to the Ux500 which doesn't fire MCI_DATABLOCKEND + * at all.) In DMA mode it suffers from the same problem + * as the Ux500. + */ + if (status & MCI_DATABLOCKEND) { + /* + * Just being a little over-cautious, we do not + * use this progressive update if the hardware blockend + * flag is unreliable: since it can stay high between + * IRQs it will corrupt the transfer counter. + */ + if (!variant->broken_blockend) + host->data_xfered += data->blksz; + host->blockend = true; + } + + if (status & MCI_DATAEND) + host->dataend = true; + + /* + * On variants with broken blockend we shall only wait for dataend, + * on others we must sync with the blockend signal since they can + * appear out-of-order. + */ + if (host->dataend && (host->blockend || variant->broken_blockend)) { mmci_stop_data(host); + /* Reset these flags */ + host->blockend = false; + host->dataend = false; + + /* + * Variants with broken blockend flags need to handle the + * end of the entire transfer here. + */ + if (variant->broken_blockend && !data->error) + host->data_xfered += data->blksz * data->blocks; + if (!data->stop) { mmci_request_end(host, data->mrq); } else { @@ -841,6 +898,10 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) } mask = MCI_IRQENABLE; + /* Don't use the datablockend flag if it's broken */ + if (variant->broken_blockend) + mask &= ~MCI_DATABLOCKEND; + writel(mask, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); -- cgit v1.2.2 From 34177802001894e064c857cac2759f68119550cd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 12:43:58 +0100 Subject: ARM: 6438/2: mmci: add SDIO support for ST Variants This adds some minor variant data and trickery to enable SDIO on the ST Micro variants of MMCI/PL180. Signed-off-by: Marcin Mielczarczyk Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 976c9d0e8080..0814b88b44d6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static unsigned int fmax = 515633; * and will not work at all. * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when * using DMA. + * @sdio: variant supports SDIO */ struct variant_data { unsigned int clkreg; @@ -58,6 +60,7 @@ struct variant_data { unsigned int fifohalfsize; bool broken_blockend; bool broken_blockend_dma; + bool sdio; }; static struct variant_data variant_arm = { @@ -72,6 +75,7 @@ static struct variant_data variant_u300 = { .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, .broken_blockend_dma = true, + .sdio = true, }; static struct variant_data variant_ux500 = { @@ -81,6 +85,7 @@ static struct variant_data variant_ux500 = { .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, .broken_blockend = true, + .sdio = true, }; /* * This must be called with host->lock held @@ -222,6 +227,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } + /* The ST Micro variants has a special bit to enable SDIO */ + if (variant->sdio && host->mmc->card) + if (mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); @@ -429,7 +439,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); - writesl(base + MMCIFIFO, ptr, count >> 2); + /* + * The ST Micro variant for SDIO transfer sizes + * less then 8 bytes should have clock H/W flow + * control disabled. + */ + if (variant->sdio && + mmc_card_sdio(host->mmc->card)) { + if (count < 8) + writel(readl(host->base + MMCICLOCK) & + ~variant->clkreg_enable, + host->base + MMCICLOCK); + else + writel(readl(host->base + MMCICLOCK) | + variant->clkreg_enable, + host->base + MMCICLOCK); + } + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc), and the FIFO only accept full 32-bit writes. + * So compensate by adding +3 on the count, a single + * byte become a 32bit write, 7 bytes will be two + * 32bit writes etc. + */ + writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); ptr += count; remain -= count; -- cgit v1.2.2 From b70a67f938e4a7544ca4dea2856b88f3c47669ff Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Dec 2010 09:24:14 +0100 Subject: ARM: 6526/1: mmci: corrected calculation of clock div for ux500 The Ux500 variant of this block has a different divider. The value used right now is too big and which means a loss in performance. This fix corrects it. Also expand the math comments a bit so it's clear what's happening. Further the Ux500 variant does not like if we use the BYPASS bit, instead we are supposed to set the clock divider to zero. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0814b88b44d6..f67fd4f2ab48 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -51,6 +51,7 @@ static unsigned int fmax = 515633; * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when * using DMA. * @sdio: variant supports SDIO + * @st_clkdiv: true if using a ST-specific clock divider algorithm */ struct variant_data { unsigned int clkreg; @@ -61,6 +62,7 @@ struct variant_data { bool broken_blockend; bool broken_blockend_dma; bool sdio; + bool st_clkdiv; }; static struct variant_data variant_arm = { @@ -86,7 +88,9 @@ static struct variant_data variant_ux500 = { .datalength_bits = 24, .broken_blockend = true, .sdio = true, + .st_clkdiv = true, }; + /* * This must be called with host->lock held */ @@ -97,9 +101,30 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (desired) { if (desired >= host->mclk) { - clk = MCI_CLK_BYPASS; + /* + * The ST clock divider does not like the bypass bit, + * even though it's available. Instead the datasheet + * recommends setting the divider to zero. + */ + if (!variant->st_clkdiv) + clk = MCI_CLK_BYPASS; host->cclk = host->mclk; + } else if (variant->st_clkdiv) { + /* + * DB8500 TRM says f = mclk / (clkdiv + 2) + * => clkdiv = (mclk / f) - 2 + * Round the divider up so we don't exceed the max + * frequency + */ + clk = DIV_ROUND_UP(host->mclk, desired) - 2; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (clk + 2); } else { + /* + * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) + * => clkdiv = mclk / (2 * f) - 1 + */ clk = host->mclk / (2 * desired) - 1; if (clk >= 256) clk = 255; -- cgit v1.2.2 From 991a86e182203913b71607f0695955d7e23075d7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 10 Dec 2010 09:35:53 +0100 Subject: ARM: 6530/1: mmci: partially revert clock divisor code I misread the datasheet as if bypass mode was not available at all on the ux500's, I was wrong. It is there, the datasheet just states that you should not have to use it. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index f67fd4f2ab48..0b4a5bf0ec2c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -101,13 +101,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (desired) { if (desired >= host->mclk) { - /* - * The ST clock divider does not like the bypass bit, - * even though it's available. Instead the datasheet - * recommends setting the divider to zero. - */ - if (!variant->st_clkdiv) - clk = MCI_CLK_BYPASS; + clk = MCI_CLK_BYPASS; host->cclk = host->mclk; } else if (variant->st_clkdiv) { /* -- cgit v1.2.2 From 8c11a94d86eb5489dc665bc566bf624e329d89fa Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 28 Dec 2010 19:40:40 +0000 Subject: ARM: mmci: Clean up MMCI announcement printk Make the MMCI announcement printk say which primecell part number has been found. Display the revision as an unsigned decimal, and display only the first 8 hex digits of the base address unless it's larger. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0b4a5bf0ec2c..563022825667 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -960,12 +960,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) amba_set_drvdata(dev, mmc); - mmc_add_host(mmc); - - dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", - mmc_hostname(mmc), amba_rev(dev), amba_config(dev), + dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", + mmc_hostname(mmc), amba_part(dev), amba_rev(dev), (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); + mmc_add_host(mmc); + return 0; irq0_free: -- cgit v1.2.2 From 8cb2815574278a1bf966f041cbfe5b7c91472dcd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 24 Jan 2011 15:22:13 +0100 Subject: ARM: 6632/3: mmci: stop using the blockend interrupts Implement a suggestion from Russell to drop the use of blockend interrupts altogether and instead rely on the data counter. Tested with error-free cards on U300, U8500 and RealView PB1176. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 98 ++++++++++--------------------------------------- 1 file changed, 20 insertions(+), 78 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 563022825667..2de12fe155da 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -46,10 +46,6 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) - * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware - * and will not work at all. - * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when - * using DMA. * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm */ @@ -59,8 +55,6 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; - bool broken_blockend; - bool broken_blockend_dma; bool sdio; bool st_clkdiv; }; @@ -76,7 +70,6 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, - .broken_blockend_dma = true, .sdio = true, }; @@ -86,7 +79,6 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, - .broken_blockend = true, .sdio = true, .st_clkdiv = true, }; @@ -210,8 +202,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; - host->blockend = false; - host->dataend = false; mmci_init_sg(host, data); @@ -288,21 +278,26 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - struct variant_data *variant = host->variant; - /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + u32 remain, success; + + /* Calculate how far we are into the transfer */ + remain = readl(host->base + MMCIDATACNT) << 2; + success = data->blksz * data->blocks - remain; + dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); - if (status & MCI_DATACRCFAIL) + if (status & MCI_DATACRCFAIL) { + /* Last block was not successful */ + host->data_xfered = ((success / data->blksz) - 1 * data->blksz); data->error = -EILSEQ; - else if (status & MCI_DATATIMEOUT) + } else if (status & MCI_DATATIMEOUT) { + host->data_xfered = success; data->error = -ETIMEDOUT; - else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) + } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + host->data_xfered = success; data->error = -EIO; - - /* Force-complete the transaction */ - host->blockend = true; - host->dataend = true; + } /* * We hit an error condition. Ensure that any data @@ -321,61 +316,14 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, } } - /* - * On ARM variants in PIO mode, MCI_DATABLOCKEND - * is always sent first, and we increase the - * transfered number of bytes for that IRQ. Then - * MCI_DATAEND follows and we conclude the transaction. - * - * On the Ux500 single-IRQ variant MCI_DATABLOCKEND - * doesn't seem to immediately clear from the status, - * so we can't use it keep count when only one irq is - * used because the irq will hit for other reasons, and - * then the flag is still up. So we use the MCI_DATAEND - * IRQ at the end of the entire transfer because - * MCI_DATABLOCKEND is broken. - * - * In the U300, the IRQs can arrive out-of-order, - * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, - * so for this case we use the flags "blockend" and - * "dataend" to make sure both IRQs have arrived before - * concluding the transaction. (This does not apply - * to the Ux500 which doesn't fire MCI_DATABLOCKEND - * at all.) In DMA mode it suffers from the same problem - * as the Ux500. - */ - if (status & MCI_DATABLOCKEND) { - /* - * Just being a little over-cautious, we do not - * use this progressive update if the hardware blockend - * flag is unreliable: since it can stay high between - * IRQs it will corrupt the transfer counter. - */ - if (!variant->broken_blockend) - host->data_xfered += data->blksz; - host->blockend = true; - } - - if (status & MCI_DATAEND) - host->dataend = true; + if (status & MCI_DATABLOCKEND) + dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); - /* - * On variants with broken blockend we shall only wait for dataend, - * on others we must sync with the blockend signal since they can - * appear out-of-order. - */ - if (host->dataend && (host->blockend || variant->broken_blockend)) { + if (status & MCI_DATAEND) { mmci_stop_data(host); - /* Reset these flags */ - host->blockend = false; - host->dataend = false; - - /* - * Variants with broken blockend flags need to handle the - * end of the entire transfer here. - */ - if (variant->broken_blockend && !data->error) + if (!data->error) + /* The error clause is handled above, success! */ host->data_xfered += data->blksz * data->blocks; if (!data->stop) { @@ -770,7 +718,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; - unsigned int mask; int ret; /* must have platform data */ @@ -951,12 +898,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto irq0_free; } - mask = MCI_IRQENABLE; - /* Don't use the datablockend flag if it's broken */ - if (variant->broken_blockend) - mask &= ~MCI_DATABLOCKEND; - - writel(mask, host->base + MMCIMASK0); + writel(MCI_IRQENABLE, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); -- cgit v1.2.2 From 9047b435a0b43952f5d1f7eb15a9b63a36efc7f2 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Tue, 11 Jan 2011 16:35:56 +0000 Subject: mmc: mmci: don't read command response when invalid Don't read the command response from the registers when either the command timed out (because there was no response from the card) or the checksum on the response was invalid. Signed-off-by: Russell King Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2de12fe155da..4b8dcd5b2a01 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -342,15 +342,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, host->cmd = NULL; - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); - cmd->resp[2] = readl(base + MMCIRESPONSE2); - cmd->resp[3] = readl(base + MMCIRESPONSE3); - if (status & MCI_CMDTIMEOUT) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; + } else { + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); + cmd->resp[2] = readl(base + MMCIRESPONSE2); + cmd->resp[3] = readl(base + MMCIRESPONSE3); } if (!cmd->data || cmd->error) { -- cgit v1.2.2 From f5a106d9e2a5d947e106c3caace373ded1a695ed Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 27 Jan 2011 17:44:34 +0100 Subject: ARM: 6642/1: mmci: calculate remaining bytes at error correctly The MMCIDATACNT register contain the number of byte left at error not the number of words, so loose the << 2 thing. Further if CRC fails on the first block, we may end up with a negative number of transferred bytes which is not good, and the formula was in wrong order. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4b8dcd5b2a01..b6fd6dcb41e7 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -283,13 +283,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, u32 remain, success; /* Calculate how far we are into the transfer */ - remain = readl(host->base + MMCIDATACNT) << 2; + remain = readl(host->base + MMCIDATACNT); success = data->blksz * data->blocks - remain; dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) { /* Last block was not successful */ - host->data_xfered = ((success / data->blksz) - 1 * data->blksz); + host->data_xfered = ((success - 1) / data->blksz) * data->blksz; data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { host->data_xfered = success; -- cgit v1.2.2 From ccff9b51825b7335889b780bdf7de84ca803e291 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Jan 2011 21:03:50 +0000 Subject: ARM: mmci: complete the transaction on error When we encounter an error, make sure we complete the transaction otherwise we'll leave the request dangling. Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b6fd6dcb41e7..175a623a6a29 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -319,7 +319,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (status & MCI_DATABLOCKEND) dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); - if (status & MCI_DATAEND) { + if (status & MCI_DATAEND || data->error) { mmci_stop_data(host); if (!data->error) -- cgit v1.2.2 From 613b152c63e35095a929f9bb80441cbe91ff5e80 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Jan 2011 21:06:53 +0000 Subject: ARM: mmci: round down the bytes transferred on error We should not report incomplete blocks on error. Return the number of bytes successfully transferred, rounded down to the nearest block. Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 175a623a6a29..2d6de3e03e2d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -289,13 +290,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) { /* Last block was not successful */ - host->data_xfered = ((success - 1) / data->blksz) * data->blksz; + host->data_xfered = round_down(success - 1, data->blksz); data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { - host->data_xfered = success; + host->data_xfered = round_down(success, data->blksz); data->error = -ETIMEDOUT; } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) { - host->data_xfered = success; + host->data_xfered = round_down(success, data->blksz); data->error = -EIO; } -- cgit v1.2.2 From c8afc9d59ce1100d3f7704e86fda5a25361c45bf Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 4 Feb 2011 09:19:46 +0000 Subject: ARM: mmci: avoid reporting too many completed bytes on fifo overrun The data counter counts the number of bytes transferred on the MMC bus. When a FIFO overrun occurs, we will not have transferred a FIFOs-worth of data to memory, and so the data counter will be a FIFOs-worth ahead. If this occurs on a block boundary, we will report one too many sectors as successful. Fix this. Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2d6de3e03e2d..d7b83a8b3534 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -283,22 +283,34 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; - /* Calculate how far we are into the transfer */ + /* + * Calculate how far we are into the transfer. Note that + * the data counter gives the number of bytes transferred + * on the MMC bus, not on the host side. On reads, this + * can be as much as a FIFO-worth of data ahead. This + * matters for FIFO overruns only. + */ remain = readl(host->base + MMCIDATACNT); success = data->blksz * data->blocks - remain; - dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); + dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", + status, success); if (status & MCI_DATACRCFAIL) { /* Last block was not successful */ - host->data_xfered = round_down(success - 1, data->blksz); + success -= 1; data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { - host->data_xfered = round_down(success, data->blksz); data->error = -ETIMEDOUT; - } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) { - host->data_xfered = round_down(success, data->blksz); + } else if (status & MCI_TXUNDERRUN) { + data->error = -EIO; + } else if (status & MCI_RXOVERRUN) { + if (success > host->variant->fifosize) + success -= host->variant->fifosize; + else + success = 0; data->error = -EIO; } + host->data_xfered = round_down(success, data->blksz); /* * We hit an error condition. Ensure that any data -- cgit v1.2.2 From 7d7aa23cf0700f4025cb61bd1ac517ccf79bd460 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 27 Jan 2011 09:46:29 +0000 Subject: ARM: mmci: no need to call flush_dcache_page() with sg_miter API The sg_miter API provides the required cache maintainence, so we don't need to do that ourselves. Remove the unnecessary additional cache maintainence. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index d7b83a8b3534..2563792c01d0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -311,22 +311,6 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -EIO; } host->data_xfered = round_down(success, data->blksz); - - /* - * We hit an error condition. Ensure that any data - * partially written to a page is properly coherent. - */ - if (data->flags & MMC_DATA_READ) { - struct sg_mapping_iter *sg_miter = &host->sg_miter; - unsigned long flags; - - local_irq_save(flags); - if (sg_miter_next(sg_miter)) { - flush_dcache_page(sg_miter->page); - sg_miter_stop(sg_miter); - } - local_irq_restore(flags); - } } if (status & MCI_DATABLOCKEND) @@ -510,9 +494,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) if (remain) break; - if (status & MCI_RXACTIVE) - flush_dcache_page(sg_miter->page); - status = readl(base + MMCISTATUS); } while (1); -- cgit v1.2.2 From c4d877c1b3df58d89f01d7b211f58b944356eea3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 27 Jan 2011 09:50:13 +0000 Subject: ARM: mmci: avoid unnecessary switch to data available PIO interrupts We don't need to switch to data available interrupts if there's at least half a FIFO depth worth of data remaining, as we'll still get the FIFO half full interrupt. Keep this interrupt masked off until we have less than half the FIFO depth worth of data remaining. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2563792c01d0..bde170d8f723 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -224,10 +224,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_RXFIFOHALFFULLMASK; /* - * If we have less than a FIFOSIZE of bytes to transfer, - * trigger a PIO interrupt as soon as any data is available. + * If we have less than the fifo 'half-full' threshold to + * transfer, trigger a PIO interrupt as soon as any data + * is available. */ - if (host->size < variant->fifosize) + if (host->size < variant->fifohalfsize) irqmask |= MCI_RXDATAAVLBLMASK; } else { /* @@ -502,10 +503,10 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) local_irq_restore(flags); /* - * If we're nearing the end of the read, switch to - * "any data available" mode. + * If we have less than the fifo 'half-full' threshold to transfer, + * trigger a PIO interrupt as soon as any data is available. */ - if (status & MCI_RXACTIVE && host->size < variant->fifosize) + if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize) mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* -- cgit v1.2.2 From 51d4375dd72f352594f1a4f1d7598bf9a75b8dfe Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 27 Jan 2011 10:56:52 +0000 Subject: ARM: mmci: no need for separate host->data_xfered We don't need to store the number of bytes transferred in our host structure - we can store this directly in data->bytes_xfered. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index bde170d8f723..db2a358143d6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -142,9 +142,6 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->mrq = NULL; host->cmd = NULL; - if (mrq->data) - mrq->data->bytes_xfered = host->data_xfered; - /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -202,7 +199,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; - host->data_xfered = 0; + data->bytes_xfered = 0; mmci_init_sg(host, data); @@ -311,7 +308,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, success = 0; data->error = -EIO; } - host->data_xfered = round_down(success, data->blksz); + data->bytes_xfered = round_down(success, data->blksz); } if (status & MCI_DATABLOCKEND) @@ -322,7 +319,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (!data->error) /* The error clause is handled above, success! */ - host->data_xfered += data->blksz * data->blocks; + data->bytes_xfered = data->blksz * data->blocks; if (!data->stop) { mmci_request_end(host, data->mrq); -- cgit v1.2.2 From c8ebae37034c0ead62eb4df8ef88e999ddb8d5cf Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 11 Jan 2011 19:35:53 +0000 Subject: ARM: mmci: add dmaengine-based DMA support Based on a patch from Linus Walleij. Add dmaengine based support for DMA to the MMCI driver, using the Primecell DMA engine interface. The changes over Linus' driver are: - rename txsize_threshold to dmasize_threshold, as this reflects the purpose more. - use 'mmci_dma_' as the function prefix rather than 'dma_mmci_'. - clean up requesting of dma channels. - don't release a single channel twice when it's shared between tx and rx. - get rid of 'dma_enable' bool - instead check whether the channel is NULL. - detect incomplete DMA at the end of a transfer. Some DMA controllers (eg, PL08x) are unable to be configured for scatter DMA and also listen to all four DMA request signals [BREQ,SREQ,LBREQ,LSREQ] from the MMCI. They can do one or other but not both. As MMCI uses LBREQ/LSREQ for the final burst/words, PL08x does not transfer the last few words. - map and unmap DMA buffers using the DMA engine struct device, not the MMCI struct device - the DMA engine is doing the DMA transfer, not us. - avoid double-unmapping of the DMA buffers on MMCI data errors. - don't check for negative values from the dmaengine tx submission function - Dan says this must never fail. - use new dmaengine helper functions rather than using the ugly function pointers directly. - allow DMA code to be fully optimized away using dma_inprogress() which is defined to constant 0 if DMA engine support is disabled. - request maximum segment size from the DMA engine struct device and set this appropriately. - removed checking of buffer alignment - the DMA engine should deal with its own restrictions on buffer alignment, not the individual DMA engine users. - removed setting DMAREQCTL - this confuses some DMA controllers as it causes LBREQ to be asserted for the last seven transfers, rather than six SREQ and one LSREQ. - removed burst setting - the DMA controller should not burst past the transfer size required to complete the DMA operation. Tested-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 274 insertions(+), 8 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index db2a358143d6..8a29c9f4a812 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -2,7 +2,7 @@ * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * Copyright (C) 2010 ST-Ericsson AB. + * Copyright (C) 2010 ST-Ericsson SA * * 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 @@ -25,8 +25,10 @@ #include #include #include -#include #include +#include +#include +#include #include #include @@ -186,6 +188,248 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); } +/* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, + * no custom DMA interfaces are supported. + */ +#ifdef CONFIG_DMA_ENGINE +static void __devinit mmci_dma_setup(struct mmci_host *host) +{ + struct mmci_platform_data *plat = host->plat; + const char *rxname, *txname; + dma_cap_mask_t mask; + + if (!plat || !plat->dma_filter) { + dev_info(mmc_dev(host->mmc), "no DMA platform data\n"); + return; + } + + /* Try to acquire a generic DMA engine slave channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* + * If only an RX channel is specified, the driver will + * attempt to use it bidirectionally, however if it is + * is specified but cannot be located, DMA will be disabled. + */ + if (plat->dma_rx_param) { + host->dma_rx_channel = dma_request_channel(mask, + plat->dma_filter, + plat->dma_rx_param); + /* E.g if no DMA hardware is present */ + if (!host->dma_rx_channel) + dev_err(mmc_dev(host->mmc), "no RX DMA channel\n"); + } + + if (plat->dma_tx_param) { + host->dma_tx_channel = dma_request_channel(mask, + plat->dma_filter, + plat->dma_tx_param); + if (!host->dma_tx_channel) + dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n"); + } else { + host->dma_tx_channel = host->dma_rx_channel; + } + + if (host->dma_rx_channel) + rxname = dma_chan_name(host->dma_rx_channel); + else + rxname = "none"; + + if (host->dma_tx_channel) + txname = dma_chan_name(host->dma_tx_channel); + else + txname = "none"; + + dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", + rxname, txname); + + /* + * Limit the maximum segment size in any SG entry according to + * the parameters of the DMA engine device. + */ + if (host->dma_tx_channel) { + struct device *dev = host->dma_tx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } + if (host->dma_rx_channel) { + struct device *dev = host->dma_rx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } +} + +/* + * This is used in __devinit or __devexit so inline it + * so it can be discarded. + */ +static inline void mmci_dma_release(struct mmci_host *host) +{ + struct mmci_platform_data *plat = host->plat; + + if (host->dma_rx_channel) + dma_release_channel(host->dma_rx_channel); + if (host->dma_tx_channel && plat->dma_tx_param) + dma_release_channel(host->dma_tx_channel); + host->dma_rx_channel = host->dma_tx_channel = NULL; +} + +static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +{ + struct dma_chan *chan = host->dma_current; + enum dma_data_direction dir; + u32 status; + int i; + + /* Wait up to 1ms for the DMA to complete */ + for (i = 0; ; i++) { + status = readl(host->base + MMCISTATUS); + if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100) + break; + udelay(10); + } + + /* + * Check to see whether we still have some data left in the FIFO - + * this catches DMA controllers which are unable to monitor the + * DMALBREQ and DMALSREQ signals while allowing us to DMA to non- + * contiguous buffers. On TX, we'll get a FIFO underrun error. + */ + if (status & MCI_RXDATAAVLBLMASK) { + dmaengine_terminate_all(chan); + if (!data->error) + data->error = -EIO; + } + + if (data->flags & MMC_DATA_WRITE) { + dir = DMA_TO_DEVICE; + } else { + dir = DMA_FROM_DEVICE; + } + + dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); + + /* + * Use of DMA with scatter-gather is impossible. + * Give up with DMA and switch back to PIO mode. + */ + if (status & MCI_RXDATAAVLBLMASK) { + dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); + mmci_dma_release(host); + } +} + +static void mmci_dma_data_error(struct mmci_host *host) +{ + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); + dmaengine_terminate_all(host->dma_current); +} + +static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +{ + struct variant_data *variant = host->variant; + struct dma_slave_config conf = { + .src_addr = host->phybase + MMCIFIFO, + .dst_addr = host->phybase + MMCIFIFO, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ + .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ + }; + struct mmc_data *data = host->data; + struct dma_chan *chan; + struct dma_device *device; + struct dma_async_tx_descriptor *desc; + int nr_sg; + + host->dma_current = NULL; + + if (data->flags & MMC_DATA_READ) { + conf.direction = DMA_FROM_DEVICE; + chan = host->dma_rx_channel; + } else { + conf.direction = DMA_TO_DEVICE; + chan = host->dma_tx_channel; + } + + /* If there's no DMA channel, fall back to PIO */ + if (!chan) + return -EINVAL; + + /* If less than or equal to the fifo size, don't bother with DMA */ + if (host->size <= variant->fifosize) + return -EINVAL; + + device = chan->device; + nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction); + if (nr_sg == 0) + return -EINVAL; + + dmaengine_slave_config(chan, &conf); + desc = device->device_prep_slave_sg(chan, data->sg, nr_sg, + conf.direction, DMA_CTRL_ACK); + if (!desc) + goto unmap_exit; + + /* Okay, go for it. */ + host->dma_current = chan; + + dev_vdbg(mmc_dev(host->mmc), + "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", + data->sg_len, data->blksz, data->blocks, data->flags); + dmaengine_submit(desc); + dma_async_issue_pending(chan); + + datactrl |= MCI_DPSM_DMAENABLE; + + /* Trigger the DMA transfer */ + writel(datactrl, host->base + MMCIDATACTRL); + + /* + * Let the MMCI say when the data is ended and it's time + * to fire next DMA request. When that happens, MMCI will + * call mmci_data_end() + */ + writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, + host->base + MMCIMASK0); + return 0; + +unmap_exit: + dmaengine_terminate_all(chan); + dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); + return -ENOMEM; +} +#else +/* Blank functions if the DMA engine is not available */ +static inline void mmci_dma_setup(struct mmci_host *host) +{ +} + +static inline void mmci_dma_release(struct mmci_host *host) +{ +} + +static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +{ +} + +static inline void mmci_dma_data_error(struct mmci_host *host) +{ +} + +static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +{ + return -ENOSYS; +} +#endif + static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { struct variant_data *variant = host->variant; @@ -201,8 +445,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->size = data->blksz * data->blocks; data->bytes_xfered = 0; - mmci_init_sg(host, data); - clks = (unsigned long long)data->timeout_ns * host->cclk; do_div(clks, 1000000000UL); @@ -216,8 +458,21 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) BUG_ON(1 << blksz_bits != data->blksz); datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; - if (data->flags & MMC_DATA_READ) { + + if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; + + /* + * Attempt to use DMA operation mode, if this + * should fail, fall back to PIO mode + */ + if (!mmci_dma_start_data(host, datactrl)) + return; + + /* IRQ mode, map the SG list for CPU reading/writing */ + mmci_init_sg(host, data); + + if (data->flags & MMC_DATA_READ) { irqmask = MCI_RXFIFOHALFFULLMASK; /* @@ -281,6 +536,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) + mmci_dma_data_error(host); + /* * Calculate how far we are into the transfer. Note that * the data counter gives the number of bytes transferred @@ -315,6 +574,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); if (status & MCI_DATAEND || data->error) { + if (dma_inprogress(host)) + mmci_dma_unmap(host, data); mmci_stop_data(host); if (!data->error) @@ -767,6 +1028,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", host->mclk); } + host->phybase = dev->res.start; host->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!host->base) { ret = -ENOMEM; @@ -894,9 +1156,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) amba_set_drvdata(dev, mmc); - dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", - mmc_hostname(mmc), amba_part(dev), amba_rev(dev), - (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); + dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", + mmc_hostname(mmc), amba_part(dev), amba_manf(dev), + amba_rev(dev), (unsigned long long)dev->res.start, + dev->irq[0], dev->irq[1]); + + mmci_dma_setup(host); mmc_add_host(mmc); @@ -943,6 +1208,7 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCICOMMAND); writel(0, host->base + MMCIDATACTRL); + mmci_dma_release(host); free_irq(dev->irq[0], host); if (!host->singleirq) free_irq(dev->irq[1], host); -- cgit v1.2.2 From aa25afad2ca60d19457849ea75e9c31236f4e174 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 19 Feb 2011 15:55:00 +0000 Subject: ARM: amba: make probe() functions take const id tables Make Primecell driver probe functions take a const pointer to their ID tables. Drivers should never modify their ID tables in their probe handler. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2d6de3e03e2d..67f17d61b978 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -713,7 +713,8 @@ static const struct mmc_host_ops mmci_ops = { .get_cd = mmci_get_cd, }; -static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) +static int __devinit mmci_probe(struct amba_device *dev, + const struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; struct variant_data *variant = id->data; -- cgit v1.2.2 From 768fbc1876b3239f4c463c00ea1e78725554cf21 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Fri, 11 Mar 2011 17:18:07 +0000 Subject: mmc: mmci: Add ARM variant with extended FIFO New IO FPGA implementation for Versatile Express boards contain MMCI (PL180) cell with FIFO extended to 128 words (512 bytes). Matt Waddel reports that this patch improves MMC performance on his vexpress system, and also fixes "mmcblk0: error -5 transferring data" errors. Signed-off-by: Pawel Moll Tested-by: Matt Waddel Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5bbb87d10251..b4a7e4fba90f 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -68,6 +68,12 @@ static struct variant_data variant_arm = { .datalength_bits = 16, }; +static struct variant_data variant_arm_extended_fifo = { + .fifosize = 128 * 4, + .fifohalfsize = 64 * 4, + .datalength_bits = 16, +}; + static struct variant_data variant_u300 = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, @@ -1277,9 +1283,14 @@ static int mmci_resume(struct amba_device *dev) static struct amba_id mmci_ids[] = { { .id = 0x00041180, - .mask = 0x000fffff, + .mask = 0xff0fffff, .data = &variant_arm, }, + { + .id = 0x01041180, + .mask = 0xff0fffff, + .data = &variant_arm_extended_fifo, + }, { .id = 0x00041181, .mask = 0x000fffff, -- cgit v1.2.2 From 49ac215e071234b2bf2cff7b8bf4f4f3d0e8cd6e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 4 Mar 2011 14:54:16 +0100 Subject: ARM: 6785/1: mmci: separate out ST Micro register defines The mmci.h header contained a few registers not clearly marked as ST Micro only, rectify this and remove the HWFC magic in the process. The idea is to make the mmci.h header file more ordered so other vendors with PL180 derivates can see where to put in their custom register defines. Includes portions of an earlier patch from Sebastian Rasmussen. Acked-by: Sebastian Rasmussen Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b4a7e4fba90f..92061f8df31e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -77,7 +77,7 @@ static struct variant_data variant_arm_extended_fifo = { static struct variant_data variant_u300 = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, - .clkreg_enable = 1 << 13, /* HWFCEN */ + .clkreg_enable = MCI_ST_U300_HWFCEN, .datalength_bits = 16, .sdio = true, }; @@ -86,7 +86,7 @@ static struct variant_data variant_ux500 = { .fifosize = 30 * 4, .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, - .clkreg_enable = 1 << 14, /* HWFCEN */ + .clkreg_enable = MCI_ST_UX500_HWFCEN, .datalength_bits = 24, .sdio = true, .st_clkdiv = true, -- cgit v1.2.2 From 399bc4863e2a3b4b255ca22189820c81ca34f4e0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Apr 2011 07:59:17 +0100 Subject: ARM: 6858/1: mmci: force negative edge on clock bypass for ux500 This fixes a regression on high clock speeds with the MMCI on ux500. We need to make sure we derive the passthru clock on the falling edge of the incoming clock if it shall work at high frequencies, and on the ux500's there is a special bit for this. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 92061f8df31e..4941e06fe2e1 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -103,6 +103,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (desired) { if (desired >= host->mclk) { clk = MCI_CLK_BYPASS; + if (variant->st_clkdiv) + clk |= MCI_ST_UX500_NEG_EDGE; host->cclk = host->mclk; } else if (variant->st_clkdiv) { /* -- cgit v1.2.2 From 1784b157c89cd2b5e6a3840abfdab6ed51f31d86 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 25 Mar 2011 08:51:52 +0100 Subject: ARM: 6832/1: mmci: support for ST-Ericsson db8500v2 ST-Ericsson modified ARM PrimeCell PL180 block has not got an updated corresponding amba-id, althought the IP block has changed in db8500v2. The change was done to the datactrl register. Using the overrided subversion ID, account for this. Signed-off-by: Philippe Langlais Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4941e06fe2e1..5da5bea0f9f0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -51,6 +51,7 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm + * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register */ struct variant_data { unsigned int clkreg; @@ -60,6 +61,7 @@ struct variant_data { unsigned int fifohalfsize; bool sdio; bool st_clkdiv; + bool blksz_datactrl16; }; static struct variant_data variant_arm = { @@ -92,6 +94,17 @@ static struct variant_data variant_ux500 = { .st_clkdiv = true, }; +static struct variant_data variant_ux500v2 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = MCI_ST_UX500_HWFCEN, + .datalength_bits = 24, + .sdio = true, + .st_clkdiv = true, + .blksz_datactrl16 = true, +}; + /* * This must be called with host->lock held */ @@ -465,7 +478,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) blksz_bits = ffs(data->blksz) - 1; BUG_ON(1 << blksz_bits != data->blksz); - datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; + if (variant->blksz_datactrl16) + datactrl = MCI_DPSM_ENABLE | (data->blksz << 16); + else + datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; @@ -1311,9 +1327,14 @@ static struct amba_id mmci_ids[] = { }, { .id = 0x00480180, - .mask = 0x00ffffff, + .mask = 0xf0ffffff, .data = &variant_ux500, }, + { + .id = 0x10480180, + .mask = 0xf0ffffff, + .data = &variant_ux500v2, + }, { 0, 0 }, }; -- cgit v1.2.2 From 17ee083b7897ab27b4949c42de805889ebd2b4c5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 5 May 2011 17:23:10 +0100 Subject: ARM: 6894/1: mmci: trigger card detect IRQs on falling and rising edges Right now the card detect IRQ for MMCI is requested without any flags which will give some default machine-specified IRQ behaviour. However on the U300 rising+falling edges (such as can be expected from a simple GPIO to generate when inserting/removing a card) need to be requested explicitly. Cc: Rabin Vincent Cc: Ulf Hansson Cc: Sebastian Rasmussen Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5da5bea0f9f0..7721de942c69 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1144,9 +1144,17 @@ static int __devinit mmci_probe(struct amba_device *dev, else if (ret != -ENOSYS) goto err_gpio_cd; + /* + * A gpio pin that will detect cards when inserted and removed + * will most likely want to trigger on the edges if it is + * 0 when ejected and 1 when inserted (or mutatis mutandis + * for the inverted case) so we request triggers on both + * edges. + */ ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), - mmci_cd_irq, 0, - DRIVER_NAME " (cd)", host); + mmci_cd_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRIVER_NAME " (cd)", host); if (ret >= 0) host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } -- cgit v1.2.2 From 757df746fc5db0020ddab45914617a19d149c252 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2011 15:10:21 +0100 Subject: ARM: 6980/1: mmci: use StartBitErr to detect bad connections Stresstesting insert/remove of SD-cards can trigger a StartBitErr. This made the driver to hang in forever waiting for a non ocurring data timeout. This bit and interrupt is documented in the original PL180 TRM, just never implemented until now. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 7721de942c69..fe140724a02e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -582,6 +582,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { data->error = -ETIMEDOUT; + } else if (status & MCI_STARTBITERR) { + data->error = -ECOMM; } else if (status & MCI_TXUNDERRUN) { data->error = -EIO; } else if (status & MCI_RXOVERRUN) { -- cgit v1.2.2