hpt366: clean up DMA timeout handling for HPT370
[powerpc.git] / drivers / mmc / sdhci.c
index e37c814..4bf1fea 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)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
+
 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,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_ENE,
+               .device         = PCI_DEVICE_ID_ENE_CB712_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+       },
+
+       {       /* Generic SD host controller */
+               PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+       },
+
        { /* end: all zeroes */ },
 };
 
@@ -90,6 +137,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)
@@ -153,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
-{
-       host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
-       return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
 {
-       kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+       return page_address(host->cur_sg->page) + host->cur_sg->offset;
 }
 
 static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -196,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
        chunk_remain = 0;
        data = 0;
 
-       buffer = sdhci_kmap_sg(host) + host->offset;
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
 
        while (blksize) {
                if (chunk_remain == 0) {
@@ -220,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
                }
 
                if (host->remain == 0) {
-                       sdhci_kunmap_sg(host);
                        if (sdhci_next_sg(host) == 0) {
                                BUG_ON(blksize != 0);
                                return;
                        }
-                       buffer = sdhci_kmap_sg(host);
+                       buffer = sdhci_sg_to_buffer(host);
                }
        }
-
-       sdhci_kunmap_sg(host);
 }
 
 static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -246,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
        data = 0;
 
        bytes = 0;
-       buffer = sdhci_kmap_sg(host) + host->offset;
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
 
        while (blksize) {
                size = min(host->size, host->remain);
@@ -270,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
                }
 
                if (host->remain == 0) {
-                       sdhci_kunmap_sg(host);
                        if (sdhci_next_sg(host) == 0) {
                                BUG_ON(blksize != 0);
                                return;
                        }
-                       buffer = sdhci_kmap_sg(host);
+                       buffer = sdhci_sg_to_buffer(host);
                }
        }
-
-       sdhci_kunmap_sg(host);
 }
 
 static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -328,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        /* Sanity checks */
        BUG_ON(data->blksz * data->blocks > 524288);
-       BUG_ON(data->blksz > host->max_block);
+       BUG_ON(data->blksz > host->mmc->max_blk_size);
        BUG_ON(data->blocks > 65535);
 
        /* timeout in us */
@@ -436,9 +477,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);
@@ -533,7 +572,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);
 }
 
@@ -574,6 +613,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        int div;
+       u8 ctrl;
        u16 clk;
        unsigned long timeout;
 
@@ -582,6 +622,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 
        writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
 
+       ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+       if (clock > 25000000)
+               ctrl |= SDHCI_CTRL_HISPD;
+       else
+               ctrl &= ~SDHCI_CTRL_HISPD;
+       writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+
        if (clock == 0)
                goto out;
 
@@ -624,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
        if (host->power == power)
                return;
 
-       writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
-       if (power == (unsigned short)-1)
+       if (power == (unsigned short)-1) {
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
                goto out;
+       }
+
+       /*
+        * Spec says that we should clear the power reg before setting
+        * a new value. Some controllers don't seem to like this though.
+        */
+       if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 
        pwr = SDHCI_POWER_ON;
 
@@ -684,6 +738,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);
 }
 
@@ -720,6 +775,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);
 }
 
@@ -740,7 +796,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
        return !(present & SDHCI_WRITE_PROTECT);
 }
 
-static struct mmc_host_ops sdhci_ops = {
+static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
        .set_ios        = sdhci_set_ios,
        .get_ro         = sdhci_get_ro,
@@ -804,6 +860,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);
        }
@@ -814,6 +883,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);
@@ -847,6 +917,7 @@ static void sdhci_timeout_timer(unsigned long data)
                }
        }
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -926,7 +997,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;
@@ -984,6 +1055,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
 
        result = IRQ_HANDLED;
 
+       mmiowb();
 out:
        spin_unlock(&host->lock);
 
@@ -1041,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
-       pci_enable_device(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
 
        for (i = 0;i < chip->num_slots;i++) {
                if (!chip->hosts[i])
@@ -1049,6 +1123,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;
@@ -1101,7 +1176,17 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        }
 
        if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
-               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n");
+               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
+                       "You may experience problems.\n");
+       }
+
+       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;
        }
 
@@ -1112,6 +1197,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);
@@ -1132,19 +1220,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). "
-                       "Cowardly refusing to continue.\n", host->slot_descr,
+                       "You may experience problems.\n", host->slot_descr,
                        version);
-               ret = -ENODEV;
-               goto unmap;
        }
 
        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) {
@@ -1181,31 +1280,29 @@ 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)
                mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
-       else if (caps & SDHCI_CAN_VDD_300)
+       if (caps & SDHCI_CAN_VDD_300)
                mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
-       else if (caps & SDHCI_CAN_VDD_180)
+       if (caps & SDHCI_CAN_VDD_180)
                mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
 
+       if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
+               printk(KERN_ERR "%s: Controller reports > 25 MHz base clock,"
+                       " but no high speed support.\n",
+                       host->slot_descr);
+               mmc->f_max = 25000000;
+       }
+
        if (mmc->ocr_avail == 0) {
                printk(KERN_ERR "%s: Hardware doesn't report any "
                        "support voltages.\n", host->slot_descr);
@@ -1226,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        /*
         * Maximum number of sectors in one transfer. Limited by DMA boundary
-        * size (512KiB), which means (512 KiB/512=) 1024 entries.
+        * size (512KiB).
         */
-       mmc->max_sectors = 1024;
+       mmc->max_req_size = 524288;
 
        /*
         * Maximum segment size. Could be one segment with the maximum number
-        * of sectors.
+        * of bytes.
         */
-       mmc->max_seg_size = mmc->max_sectors * 512;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Maximum block size. This varies from controller to controller and
+        * is specified in the capabilities register.
+        */
+       mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+       if (mmc->max_blk_size >= 3) {
+               printk(KERN_ERR "%s: Invalid maximum block size.\n",
+                       host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+       /*
+        * Maximum block count.
+        */
+       mmc->max_blk_count = 65535;
 
        /*
         * Init tasklets.
@@ -1244,9 +1359,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;
@@ -1257,8 +1372,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);
 
@@ -1349,6 +1463,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);
@@ -1427,7 +1545,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.");