]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/sdhci.c
Merge branch 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied...
[linux-2.6-omap-h63xx.git] / drivers / mmc / sdhci.c
index 8e480140cd289d1bb9550bae7a6682cb89ed77d2..9a7d39b7cdbf43ae3b24df6eed03b8e4c511148b 100644 (file)
@@ -4,8 +4,9 @@
  *  Copyright (C) 2005-2006 Pierre Ossman, 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
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  */
 
 #include <linux/delay.h>
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.11"
+#define DRIVER_VERSION "0.12"
 
 #define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
 
 #define DBG(f, x...) \
        pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
 
+static unsigned int debug_nodma = 0;
+static unsigned int debug_forcedma = 0;
+static unsigned int debug_quirks = 0;
+
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
+#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
+/* Controller doesn't like some resets when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+
 static const struct pci_device_id pci_ids[] __devinitdata = {
-       /* handle any SD host controller */
-       {PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_VENDOR_ID_IBM,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+                                 SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA |
+                                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_TI,
+               .device         = PCI_DEVICE_ID_TI_XX21_XX11_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {       /* Generic SD host controller */
+               PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+       },
+
        { /* end: all zeroes */ },
 };
 
@@ -90,6 +128,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
 
+       if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+                       SDHCI_CARD_PRESENT))
+                       return;
+       }
+
        writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
 
        if (mask & SDHCI_RESET_ALL)
@@ -326,6 +370,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
        DBG("tsac %d ms nsac %d clk\n",
                data->timeout_ns / 1000000, data->timeout_clks);
 
+       /* Sanity checks */
+       BUG_ON(data->blksz * data->blocks > 524288);
+       BUG_ON(data->blksz > host->max_block);
+       BUG_ON(data->blocks > 65535);
+
        /* timeout in us */
        target_timeout = data->timeout_ns / 1000 +
                data->timeout_clks / host->clock;
@@ -375,7 +424,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
                host->remain = host->cur_sg->length;
        }
 
-       writew(data->blksz, host->ioaddr + SDHCI_BLOCK_SIZE);
+       /* We do not handle DMA boundaries, so set it to max (512 KiB) */
+       writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
+               host->ioaddr + SDHCI_BLOCK_SIZE);
        writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
 }
 
@@ -429,9 +480,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
                        "though there were blocks left. Please report this "
                        "to " BUGMAIL ".\n", mmc_hostname(host->mmc));
                data->error = MMC_ERR_FAILED;
-       }
-
-       if (host->size != 0) {
+       } else if (host->size != 0) {
                printk(KERN_ERR "%s: %d bytes were left untransferred. "
                        "Please report this to " BUGMAIL ".\n",
                        mmc_hostname(host->mmc), host->size);
@@ -458,6 +507,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
 static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
        int flags;
+       u32 mask;
        unsigned long timeout;
 
        WARN_ON(host->cmd);
@@ -466,11 +516,20 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        /* Wait max 10 ms */
        timeout = 10;
-       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) &
-               (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
+
+       mask = SDHCI_CMD_INHIBIT;
+       if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+               mask |= SDHCI_DATA_INHIBIT;
+
+       /* We shouldn't wait for data inihibit for stop commands, even
+          though they might use busy signaling */
+       if (host->mrq->data && (cmd == host->mrq->data->stop))
+               mask &= ~SDHCI_DATA_INHIBIT;
+
+       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
                if (timeout == 0) {
                        printk(KERN_ERR "%s: Controller never released "
-                               "inhibit bits. Please report this to "
+                               "inhibit bit(s). Please report this to "
                                BUGMAIL ".\n", mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        cmd->error = MMC_ERR_FAILED;
@@ -516,7 +575,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        if (cmd->data)
                flags |= SDHCI_CMD_DATA;
 
-       writel(SDHCI_MAKE_CMD(cmd->opcode, flags),
+       writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
                host->ioaddr + SDHCI_COMMAND);
 }
 
@@ -667,6 +726,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        } else
                sdhci_send_command(host, mrq->cmd);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -703,6 +763,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                ctrl &= ~SDHCI_CTRL_4BITBUS;
        writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -787,6 +848,19 @@ static void sdhci_tasklet_finish(unsigned long param)
        if ((mrq->cmd->error != MMC_ERR_NONE) ||
                (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
                (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+
+               /* Some controllers need this kick or reset won't work here */
+               if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+                       unsigned int clock;
+
+                       /* This is to force an update */
+                       clock = host->clock;
+                       host->clock = 0;
+                       sdhci_set_clock(host, clock);
+               }
+
+               /* Spec says we should do both at the same time, but Ricoh
+                  controllers do not like that. */
                sdhci_reset(host, SDHCI_RESET_CMD);
                sdhci_reset(host, SDHCI_RESET_DATA);
        }
@@ -797,6 +871,7 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        sdhci_deactivate_led(host);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
        mmc_request_done(host->mmc, mrq);
@@ -830,6 +905,7 @@ static void sdhci_timeout_timer(unsigned long data)
                }
        }
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -909,7 +985,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
        }
 }
 
-static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
        irqreturn_t result;
        struct sdhci_host* host = dev_id;
@@ -967,6 +1043,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
 
        result = IRQ_HANDLED;
 
+       mmiowb();
 out:
        spin_unlock(&host->lock);
 
@@ -1032,6 +1109,7 @@ static int sdhci_resume (struct pci_dev *pdev)
                if (chip->hosts[i]->flags & SDHCI_USE_DMA)
                        pci_set_master(pdev);
                sdhci_init(chip->hosts[i]);
+               mmiowb();
                ret = mmc_resume_host(chip->hosts[i]->mmc);
                if (ret)
                        return ret;
@@ -1056,6 +1134,7 @@ static int sdhci_resume (struct pci_dev *pdev)
 static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 {
        int ret;
+       unsigned int version;
        struct sdhci_chip *chip;
        struct mmc_host *mmc;
        struct sdhci_host *host;
@@ -1087,6 +1166,16 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                return -ENODEV;
        }
 
+       if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
+               return -ENODEV;
+       }
+
+       if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
+               return -ENODEV;
+       }
+
        mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
        if (!mmc)
                return -ENOMEM;
@@ -1094,6 +1183,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        host = mmc_priv(mmc);
        host->mmc = mmc;
 
+       host->chip = chip;
+       chip->hosts[slot] = host;
+
        host->bar = first_bar + slot;
 
        host->addr = pci_resource_start(pdev, host->bar);
@@ -1114,9 +1206,30 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                goto release;
        }
 
+       sdhci_reset(host, SDHCI_RESET_ALL);
+
+       version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+       version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+       if (version != 0) {
+               printk(KERN_ERR "%s: Unknown controller version (%d). "
+                       "You may experience problems.\n", host->slot_descr,
+                       version);
+       }
+
        caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 
-       if ((caps & SDHCI_CAN_DO_DMA) && ((pdev->class & 0x0000FF) == 0x01))
+       if (debug_nodma)
+               DBG("DMA forced off\n");
+       else if (debug_forcedma) {
+               DBG("DMA forced on\n");
+               host->flags |= SDHCI_USE_DMA;
+       } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+               host->flags |= SDHCI_USE_DMA;
+       else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+               DBG("Controller doesn't have DMA interface\n");
+       else if (!(caps & SDHCI_CAN_DO_DMA))
+               DBG("Controller doesn't have DMA capability\n");
+       else
                host->flags |= SDHCI_USE_DMA;
 
        if (host->flags & SDHCI_USE_DMA) {
@@ -1153,13 +1266,22 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        if (caps & SDHCI_TIMEOUT_CLK_UNIT)
                host->timeout_clk *= 1000;
 
+       host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+       if (host->max_block >= 3) {
+               printk(KERN_ERR "%s: Invalid maximum block size.\n",
+                       host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       host->max_block = 512 << host->max_block;
+
        /*
         * Set host parameters.
         */
        mmc->ops = &sdhci_ops;
        mmc->f_min = host->max_clk / 256;
        mmc->f_max = host->max_clk;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
 
        mmc->ocr_avail = 0;
        if (caps & SDHCI_CAN_VDD_330)
@@ -1188,10 +1310,10 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        mmc->max_phys_segs = 16;
 
        /*
-        * Maximum number of sectors in one transfer. Limited by sector
-        * count register.
+        * Maximum number of sectors in one transfer. Limited by DMA boundary
+        * size (512KiB), which means (512 KiB/512=) 1024 entries.
         */
-       mmc->max_sectors = 0x3FFF;
+       mmc->max_sectors = 1024;
 
        /*
         * Maximum segment size. Could be one segment with the maximum number
@@ -1207,9 +1329,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        tasklet_init(&host->finish_tasklet,
                sdhci_tasklet_finish, (unsigned long)host);
 
-       setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
+       setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
-       ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ,
+       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                host->slot_descr, host);
        if (ret)
                goto untasklet;
@@ -1220,8 +1342,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        sdhci_dumpregs(host);
 #endif
 
-       host->chip = chip;
-       chip->hosts[slot] = host;
+       mmiowb();
 
        mmc_add_host(mmc);
 
@@ -1312,6 +1433,10 @@ static int __devinit sdhci_probe(struct pci_dev *pdev,
        }
 
        chip->pdev = pdev;
+       chip->quirks = ent->driver_data;
+
+       if (debug_quirks)
+               chip->quirks = debug_quirks;
 
        chip->num_slots = slots;
        pci_set_drvdata(pdev, chip);
@@ -1390,7 +1515,15 @@ static void __exit sdhci_drv_exit(void)
 module_init(sdhci_drv_init);
 module_exit(sdhci_drv_exit);
 
+module_param(debug_nodma, uint, 0444);
+module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
+
 MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
 MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");