xref: /openbmc/linux/drivers/mmc/host/sdhci.c (revision e08c1694)
11c6a0718SPierre Ossman /*
270f10482SPierre Ossman  *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
31c6a0718SPierre Ossman  *
4b69c9058SPierre Ossman  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
51c6a0718SPierre Ossman  *
61c6a0718SPierre Ossman  * This program is free software; you can redistribute it and/or modify
71c6a0718SPierre Ossman  * it under the terms of the GNU General Public License as published by
81c6a0718SPierre Ossman  * the Free Software Foundation; either version 2 of the License, or (at
91c6a0718SPierre Ossman  * your option) any later version.
1084c46a53SPierre Ossman  *
1184c46a53SPierre Ossman  * Thanks to the following companies for their support:
1284c46a53SPierre Ossman  *
1384c46a53SPierre Ossman  *     - JMicron (hardware and technical support)
141c6a0718SPierre Ossman  */
151c6a0718SPierre Ossman 
161c6a0718SPierre Ossman #include <linux/delay.h>
171c6a0718SPierre Ossman #include <linux/highmem.h>
181c6a0718SPierre Ossman #include <linux/pci.h>
191c6a0718SPierre Ossman #include <linux/dma-mapping.h>
2011763609SRalf Baechle #include <linux/scatterlist.h>
211c6a0718SPierre Ossman 
222f730fecSPierre Ossman #include <linux/leds.h>
232f730fecSPierre Ossman 
241c6a0718SPierre Ossman #include <linux/mmc/host.h>
251c6a0718SPierre Ossman 
261c6a0718SPierre Ossman #include "sdhci.h"
271c6a0718SPierre Ossman 
281c6a0718SPierre Ossman #define DRIVER_NAME "sdhci"
291c6a0718SPierre Ossman 
301c6a0718SPierre Ossman #define DBG(f, x...) \
311c6a0718SPierre Ossman 	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
321c6a0718SPierre Ossman 
331c6a0718SPierre Ossman static unsigned int debug_quirks = 0;
341c6a0718SPierre Ossman 
35dc93441bSPierre Ossman /*
36dc93441bSPierre Ossman  * Different quirks to handle when the hardware deviates from a strict
37dc93441bSPierre Ossman  * interpretation of the SDHCI specification.
38dc93441bSPierre Ossman  */
39dc93441bSPierre Ossman 
40dc93441bSPierre Ossman /* Controller doesn't honor resets unless we touch the clock register */
411c6a0718SPierre Ossman #define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
42dc93441bSPierre Ossman /* Controller has bad caps bits, but really supports DMA */
431c6a0718SPierre Ossman #define SDHCI_QUIRK_FORCE_DMA				(1<<1)
440b82684cSPierre Ossman /* Controller doesn't like to be reset when there is no card inserted. */
451c6a0718SPierre Ossman #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
46dc93441bSPierre Ossman /* Controller doesn't like clearing the power reg before a change */
471c6a0718SPierre Ossman #define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
48dc93441bSPierre Ossman /* Controller has flaky internal state so reset it on each ios change */
49b8352260SLeandro Dorileo #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
50dc93441bSPierre Ossman /* Controller has an unusable DMA engine */
517c168e3dSFeng Tang #define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
52c9fddbc4SPierre Ossman /* Controller can only DMA from 32-bit aligned addresses */
53c9fddbc4SPierre Ossman #define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<6)
54c9fddbc4SPierre Ossman /* Controller can only DMA chunk sizes that are a multiple of 32 bits */
55c9fddbc4SPierre Ossman #define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
5684c46a53SPierre Ossman /* Controller needs to be reset after each request to stay stable */
5784c46a53SPierre Ossman #define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
58e08c1694SAndres Salomon /* Controller needs voltage and power writes to happen separately */
59e08c1694SAndres Salomon #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
601c6a0718SPierre Ossman 
611c6a0718SPierre Ossman static const struct pci_device_id pci_ids[] __devinitdata = {
621c6a0718SPierre Ossman 	{
631c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_RICOH,
641c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
651c6a0718SPierre Ossman 		.subvendor	= PCI_VENDOR_ID_IBM,
661c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
671c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
681c6a0718SPierre Ossman 				  SDHCI_QUIRK_FORCE_DMA,
691c6a0718SPierre Ossman 	},
701c6a0718SPierre Ossman 
711c6a0718SPierre Ossman 	{
721c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_RICOH,
731c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
740b82684cSPierre Ossman 		.subvendor	= PCI_VENDOR_ID_SAMSUNG,
751c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
761c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
771c6a0718SPierre Ossman 				  SDHCI_QUIRK_NO_CARD_NO_RESET,
781c6a0718SPierre Ossman 	},
791c6a0718SPierre Ossman 
801c6a0718SPierre Ossman 	{
810b82684cSPierre Ossman 		.vendor		= PCI_VENDOR_ID_RICOH,
820b82684cSPierre Ossman 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
830b82684cSPierre Ossman 		.subvendor	= PCI_ANY_ID,
840b82684cSPierre Ossman 		.subdevice	= PCI_ANY_ID,
850b82684cSPierre Ossman 		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
860b82684cSPierre Ossman 	},
870b82684cSPierre Ossman 
880b82684cSPierre Ossman 	{
891c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_TI,
901c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
911c6a0718SPierre Ossman 		.subvendor	= PCI_ANY_ID,
921c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
931c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
941c6a0718SPierre Ossman 	},
951c6a0718SPierre Ossman 
961c6a0718SPierre Ossman 	{
971c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_ENE,
981c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
991c6a0718SPierre Ossman 		.subvendor	= PCI_ANY_ID,
1001c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
1017c168e3dSFeng Tang 		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
1027c168e3dSFeng Tang 				  SDHCI_QUIRK_BROKEN_DMA,
1031c6a0718SPierre Ossman 	},
1041c6a0718SPierre Ossman 
1057de064ebSMilko Krachounov 	{
1067de064ebSMilko Krachounov 		.vendor		= PCI_VENDOR_ID_ENE,
1077de064ebSMilko Krachounov 		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
1087de064ebSMilko Krachounov 		.subvendor	= PCI_ANY_ID,
1097de064ebSMilko Krachounov 		.subdevice	= PCI_ANY_ID,
1107c168e3dSFeng Tang 		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
1117c168e3dSFeng Tang 				  SDHCI_QUIRK_BROKEN_DMA,
1127de064ebSMilko Krachounov 	},
1137de064ebSMilko Krachounov 
114b8352260SLeandro Dorileo 	{
115b8352260SLeandro Dorileo 		.vendor         = PCI_VENDOR_ID_ENE,
116b8352260SLeandro Dorileo 		.device         = PCI_DEVICE_ID_ENE_CB714_SD,
117b8352260SLeandro Dorileo 		.subvendor      = PCI_ANY_ID,
118b8352260SLeandro Dorileo 		.subdevice      = PCI_ANY_ID,
119b8352260SLeandro Dorileo 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
120b8352260SLeandro Dorileo 				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
121b8352260SLeandro Dorileo 	},
122b8352260SLeandro Dorileo 
123b8352260SLeandro Dorileo 	{
124b8352260SLeandro Dorileo 		.vendor         = PCI_VENDOR_ID_ENE,
125b8352260SLeandro Dorileo 		.device         = PCI_DEVICE_ID_ENE_CB714_SD_2,
126b8352260SLeandro Dorileo 		.subvendor      = PCI_ANY_ID,
127b8352260SLeandro Dorileo 		.subdevice      = PCI_ANY_ID,
128b8352260SLeandro Dorileo 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
129b8352260SLeandro Dorileo 				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
130b8352260SLeandro Dorileo 	},
131b8352260SLeandro Dorileo 
13284c46a53SPierre Ossman 	{
133e08c1694SAndres Salomon 		.vendor         = PCI_VENDOR_ID_MARVELL,
134e08c1694SAndres Salomon 		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
135e08c1694SAndres Salomon 		.subvendor      = PCI_ANY_ID,
136e08c1694SAndres Salomon 		.subdevice      = PCI_ANY_ID,
137e08c1694SAndres Salomon 		.driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
138e08c1694SAndres Salomon 	},
139e08c1694SAndres Salomon 
140e08c1694SAndres Salomon 	{
14184c46a53SPierre Ossman 		.vendor         = PCI_VENDOR_ID_JMICRON,
14284c46a53SPierre Ossman 		.device         = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
14384c46a53SPierre Ossman 		.subvendor      = PCI_ANY_ID,
14484c46a53SPierre Ossman 		.subdevice      = PCI_ANY_ID,
14584c46a53SPierre Ossman 		.driver_data    = SDHCI_QUIRK_32BIT_DMA_ADDR |
14684c46a53SPierre Ossman 				  SDHCI_QUIRK_32BIT_DMA_SIZE |
14784c46a53SPierre Ossman 				  SDHCI_QUIRK_RESET_AFTER_REQUEST,
14884c46a53SPierre Ossman 	},
14984c46a53SPierre Ossman 
1501c6a0718SPierre Ossman 	{	/* Generic SD host controller */
1511c6a0718SPierre Ossman 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
1521c6a0718SPierre Ossman 	},
1531c6a0718SPierre Ossman 
1541c6a0718SPierre Ossman 	{ /* end: all zeroes */ },
1551c6a0718SPierre Ossman };
1561c6a0718SPierre Ossman 
1571c6a0718SPierre Ossman MODULE_DEVICE_TABLE(pci, pci_ids);
1581c6a0718SPierre Ossman 
1591c6a0718SPierre Ossman static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
1601c6a0718SPierre Ossman static void sdhci_finish_data(struct sdhci_host *);
1611c6a0718SPierre Ossman 
1621c6a0718SPierre Ossman static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
1631c6a0718SPierre Ossman static void sdhci_finish_command(struct sdhci_host *);
1641c6a0718SPierre Ossman 
1651c6a0718SPierre Ossman static void sdhci_dumpregs(struct sdhci_host *host)
1661c6a0718SPierre Ossman {
1671c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
1681c6a0718SPierre Ossman 
1691c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
1701c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
1711c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_HOST_VERSION));
1721c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
1731c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
1741c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
1751c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
1761c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_ARGUMENT),
1771c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
1781c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
1791c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_PRESENT_STATE),
1801c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_HOST_CONTROL));
1811c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
1821c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_POWER_CONTROL),
1831c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
1841c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
1852df3b71bSNicolas Pitre 		readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
1861c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
1871c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
1881c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
1891c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_INT_STATUS));
1901c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
1911c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_INT_ENABLE),
1921c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
1931c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
1941c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_ACMD12_ERR),
1951c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
1961c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
1971c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_CAPABILITIES),
1981c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_MAX_CURRENT));
1991c6a0718SPierre Ossman 
2001c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
2011c6a0718SPierre Ossman }
2021c6a0718SPierre Ossman 
2031c6a0718SPierre Ossman /*****************************************************************************\
2041c6a0718SPierre Ossman  *                                                                           *
2051c6a0718SPierre Ossman  * Low level functions                                                       *
2061c6a0718SPierre Ossman  *                                                                           *
2071c6a0718SPierre Ossman \*****************************************************************************/
2081c6a0718SPierre Ossman 
2091c6a0718SPierre Ossman static void sdhci_reset(struct sdhci_host *host, u8 mask)
2101c6a0718SPierre Ossman {
2111c6a0718SPierre Ossman 	unsigned long timeout;
2121c6a0718SPierre Ossman 
2131c6a0718SPierre Ossman 	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
2141c6a0718SPierre Ossman 		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
2151c6a0718SPierre Ossman 			SDHCI_CARD_PRESENT))
2161c6a0718SPierre Ossman 			return;
2171c6a0718SPierre Ossman 	}
2181c6a0718SPierre Ossman 
2191c6a0718SPierre Ossman 	writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
2201c6a0718SPierre Ossman 
2211c6a0718SPierre Ossman 	if (mask & SDHCI_RESET_ALL)
2221c6a0718SPierre Ossman 		host->clock = 0;
2231c6a0718SPierre Ossman 
2241c6a0718SPierre Ossman 	/* Wait max 100 ms */
2251c6a0718SPierre Ossman 	timeout = 100;
2261c6a0718SPierre Ossman 
2271c6a0718SPierre Ossman 	/* hw clears the bit when it's done */
2281c6a0718SPierre Ossman 	while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
2291c6a0718SPierre Ossman 		if (timeout == 0) {
2301c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
2311c6a0718SPierre Ossman 				mmc_hostname(host->mmc), (int)mask);
2321c6a0718SPierre Ossman 			sdhci_dumpregs(host);
2331c6a0718SPierre Ossman 			return;
2341c6a0718SPierre Ossman 		}
2351c6a0718SPierre Ossman 		timeout--;
2361c6a0718SPierre Ossman 		mdelay(1);
2371c6a0718SPierre Ossman 	}
2381c6a0718SPierre Ossman }
2391c6a0718SPierre Ossman 
2401c6a0718SPierre Ossman static void sdhci_init(struct sdhci_host *host)
2411c6a0718SPierre Ossman {
2421c6a0718SPierre Ossman 	u32 intmask;
2431c6a0718SPierre Ossman 
2441c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
2451c6a0718SPierre Ossman 
2461c6a0718SPierre Ossman 	intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
2471c6a0718SPierre Ossman 		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
2481c6a0718SPierre Ossman 		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
2491c6a0718SPierre Ossman 		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
2501c6a0718SPierre Ossman 		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
2511c6a0718SPierre Ossman 		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
2521c6a0718SPierre Ossman 
2531c6a0718SPierre Ossman 	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
2541c6a0718SPierre Ossman 	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
2551c6a0718SPierre Ossman }
2561c6a0718SPierre Ossman 
2571c6a0718SPierre Ossman static void sdhci_activate_led(struct sdhci_host *host)
2581c6a0718SPierre Ossman {
2591c6a0718SPierre Ossman 	u8 ctrl;
2601c6a0718SPierre Ossman 
2611c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
2621c6a0718SPierre Ossman 	ctrl |= SDHCI_CTRL_LED;
2631c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
2641c6a0718SPierre Ossman }
2651c6a0718SPierre Ossman 
2661c6a0718SPierre Ossman static void sdhci_deactivate_led(struct sdhci_host *host)
2671c6a0718SPierre Ossman {
2681c6a0718SPierre Ossman 	u8 ctrl;
2691c6a0718SPierre Ossman 
2701c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
2711c6a0718SPierre Ossman 	ctrl &= ~SDHCI_CTRL_LED;
2721c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
2731c6a0718SPierre Ossman }
2741c6a0718SPierre Ossman 
2752f730fecSPierre Ossman #ifdef CONFIG_LEDS_CLASS
2762f730fecSPierre Ossman static void sdhci_led_control(struct led_classdev *led,
2772f730fecSPierre Ossman 	enum led_brightness brightness)
2782f730fecSPierre Ossman {
2792f730fecSPierre Ossman 	struct sdhci_host *host = container_of(led, struct sdhci_host, led);
2802f730fecSPierre Ossman 	unsigned long flags;
2812f730fecSPierre Ossman 
2822f730fecSPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
2832f730fecSPierre Ossman 
2842f730fecSPierre Ossman 	if (brightness == LED_OFF)
2852f730fecSPierre Ossman 		sdhci_deactivate_led(host);
2862f730fecSPierre Ossman 	else
2872f730fecSPierre Ossman 		sdhci_activate_led(host);
2882f730fecSPierre Ossman 
2892f730fecSPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
2902f730fecSPierre Ossman }
2912f730fecSPierre Ossman #endif
2922f730fecSPierre Ossman 
2931c6a0718SPierre Ossman /*****************************************************************************\
2941c6a0718SPierre Ossman  *                                                                           *
2951c6a0718SPierre Ossman  * Core functions                                                            *
2961c6a0718SPierre Ossman  *                                                                           *
2971c6a0718SPierre Ossman \*****************************************************************************/
2981c6a0718SPierre Ossman 
2991c6a0718SPierre Ossman static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
3001c6a0718SPierre Ossman {
30145711f1aSJens Axboe 	return sg_virt(host->cur_sg);
3021c6a0718SPierre Ossman }
3031c6a0718SPierre Ossman 
3041c6a0718SPierre Ossman static inline int sdhci_next_sg(struct sdhci_host* host)
3051c6a0718SPierre Ossman {
3061c6a0718SPierre Ossman 	/*
3071c6a0718SPierre Ossman 	 * Skip to next SG entry.
3081c6a0718SPierre Ossman 	 */
3091c6a0718SPierre Ossman 	host->cur_sg++;
3101c6a0718SPierre Ossman 	host->num_sg--;
3111c6a0718SPierre Ossman 
3121c6a0718SPierre Ossman 	/*
3131c6a0718SPierre Ossman 	 * Any entries left?
3141c6a0718SPierre Ossman 	 */
3151c6a0718SPierre Ossman 	if (host->num_sg > 0) {
3161c6a0718SPierre Ossman 		host->offset = 0;
3171c6a0718SPierre Ossman 		host->remain = host->cur_sg->length;
3181c6a0718SPierre Ossman 	}
3191c6a0718SPierre Ossman 
3201c6a0718SPierre Ossman 	return host->num_sg;
3211c6a0718SPierre Ossman }
3221c6a0718SPierre Ossman 
3231c6a0718SPierre Ossman static void sdhci_read_block_pio(struct sdhci_host *host)
3241c6a0718SPierre Ossman {
3251c6a0718SPierre Ossman 	int blksize, chunk_remain;
3261c6a0718SPierre Ossman 	u32 data;
3271c6a0718SPierre Ossman 	char *buffer;
3281c6a0718SPierre Ossman 	int size;
3291c6a0718SPierre Ossman 
3301c6a0718SPierre Ossman 	DBG("PIO reading\n");
3311c6a0718SPierre Ossman 
3321c6a0718SPierre Ossman 	blksize = host->data->blksz;
3331c6a0718SPierre Ossman 	chunk_remain = 0;
3341c6a0718SPierre Ossman 	data = 0;
3351c6a0718SPierre Ossman 
3361c6a0718SPierre Ossman 	buffer = sdhci_sg_to_buffer(host) + host->offset;
3371c6a0718SPierre Ossman 
3381c6a0718SPierre Ossman 	while (blksize) {
3391c6a0718SPierre Ossman 		if (chunk_remain == 0) {
3401c6a0718SPierre Ossman 			data = readl(host->ioaddr + SDHCI_BUFFER);
3411c6a0718SPierre Ossman 			chunk_remain = min(blksize, 4);
3421c6a0718SPierre Ossman 		}
3431c6a0718SPierre Ossman 
3441c6a0718SPierre Ossman 		size = min(host->remain, chunk_remain);
3451c6a0718SPierre Ossman 
3461c6a0718SPierre Ossman 		chunk_remain -= size;
3471c6a0718SPierre Ossman 		blksize -= size;
3481c6a0718SPierre Ossman 		host->offset += size;
3491c6a0718SPierre Ossman 		host->remain -= size;
3501c6a0718SPierre Ossman 
3511c6a0718SPierre Ossman 		while (size) {
3521c6a0718SPierre Ossman 			*buffer = data & 0xFF;
3531c6a0718SPierre Ossman 			buffer++;
3541c6a0718SPierre Ossman 			data >>= 8;
3551c6a0718SPierre Ossman 			size--;
3561c6a0718SPierre Ossman 		}
3571c6a0718SPierre Ossman 
3581c6a0718SPierre Ossman 		if (host->remain == 0) {
3591c6a0718SPierre Ossman 			if (sdhci_next_sg(host) == 0) {
3601c6a0718SPierre Ossman 				BUG_ON(blksize != 0);
3611c6a0718SPierre Ossman 				return;
3621c6a0718SPierre Ossman 			}
3631c6a0718SPierre Ossman 			buffer = sdhci_sg_to_buffer(host);
3641c6a0718SPierre Ossman 		}
3651c6a0718SPierre Ossman 	}
3661c6a0718SPierre Ossman }
3671c6a0718SPierre Ossman 
3681c6a0718SPierre Ossman static void sdhci_write_block_pio(struct sdhci_host *host)
3691c6a0718SPierre Ossman {
3701c6a0718SPierre Ossman 	int blksize, chunk_remain;
3711c6a0718SPierre Ossman 	u32 data;
3721c6a0718SPierre Ossman 	char *buffer;
3731c6a0718SPierre Ossman 	int bytes, size;
3741c6a0718SPierre Ossman 
3751c6a0718SPierre Ossman 	DBG("PIO writing\n");
3761c6a0718SPierre Ossman 
3771c6a0718SPierre Ossman 	blksize = host->data->blksz;
3781c6a0718SPierre Ossman 	chunk_remain = 4;
3791c6a0718SPierre Ossman 	data = 0;
3801c6a0718SPierre Ossman 
3811c6a0718SPierre Ossman 	bytes = 0;
3821c6a0718SPierre Ossman 	buffer = sdhci_sg_to_buffer(host) + host->offset;
3831c6a0718SPierre Ossman 
3841c6a0718SPierre Ossman 	while (blksize) {
3851c6a0718SPierre Ossman 		size = min(host->remain, chunk_remain);
3861c6a0718SPierre Ossman 
3871c6a0718SPierre Ossman 		chunk_remain -= size;
3881c6a0718SPierre Ossman 		blksize -= size;
3891c6a0718SPierre Ossman 		host->offset += size;
3901c6a0718SPierre Ossman 		host->remain -= size;
3911c6a0718SPierre Ossman 
3921c6a0718SPierre Ossman 		while (size) {
3931c6a0718SPierre Ossman 			data >>= 8;
3941c6a0718SPierre Ossman 			data |= (u32)*buffer << 24;
3951c6a0718SPierre Ossman 			buffer++;
3961c6a0718SPierre Ossman 			size--;
3971c6a0718SPierre Ossman 		}
3981c6a0718SPierre Ossman 
3991c6a0718SPierre Ossman 		if (chunk_remain == 0) {
4001c6a0718SPierre Ossman 			writel(data, host->ioaddr + SDHCI_BUFFER);
4011c6a0718SPierre Ossman 			chunk_remain = min(blksize, 4);
4021c6a0718SPierre Ossman 		}
4031c6a0718SPierre Ossman 
4041c6a0718SPierre Ossman 		if (host->remain == 0) {
4051c6a0718SPierre Ossman 			if (sdhci_next_sg(host) == 0) {
4061c6a0718SPierre Ossman 				BUG_ON(blksize != 0);
4071c6a0718SPierre Ossman 				return;
4081c6a0718SPierre Ossman 			}
4091c6a0718SPierre Ossman 			buffer = sdhci_sg_to_buffer(host);
4101c6a0718SPierre Ossman 		}
4111c6a0718SPierre Ossman 	}
4121c6a0718SPierre Ossman }
4131c6a0718SPierre Ossman 
4141c6a0718SPierre Ossman static void sdhci_transfer_pio(struct sdhci_host *host)
4151c6a0718SPierre Ossman {
4161c6a0718SPierre Ossman 	u32 mask;
4171c6a0718SPierre Ossman 
4181c6a0718SPierre Ossman 	BUG_ON(!host->data);
4191c6a0718SPierre Ossman 
4201c6a0718SPierre Ossman 	if (host->num_sg == 0)
4211c6a0718SPierre Ossman 		return;
4221c6a0718SPierre Ossman 
4231c6a0718SPierre Ossman 	if (host->data->flags & MMC_DATA_READ)
4241c6a0718SPierre Ossman 		mask = SDHCI_DATA_AVAILABLE;
4251c6a0718SPierre Ossman 	else
4261c6a0718SPierre Ossman 		mask = SDHCI_SPACE_AVAILABLE;
4271c6a0718SPierre Ossman 
4281c6a0718SPierre Ossman 	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
4291c6a0718SPierre Ossman 		if (host->data->flags & MMC_DATA_READ)
4301c6a0718SPierre Ossman 			sdhci_read_block_pio(host);
4311c6a0718SPierre Ossman 		else
4321c6a0718SPierre Ossman 			sdhci_write_block_pio(host);
4331c6a0718SPierre Ossman 
4341c6a0718SPierre Ossman 		if (host->num_sg == 0)
4351c6a0718SPierre Ossman 			break;
4361c6a0718SPierre Ossman 	}
4371c6a0718SPierre Ossman 
4381c6a0718SPierre Ossman 	DBG("PIO transfer complete.\n");
4391c6a0718SPierre Ossman }
4401c6a0718SPierre Ossman 
4411c6a0718SPierre Ossman static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
4421c6a0718SPierre Ossman {
4431c6a0718SPierre Ossman 	u8 count;
4441c6a0718SPierre Ossman 	unsigned target_timeout, current_timeout;
4451c6a0718SPierre Ossman 
4461c6a0718SPierre Ossman 	WARN_ON(host->data);
4471c6a0718SPierre Ossman 
4481c6a0718SPierre Ossman 	if (data == NULL)
4491c6a0718SPierre Ossman 		return;
4501c6a0718SPierre Ossman 
4511c6a0718SPierre Ossman 	/* Sanity checks */
4521c6a0718SPierre Ossman 	BUG_ON(data->blksz * data->blocks > 524288);
4531c6a0718SPierre Ossman 	BUG_ON(data->blksz > host->mmc->max_blk_size);
4541c6a0718SPierre Ossman 	BUG_ON(data->blocks > 65535);
4551c6a0718SPierre Ossman 
456e538fbe8SPierre Ossman 	host->data = data;
457e538fbe8SPierre Ossman 	host->data_early = 0;
458e538fbe8SPierre Ossman 
4591c6a0718SPierre Ossman 	/* timeout in us */
4601c6a0718SPierre Ossman 	target_timeout = data->timeout_ns / 1000 +
4611c6a0718SPierre Ossman 		data->timeout_clks / host->clock;
4621c6a0718SPierre Ossman 
4631c6a0718SPierre Ossman 	/*
4641c6a0718SPierre Ossman 	 * Figure out needed cycles.
4651c6a0718SPierre Ossman 	 * We do this in steps in order to fit inside a 32 bit int.
4661c6a0718SPierre Ossman 	 * The first step is the minimum timeout, which will have a
4671c6a0718SPierre Ossman 	 * minimum resolution of 6 bits:
4681c6a0718SPierre Ossman 	 * (1) 2^13*1000 > 2^22,
4691c6a0718SPierre Ossman 	 * (2) host->timeout_clk < 2^16
4701c6a0718SPierre Ossman 	 *     =>
4711c6a0718SPierre Ossman 	 *     (1) / (2) > 2^6
4721c6a0718SPierre Ossman 	 */
4731c6a0718SPierre Ossman 	count = 0;
4741c6a0718SPierre Ossman 	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
4751c6a0718SPierre Ossman 	while (current_timeout < target_timeout) {
4761c6a0718SPierre Ossman 		count++;
4771c6a0718SPierre Ossman 		current_timeout <<= 1;
4781c6a0718SPierre Ossman 		if (count >= 0xF)
4791c6a0718SPierre Ossman 			break;
4801c6a0718SPierre Ossman 	}
4811c6a0718SPierre Ossman 
4821c6a0718SPierre Ossman 	if (count >= 0xF) {
4831c6a0718SPierre Ossman 		printk(KERN_WARNING "%s: Too large timeout requested!\n",
4841c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
4851c6a0718SPierre Ossman 		count = 0xE;
4861c6a0718SPierre Ossman 	}
4871c6a0718SPierre Ossman 
4881c6a0718SPierre Ossman 	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
4891c6a0718SPierre Ossman 
490c9fddbc4SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
491c9fddbc4SPierre Ossman 		host->flags |= SDHCI_REQ_USE_DMA;
492c9fddbc4SPierre Ossman 
493c9fddbc4SPierre Ossman 	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
494c9fddbc4SPierre Ossman 		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
495c9fddbc4SPierre Ossman 		((data->blksz * data->blocks) & 0x3))) {
496c9fddbc4SPierre Ossman 		DBG("Reverting to PIO because of transfer size (%d)\n",
497c9fddbc4SPierre Ossman 			data->blksz * data->blocks);
498c9fddbc4SPierre Ossman 		host->flags &= ~SDHCI_REQ_USE_DMA;
499c9fddbc4SPierre Ossman 	}
500c9fddbc4SPierre Ossman 
501c9fddbc4SPierre Ossman 	/*
502c9fddbc4SPierre Ossman 	 * The assumption here being that alignment is the same after
503c9fddbc4SPierre Ossman 	 * translation to device address space.
504c9fddbc4SPierre Ossman 	 */
505c9fddbc4SPierre Ossman 	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
506c9fddbc4SPierre Ossman 		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
507c9fddbc4SPierre Ossman 		(data->sg->offset & 0x3))) {
508c9fddbc4SPierre Ossman 		DBG("Reverting to PIO because of bad alignment\n");
509c9fddbc4SPierre Ossman 		host->flags &= ~SDHCI_REQ_USE_DMA;
510c9fddbc4SPierre Ossman 	}
511c9fddbc4SPierre Ossman 
512c9fddbc4SPierre Ossman 	if (host->flags & SDHCI_REQ_USE_DMA) {
5131c6a0718SPierre Ossman 		int count;
5141c6a0718SPierre Ossman 
5151c6a0718SPierre Ossman 		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
5161c6a0718SPierre Ossman 			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
5171c6a0718SPierre Ossman 		BUG_ON(count != 1);
5181c6a0718SPierre Ossman 
5191c6a0718SPierre Ossman 		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
5201c6a0718SPierre Ossman 	} else {
5211c6a0718SPierre Ossman 		host->cur_sg = data->sg;
5221c6a0718SPierre Ossman 		host->num_sg = data->sg_len;
5231c6a0718SPierre Ossman 
5241c6a0718SPierre Ossman 		host->offset = 0;
5251c6a0718SPierre Ossman 		host->remain = host->cur_sg->length;
5261c6a0718SPierre Ossman 	}
5271c6a0718SPierre Ossman 
5281c6a0718SPierre Ossman 	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
5291c6a0718SPierre Ossman 	writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
5301c6a0718SPierre Ossman 		host->ioaddr + SDHCI_BLOCK_SIZE);
5311c6a0718SPierre Ossman 	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
5321c6a0718SPierre Ossman }
5331c6a0718SPierre Ossman 
5341c6a0718SPierre Ossman static void sdhci_set_transfer_mode(struct sdhci_host *host,
5351c6a0718SPierre Ossman 	struct mmc_data *data)
5361c6a0718SPierre Ossman {
5371c6a0718SPierre Ossman 	u16 mode;
5381c6a0718SPierre Ossman 
5391c6a0718SPierre Ossman 	if (data == NULL)
5401c6a0718SPierre Ossman 		return;
5411c6a0718SPierre Ossman 
542e538fbe8SPierre Ossman 	WARN_ON(!host->data);
543e538fbe8SPierre Ossman 
5441c6a0718SPierre Ossman 	mode = SDHCI_TRNS_BLK_CNT_EN;
5451c6a0718SPierre Ossman 	if (data->blocks > 1)
5461c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_MULTI;
5471c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ)
5481c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_READ;
549c9fddbc4SPierre Ossman 	if (host->flags & SDHCI_REQ_USE_DMA)
5501c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_DMA;
5511c6a0718SPierre Ossman 
5521c6a0718SPierre Ossman 	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
5531c6a0718SPierre Ossman }
5541c6a0718SPierre Ossman 
5551c6a0718SPierre Ossman static void sdhci_finish_data(struct sdhci_host *host)
5561c6a0718SPierre Ossman {
5571c6a0718SPierre Ossman 	struct mmc_data *data;
5581c6a0718SPierre Ossman 	u16 blocks;
5591c6a0718SPierre Ossman 
5601c6a0718SPierre Ossman 	BUG_ON(!host->data);
5611c6a0718SPierre Ossman 
5621c6a0718SPierre Ossman 	data = host->data;
5631c6a0718SPierre Ossman 	host->data = NULL;
5641c6a0718SPierre Ossman 
565c9fddbc4SPierre Ossman 	if (host->flags & SDHCI_REQ_USE_DMA) {
5661c6a0718SPierre Ossman 		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
5671c6a0718SPierre Ossman 			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
5681c6a0718SPierre Ossman 	}
5691c6a0718SPierre Ossman 
5701c6a0718SPierre Ossman 	/*
5711c6a0718SPierre Ossman 	 * Controller doesn't count down when in single block mode.
5721c6a0718SPierre Ossman 	 */
5732b061973SPierre Ossman 	if (data->blocks == 1)
57417b0429dSPierre Ossman 		blocks = (data->error == 0) ? 0 : 1;
5751c6a0718SPierre Ossman 	else
5761c6a0718SPierre Ossman 		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
5771c6a0718SPierre Ossman 	data->bytes_xfered = data->blksz * (data->blocks - blocks);
5781c6a0718SPierre Ossman 
57917b0429dSPierre Ossman 	if (!data->error && blocks) {
5801c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Controller signalled completion even "
5811c6a0718SPierre Ossman 			"though there were blocks left.\n",
5821c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
58317b0429dSPierre Ossman 		data->error = -EIO;
5841c6a0718SPierre Ossman 	}
5851c6a0718SPierre Ossman 
5861c6a0718SPierre Ossman 	if (data->stop) {
5871c6a0718SPierre Ossman 		/*
5881c6a0718SPierre Ossman 		 * The controller needs a reset of internal state machines
5891c6a0718SPierre Ossman 		 * upon error conditions.
5901c6a0718SPierre Ossman 		 */
59117b0429dSPierre Ossman 		if (data->error) {
5921c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_CMD);
5931c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_DATA);
5941c6a0718SPierre Ossman 		}
5951c6a0718SPierre Ossman 
5961c6a0718SPierre Ossman 		sdhci_send_command(host, data->stop);
5971c6a0718SPierre Ossman 	} else
5981c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
5991c6a0718SPierre Ossman }
6001c6a0718SPierre Ossman 
6011c6a0718SPierre Ossman static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
6021c6a0718SPierre Ossman {
6031c6a0718SPierre Ossman 	int flags;
6041c6a0718SPierre Ossman 	u32 mask;
6051c6a0718SPierre Ossman 	unsigned long timeout;
6061c6a0718SPierre Ossman 
6071c6a0718SPierre Ossman 	WARN_ON(host->cmd);
6081c6a0718SPierre Ossman 
6091c6a0718SPierre Ossman 	/* Wait max 10 ms */
6101c6a0718SPierre Ossman 	timeout = 10;
6111c6a0718SPierre Ossman 
6121c6a0718SPierre Ossman 	mask = SDHCI_CMD_INHIBIT;
6131c6a0718SPierre Ossman 	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
6141c6a0718SPierre Ossman 		mask |= SDHCI_DATA_INHIBIT;
6151c6a0718SPierre Ossman 
6161c6a0718SPierre Ossman 	/* We shouldn't wait for data inihibit for stop commands, even
6171c6a0718SPierre Ossman 	   though they might use busy signaling */
6181c6a0718SPierre Ossman 	if (host->mrq->data && (cmd == host->mrq->data->stop))
6191c6a0718SPierre Ossman 		mask &= ~SDHCI_DATA_INHIBIT;
6201c6a0718SPierre Ossman 
6211c6a0718SPierre Ossman 	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
6221c6a0718SPierre Ossman 		if (timeout == 0) {
6231c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Controller never released "
6241c6a0718SPierre Ossman 				"inhibit bit(s).\n", mmc_hostname(host->mmc));
6251c6a0718SPierre Ossman 			sdhci_dumpregs(host);
62617b0429dSPierre Ossman 			cmd->error = -EIO;
6271c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
6281c6a0718SPierre Ossman 			return;
6291c6a0718SPierre Ossman 		}
6301c6a0718SPierre Ossman 		timeout--;
6311c6a0718SPierre Ossman 		mdelay(1);
6321c6a0718SPierre Ossman 	}
6331c6a0718SPierre Ossman 
6341c6a0718SPierre Ossman 	mod_timer(&host->timer, jiffies + 10 * HZ);
6351c6a0718SPierre Ossman 
6361c6a0718SPierre Ossman 	host->cmd = cmd;
6371c6a0718SPierre Ossman 
6381c6a0718SPierre Ossman 	sdhci_prepare_data(host, cmd->data);
6391c6a0718SPierre Ossman 
6401c6a0718SPierre Ossman 	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
6411c6a0718SPierre Ossman 
6421c6a0718SPierre Ossman 	sdhci_set_transfer_mode(host, cmd->data);
6431c6a0718SPierre Ossman 
6441c6a0718SPierre Ossman 	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
6451c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unsupported response type!\n",
6461c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
64717b0429dSPierre Ossman 		cmd->error = -EINVAL;
6481c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
6491c6a0718SPierre Ossman 		return;
6501c6a0718SPierre Ossman 	}
6511c6a0718SPierre Ossman 
6521c6a0718SPierre Ossman 	if (!(cmd->flags & MMC_RSP_PRESENT))
6531c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_NONE;
6541c6a0718SPierre Ossman 	else if (cmd->flags & MMC_RSP_136)
6551c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_LONG;
6561c6a0718SPierre Ossman 	else if (cmd->flags & MMC_RSP_BUSY)
6571c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_SHORT_BUSY;
6581c6a0718SPierre Ossman 	else
6591c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_SHORT;
6601c6a0718SPierre Ossman 
6611c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_CRC)
6621c6a0718SPierre Ossman 		flags |= SDHCI_CMD_CRC;
6631c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_OPCODE)
6641c6a0718SPierre Ossman 		flags |= SDHCI_CMD_INDEX;
6651c6a0718SPierre Ossman 	if (cmd->data)
6661c6a0718SPierre Ossman 		flags |= SDHCI_CMD_DATA;
6671c6a0718SPierre Ossman 
6681c6a0718SPierre Ossman 	writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
6691c6a0718SPierre Ossman 		host->ioaddr + SDHCI_COMMAND);
6701c6a0718SPierre Ossman }
6711c6a0718SPierre Ossman 
6721c6a0718SPierre Ossman static void sdhci_finish_command(struct sdhci_host *host)
6731c6a0718SPierre Ossman {
6741c6a0718SPierre Ossman 	int i;
6751c6a0718SPierre Ossman 
6761c6a0718SPierre Ossman 	BUG_ON(host->cmd == NULL);
6771c6a0718SPierre Ossman 
6781c6a0718SPierre Ossman 	if (host->cmd->flags & MMC_RSP_PRESENT) {
6791c6a0718SPierre Ossman 		if (host->cmd->flags & MMC_RSP_136) {
6801c6a0718SPierre Ossman 			/* CRC is stripped so we need to do some shifting. */
6811c6a0718SPierre Ossman 			for (i = 0;i < 4;i++) {
6821c6a0718SPierre Ossman 				host->cmd->resp[i] = readl(host->ioaddr +
6831c6a0718SPierre Ossman 					SDHCI_RESPONSE + (3-i)*4) << 8;
6841c6a0718SPierre Ossman 				if (i != 3)
6851c6a0718SPierre Ossman 					host->cmd->resp[i] |=
6861c6a0718SPierre Ossman 						readb(host->ioaddr +
6871c6a0718SPierre Ossman 						SDHCI_RESPONSE + (3-i)*4-1);
6881c6a0718SPierre Ossman 			}
6891c6a0718SPierre Ossman 		} else {
6901c6a0718SPierre Ossman 			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
6911c6a0718SPierre Ossman 		}
6921c6a0718SPierre Ossman 	}
6931c6a0718SPierre Ossman 
69417b0429dSPierre Ossman 	host->cmd->error = 0;
6951c6a0718SPierre Ossman 
696e538fbe8SPierre Ossman 	if (host->data && host->data_early)
697e538fbe8SPierre Ossman 		sdhci_finish_data(host);
698e538fbe8SPierre Ossman 
699e538fbe8SPierre Ossman 	if (!host->cmd->data)
7001c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
7011c6a0718SPierre Ossman 
7021c6a0718SPierre Ossman 	host->cmd = NULL;
7031c6a0718SPierre Ossman }
7041c6a0718SPierre Ossman 
7051c6a0718SPierre Ossman static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
7061c6a0718SPierre Ossman {
7071c6a0718SPierre Ossman 	int div;
7081c6a0718SPierre Ossman 	u16 clk;
7091c6a0718SPierre Ossman 	unsigned long timeout;
7101c6a0718SPierre Ossman 
7111c6a0718SPierre Ossman 	if (clock == host->clock)
7121c6a0718SPierre Ossman 		return;
7131c6a0718SPierre Ossman 
7141c6a0718SPierre Ossman 	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
7151c6a0718SPierre Ossman 
7161c6a0718SPierre Ossman 	if (clock == 0)
7171c6a0718SPierre Ossman 		goto out;
7181c6a0718SPierre Ossman 
7191c6a0718SPierre Ossman 	for (div = 1;div < 256;div *= 2) {
7201c6a0718SPierre Ossman 		if ((host->max_clk / div) <= clock)
7211c6a0718SPierre Ossman 			break;
7221c6a0718SPierre Ossman 	}
7231c6a0718SPierre Ossman 	div >>= 1;
7241c6a0718SPierre Ossman 
7251c6a0718SPierre Ossman 	clk = div << SDHCI_DIVIDER_SHIFT;
7261c6a0718SPierre Ossman 	clk |= SDHCI_CLOCK_INT_EN;
7271c6a0718SPierre Ossman 	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
7281c6a0718SPierre Ossman 
7291c6a0718SPierre Ossman 	/* Wait max 10 ms */
7301c6a0718SPierre Ossman 	timeout = 10;
7311c6a0718SPierre Ossman 	while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
7321c6a0718SPierre Ossman 		& SDHCI_CLOCK_INT_STABLE)) {
7331c6a0718SPierre Ossman 		if (timeout == 0) {
7341c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Internal clock never "
7351c6a0718SPierre Ossman 				"stabilised.\n", mmc_hostname(host->mmc));
7361c6a0718SPierre Ossman 			sdhci_dumpregs(host);
7371c6a0718SPierre Ossman 			return;
7381c6a0718SPierre Ossman 		}
7391c6a0718SPierre Ossman 		timeout--;
7401c6a0718SPierre Ossman 		mdelay(1);
7411c6a0718SPierre Ossman 	}
7421c6a0718SPierre Ossman 
7431c6a0718SPierre Ossman 	clk |= SDHCI_CLOCK_CARD_EN;
7441c6a0718SPierre Ossman 	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
7451c6a0718SPierre Ossman 
7461c6a0718SPierre Ossman out:
7471c6a0718SPierre Ossman 	host->clock = clock;
7481c6a0718SPierre Ossman }
7491c6a0718SPierre Ossman 
7501c6a0718SPierre Ossman static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
7511c6a0718SPierre Ossman {
7521c6a0718SPierre Ossman 	u8 pwr;
7531c6a0718SPierre Ossman 
7541c6a0718SPierre Ossman 	if (host->power == power)
7551c6a0718SPierre Ossman 		return;
7561c6a0718SPierre Ossman 
7571c6a0718SPierre Ossman 	if (power == (unsigned short)-1) {
7581c6a0718SPierre Ossman 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
7591c6a0718SPierre Ossman 		goto out;
7601c6a0718SPierre Ossman 	}
7611c6a0718SPierre Ossman 
7621c6a0718SPierre Ossman 	/*
7631c6a0718SPierre Ossman 	 * Spec says that we should clear the power reg before setting
7641c6a0718SPierre Ossman 	 * a new value. Some controllers don't seem to like this though.
7651c6a0718SPierre Ossman 	 */
7661c6a0718SPierre Ossman 	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
7671c6a0718SPierre Ossman 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
7681c6a0718SPierre Ossman 
7691c6a0718SPierre Ossman 	pwr = SDHCI_POWER_ON;
7701c6a0718SPierre Ossman 
7714be34c99SPhilip Langdale 	switch (1 << power) {
77255556da0SPhilip Langdale 	case MMC_VDD_165_195:
7731c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_180;
7741c6a0718SPierre Ossman 		break;
7754be34c99SPhilip Langdale 	case MMC_VDD_29_30:
7764be34c99SPhilip Langdale 	case MMC_VDD_30_31:
7771c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_300;
7781c6a0718SPierre Ossman 		break;
7794be34c99SPhilip Langdale 	case MMC_VDD_32_33:
7804be34c99SPhilip Langdale 	case MMC_VDD_33_34:
7811c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_330;
7821c6a0718SPierre Ossman 		break;
7831c6a0718SPierre Ossman 	default:
7841c6a0718SPierre Ossman 		BUG();
7851c6a0718SPierre Ossman 	}
7861c6a0718SPierre Ossman 
787e08c1694SAndres Salomon 	/*
788e08c1694SAndres Salomon 	 * At least the CaFe chip gets confused if we set the voltage
789e08c1694SAndres Salomon 	 * and set turn on power at the same time, so set the voltage first.
790e08c1694SAndres Salomon 	 */
791e08c1694SAndres Salomon 	if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
792e08c1694SAndres Salomon 		writeb(pwr & ~SDHCI_POWER_ON,
793e08c1694SAndres Salomon 				host->ioaddr + SDHCI_POWER_CONTROL);
794e08c1694SAndres Salomon 
7951c6a0718SPierre Ossman 	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
7961c6a0718SPierre Ossman 
7971c6a0718SPierre Ossman out:
7981c6a0718SPierre Ossman 	host->power = power;
7991c6a0718SPierre Ossman }
8001c6a0718SPierre Ossman 
8011c6a0718SPierre Ossman /*****************************************************************************\
8021c6a0718SPierre Ossman  *                                                                           *
8031c6a0718SPierre Ossman  * MMC callbacks                                                             *
8041c6a0718SPierre Ossman  *                                                                           *
8051c6a0718SPierre Ossman \*****************************************************************************/
8061c6a0718SPierre Ossman 
8071c6a0718SPierre Ossman static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
8081c6a0718SPierre Ossman {
8091c6a0718SPierre Ossman 	struct sdhci_host *host;
8101c6a0718SPierre Ossman 	unsigned long flags;
8111c6a0718SPierre Ossman 
8121c6a0718SPierre Ossman 	host = mmc_priv(mmc);
8131c6a0718SPierre Ossman 
8141c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8151c6a0718SPierre Ossman 
8161c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
8171c6a0718SPierre Ossman 
8182f730fecSPierre Ossman #ifndef CONFIG_LEDS_CLASS
8191c6a0718SPierre Ossman 	sdhci_activate_led(host);
8202f730fecSPierre Ossman #endif
8211c6a0718SPierre Ossman 
8221c6a0718SPierre Ossman 	host->mrq = mrq;
8231c6a0718SPierre Ossman 
8241c6a0718SPierre Ossman 	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
82517b0429dSPierre Ossman 		host->mrq->cmd->error = -ENOMEDIUM;
8261c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
8271c6a0718SPierre Ossman 	} else
8281c6a0718SPierre Ossman 		sdhci_send_command(host, mrq->cmd);
8291c6a0718SPierre Ossman 
8301c6a0718SPierre Ossman 	mmiowb();
8311c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
8321c6a0718SPierre Ossman }
8331c6a0718SPierre Ossman 
8341c6a0718SPierre Ossman static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
8351c6a0718SPierre Ossman {
8361c6a0718SPierre Ossman 	struct sdhci_host *host;
8371c6a0718SPierre Ossman 	unsigned long flags;
8381c6a0718SPierre Ossman 	u8 ctrl;
8391c6a0718SPierre Ossman 
8401c6a0718SPierre Ossman 	host = mmc_priv(mmc);
8411c6a0718SPierre Ossman 
8421c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8431c6a0718SPierre Ossman 
8441c6a0718SPierre Ossman 	/*
8451c6a0718SPierre Ossman 	 * Reset the chip on each power off.
8461c6a0718SPierre Ossman 	 * Should clear out any weird states.
8471c6a0718SPierre Ossman 	 */
8481c6a0718SPierre Ossman 	if (ios->power_mode == MMC_POWER_OFF) {
8491c6a0718SPierre Ossman 		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
8501c6a0718SPierre Ossman 		sdhci_init(host);
8511c6a0718SPierre Ossman 	}
8521c6a0718SPierre Ossman 
8531c6a0718SPierre Ossman 	sdhci_set_clock(host, ios->clock);
8541c6a0718SPierre Ossman 
8551c6a0718SPierre Ossman 	if (ios->power_mode == MMC_POWER_OFF)
8561c6a0718SPierre Ossman 		sdhci_set_power(host, -1);
8571c6a0718SPierre Ossman 	else
8581c6a0718SPierre Ossman 		sdhci_set_power(host, ios->vdd);
8591c6a0718SPierre Ossman 
8601c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
8611c6a0718SPierre Ossman 
8621c6a0718SPierre Ossman 	if (ios->bus_width == MMC_BUS_WIDTH_4)
8631c6a0718SPierre Ossman 		ctrl |= SDHCI_CTRL_4BITBUS;
8641c6a0718SPierre Ossman 	else
8651c6a0718SPierre Ossman 		ctrl &= ~SDHCI_CTRL_4BITBUS;
8661c6a0718SPierre Ossman 
8671c6a0718SPierre Ossman 	if (ios->timing == MMC_TIMING_SD_HS)
8681c6a0718SPierre Ossman 		ctrl |= SDHCI_CTRL_HISPD;
8691c6a0718SPierre Ossman 	else
8701c6a0718SPierre Ossman 		ctrl &= ~SDHCI_CTRL_HISPD;
8711c6a0718SPierre Ossman 
8721c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
8731c6a0718SPierre Ossman 
874b8352260SLeandro Dorileo 	/*
875b8352260SLeandro Dorileo 	 * Some (ENE) controllers go apeshit on some ios operation,
876b8352260SLeandro Dorileo 	 * signalling timeout and CRC errors even on CMD0. Resetting
877b8352260SLeandro Dorileo 	 * it on each ios seems to solve the problem.
878b8352260SLeandro Dorileo 	 */
879b8352260SLeandro Dorileo 	if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
880b8352260SLeandro Dorileo 		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
881b8352260SLeandro Dorileo 
8821c6a0718SPierre Ossman 	mmiowb();
8831c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
8841c6a0718SPierre Ossman }
8851c6a0718SPierre Ossman 
8861c6a0718SPierre Ossman static int sdhci_get_ro(struct mmc_host *mmc)
8871c6a0718SPierre Ossman {
8881c6a0718SPierre Ossman 	struct sdhci_host *host;
8891c6a0718SPierre Ossman 	unsigned long flags;
8901c6a0718SPierre Ossman 	int present;
8911c6a0718SPierre Ossman 
8921c6a0718SPierre Ossman 	host = mmc_priv(mmc);
8931c6a0718SPierre Ossman 
8941c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8951c6a0718SPierre Ossman 
8961c6a0718SPierre Ossman 	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
8971c6a0718SPierre Ossman 
8981c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
8991c6a0718SPierre Ossman 
9001c6a0718SPierre Ossman 	return !(present & SDHCI_WRITE_PROTECT);
9011c6a0718SPierre Ossman }
9021c6a0718SPierre Ossman 
903f75979b7SPierre Ossman static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
904f75979b7SPierre Ossman {
905f75979b7SPierre Ossman 	struct sdhci_host *host;
906f75979b7SPierre Ossman 	unsigned long flags;
907f75979b7SPierre Ossman 	u32 ier;
908f75979b7SPierre Ossman 
909f75979b7SPierre Ossman 	host = mmc_priv(mmc);
910f75979b7SPierre Ossman 
911f75979b7SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
912f75979b7SPierre Ossman 
913f75979b7SPierre Ossman 	ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
914f75979b7SPierre Ossman 
915f75979b7SPierre Ossman 	ier &= ~SDHCI_INT_CARD_INT;
916f75979b7SPierre Ossman 	if (enable)
917f75979b7SPierre Ossman 		ier |= SDHCI_INT_CARD_INT;
918f75979b7SPierre Ossman 
919f75979b7SPierre Ossman 	writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
920f75979b7SPierre Ossman 	writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
921f75979b7SPierre Ossman 
922f75979b7SPierre Ossman 	mmiowb();
923f75979b7SPierre Ossman 
924f75979b7SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
925f75979b7SPierre Ossman }
926f75979b7SPierre Ossman 
9271c6a0718SPierre Ossman static const struct mmc_host_ops sdhci_ops = {
9281c6a0718SPierre Ossman 	.request	= sdhci_request,
9291c6a0718SPierre Ossman 	.set_ios	= sdhci_set_ios,
9301c6a0718SPierre Ossman 	.get_ro		= sdhci_get_ro,
931f75979b7SPierre Ossman 	.enable_sdio_irq = sdhci_enable_sdio_irq,
9321c6a0718SPierre Ossman };
9331c6a0718SPierre Ossman 
9341c6a0718SPierre Ossman /*****************************************************************************\
9351c6a0718SPierre Ossman  *                                                                           *
9361c6a0718SPierre Ossman  * Tasklets                                                                  *
9371c6a0718SPierre Ossman  *                                                                           *
9381c6a0718SPierre Ossman \*****************************************************************************/
9391c6a0718SPierre Ossman 
9401c6a0718SPierre Ossman static void sdhci_tasklet_card(unsigned long param)
9411c6a0718SPierre Ossman {
9421c6a0718SPierre Ossman 	struct sdhci_host *host;
9431c6a0718SPierre Ossman 	unsigned long flags;
9441c6a0718SPierre Ossman 
9451c6a0718SPierre Ossman 	host = (struct sdhci_host*)param;
9461c6a0718SPierre Ossman 
9471c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
9481c6a0718SPierre Ossman 
9491c6a0718SPierre Ossman 	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
9501c6a0718SPierre Ossman 		if (host->mrq) {
9511c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Card removed during transfer!\n",
9521c6a0718SPierre Ossman 				mmc_hostname(host->mmc));
9531c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Resetting controller.\n",
9541c6a0718SPierre Ossman 				mmc_hostname(host->mmc));
9551c6a0718SPierre Ossman 
9561c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_CMD);
9571c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_DATA);
9581c6a0718SPierre Ossman 
95917b0429dSPierre Ossman 			host->mrq->cmd->error = -ENOMEDIUM;
9601c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
9611c6a0718SPierre Ossman 		}
9621c6a0718SPierre Ossman 	}
9631c6a0718SPierre Ossman 
9641c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
9651c6a0718SPierre Ossman 
9661c6a0718SPierre Ossman 	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
9671c6a0718SPierre Ossman }
9681c6a0718SPierre Ossman 
9691c6a0718SPierre Ossman static void sdhci_tasklet_finish(unsigned long param)
9701c6a0718SPierre Ossman {
9711c6a0718SPierre Ossman 	struct sdhci_host *host;
9721c6a0718SPierre Ossman 	unsigned long flags;
9731c6a0718SPierre Ossman 	struct mmc_request *mrq;
9741c6a0718SPierre Ossman 
9751c6a0718SPierre Ossman 	host = (struct sdhci_host*)param;
9761c6a0718SPierre Ossman 
9771c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
9781c6a0718SPierre Ossman 
9791c6a0718SPierre Ossman 	del_timer(&host->timer);
9801c6a0718SPierre Ossman 
9811c6a0718SPierre Ossman 	mrq = host->mrq;
9821c6a0718SPierre Ossman 
9831c6a0718SPierre Ossman 	/*
9841c6a0718SPierre Ossman 	 * The controller needs a reset of internal state machines
9851c6a0718SPierre Ossman 	 * upon error conditions.
9861c6a0718SPierre Ossman 	 */
98717b0429dSPierre Ossman 	if (mrq->cmd->error ||
98817b0429dSPierre Ossman 		(mrq->data && (mrq->data->error ||
98984c46a53SPierre Ossman 		(mrq->data->stop && mrq->data->stop->error))) ||
99084c46a53SPierre Ossman 		(host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
9911c6a0718SPierre Ossman 
9921c6a0718SPierre Ossman 		/* Some controllers need this kick or reset won't work here */
9931c6a0718SPierre Ossman 		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
9941c6a0718SPierre Ossman 			unsigned int clock;
9951c6a0718SPierre Ossman 
9961c6a0718SPierre Ossman 			/* This is to force an update */
9971c6a0718SPierre Ossman 			clock = host->clock;
9981c6a0718SPierre Ossman 			host->clock = 0;
9991c6a0718SPierre Ossman 			sdhci_set_clock(host, clock);
10001c6a0718SPierre Ossman 		}
10011c6a0718SPierre Ossman 
10021c6a0718SPierre Ossman 		/* Spec says we should do both at the same time, but Ricoh
10031c6a0718SPierre Ossman 		   controllers do not like that. */
10041c6a0718SPierre Ossman 		sdhci_reset(host, SDHCI_RESET_CMD);
10051c6a0718SPierre Ossman 		sdhci_reset(host, SDHCI_RESET_DATA);
10061c6a0718SPierre Ossman 	}
10071c6a0718SPierre Ossman 
10081c6a0718SPierre Ossman 	host->mrq = NULL;
10091c6a0718SPierre Ossman 	host->cmd = NULL;
10101c6a0718SPierre Ossman 	host->data = NULL;
10111c6a0718SPierre Ossman 
10122f730fecSPierre Ossman #ifndef CONFIG_LEDS_CLASS
10131c6a0718SPierre Ossman 	sdhci_deactivate_led(host);
10142f730fecSPierre Ossman #endif
10151c6a0718SPierre Ossman 
10161c6a0718SPierre Ossman 	mmiowb();
10171c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
10181c6a0718SPierre Ossman 
10191c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
10201c6a0718SPierre Ossman }
10211c6a0718SPierre Ossman 
10221c6a0718SPierre Ossman static void sdhci_timeout_timer(unsigned long data)
10231c6a0718SPierre Ossman {
10241c6a0718SPierre Ossman 	struct sdhci_host *host;
10251c6a0718SPierre Ossman 	unsigned long flags;
10261c6a0718SPierre Ossman 
10271c6a0718SPierre Ossman 	host = (struct sdhci_host*)data;
10281c6a0718SPierre Ossman 
10291c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
10301c6a0718SPierre Ossman 
10311c6a0718SPierre Ossman 	if (host->mrq) {
10321c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Timeout waiting for hardware "
10331c6a0718SPierre Ossman 			"interrupt.\n", mmc_hostname(host->mmc));
10341c6a0718SPierre Ossman 		sdhci_dumpregs(host);
10351c6a0718SPierre Ossman 
10361c6a0718SPierre Ossman 		if (host->data) {
103717b0429dSPierre Ossman 			host->data->error = -ETIMEDOUT;
10381c6a0718SPierre Ossman 			sdhci_finish_data(host);
10391c6a0718SPierre Ossman 		} else {
10401c6a0718SPierre Ossman 			if (host->cmd)
104117b0429dSPierre Ossman 				host->cmd->error = -ETIMEDOUT;
10421c6a0718SPierre Ossman 			else
104317b0429dSPierre Ossman 				host->mrq->cmd->error = -ETIMEDOUT;
10441c6a0718SPierre Ossman 
10451c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
10461c6a0718SPierre Ossman 		}
10471c6a0718SPierre Ossman 	}
10481c6a0718SPierre Ossman 
10491c6a0718SPierre Ossman 	mmiowb();
10501c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
10511c6a0718SPierre Ossman }
10521c6a0718SPierre Ossman 
10531c6a0718SPierre Ossman /*****************************************************************************\
10541c6a0718SPierre Ossman  *                                                                           *
10551c6a0718SPierre Ossman  * Interrupt handling                                                        *
10561c6a0718SPierre Ossman  *                                                                           *
10571c6a0718SPierre Ossman \*****************************************************************************/
10581c6a0718SPierre Ossman 
10591c6a0718SPierre Ossman static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
10601c6a0718SPierre Ossman {
10611c6a0718SPierre Ossman 	BUG_ON(intmask == 0);
10621c6a0718SPierre Ossman 
10631c6a0718SPierre Ossman 	if (!host->cmd) {
1064b67ac3f3SPierre Ossman 		printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
1065b67ac3f3SPierre Ossman 			"though no command operation was in progress.\n",
1066b67ac3f3SPierre Ossman 			mmc_hostname(host->mmc), (unsigned)intmask);
10671c6a0718SPierre Ossman 		sdhci_dumpregs(host);
10681c6a0718SPierre Ossman 		return;
10691c6a0718SPierre Ossman 	}
10701c6a0718SPierre Ossman 
10711c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_TIMEOUT)
107217b0429dSPierre Ossman 		host->cmd->error = -ETIMEDOUT;
107317b0429dSPierre Ossman 	else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
107417b0429dSPierre Ossman 			SDHCI_INT_INDEX))
107517b0429dSPierre Ossman 		host->cmd->error = -EILSEQ;
10761c6a0718SPierre Ossman 
107717b0429dSPierre Ossman 	if (host->cmd->error)
10781c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
107943b58b36SPierre Ossman 	else if (intmask & SDHCI_INT_RESPONSE)
108043b58b36SPierre Ossman 		sdhci_finish_command(host);
10811c6a0718SPierre Ossman }
10821c6a0718SPierre Ossman 
10831c6a0718SPierre Ossman static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
10841c6a0718SPierre Ossman {
10851c6a0718SPierre Ossman 	BUG_ON(intmask == 0);
10861c6a0718SPierre Ossman 
10871c6a0718SPierre Ossman 	if (!host->data) {
10881c6a0718SPierre Ossman 		/*
10891c6a0718SPierre Ossman 		 * A data end interrupt is sent together with the response
10901c6a0718SPierre Ossman 		 * for the stop command.
10911c6a0718SPierre Ossman 		 */
10921c6a0718SPierre Ossman 		if (intmask & SDHCI_INT_DATA_END)
10931c6a0718SPierre Ossman 			return;
10941c6a0718SPierre Ossman 
1095b67ac3f3SPierre Ossman 		printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
1096b67ac3f3SPierre Ossman 			"though no data operation was in progress.\n",
1097b67ac3f3SPierre Ossman 			mmc_hostname(host->mmc), (unsigned)intmask);
10981c6a0718SPierre Ossman 		sdhci_dumpregs(host);
10991c6a0718SPierre Ossman 
11001c6a0718SPierre Ossman 		return;
11011c6a0718SPierre Ossman 	}
11021c6a0718SPierre Ossman 
11031c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_DATA_TIMEOUT)
110417b0429dSPierre Ossman 		host->data->error = -ETIMEDOUT;
110517b0429dSPierre Ossman 	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
110617b0429dSPierre Ossman 		host->data->error = -EILSEQ;
11071c6a0718SPierre Ossman 
110817b0429dSPierre Ossman 	if (host->data->error)
11091c6a0718SPierre Ossman 		sdhci_finish_data(host);
11101c6a0718SPierre Ossman 	else {
11111c6a0718SPierre Ossman 		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
11121c6a0718SPierre Ossman 			sdhci_transfer_pio(host);
11131c6a0718SPierre Ossman 
11146ba736a1SPierre Ossman 		/*
11156ba736a1SPierre Ossman 		 * We currently don't do anything fancy with DMA
11166ba736a1SPierre Ossman 		 * boundaries, but as we can't disable the feature
11176ba736a1SPierre Ossman 		 * we need to at least restart the transfer.
11186ba736a1SPierre Ossman 		 */
11196ba736a1SPierre Ossman 		if (intmask & SDHCI_INT_DMA_END)
11206ba736a1SPierre Ossman 			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
11216ba736a1SPierre Ossman 				host->ioaddr + SDHCI_DMA_ADDRESS);
11226ba736a1SPierre Ossman 
1123e538fbe8SPierre Ossman 		if (intmask & SDHCI_INT_DATA_END) {
1124e538fbe8SPierre Ossman 			if (host->cmd) {
1125e538fbe8SPierre Ossman 				/*
1126e538fbe8SPierre Ossman 				 * Data managed to finish before the
1127e538fbe8SPierre Ossman 				 * command completed. Make sure we do
1128e538fbe8SPierre Ossman 				 * things in the proper order.
1129e538fbe8SPierre Ossman 				 */
1130e538fbe8SPierre Ossman 				host->data_early = 1;
1131e538fbe8SPierre Ossman 			} else {
11321c6a0718SPierre Ossman 				sdhci_finish_data(host);
11331c6a0718SPierre Ossman 			}
11341c6a0718SPierre Ossman 		}
1135e538fbe8SPierre Ossman 	}
1136e538fbe8SPierre Ossman }
11371c6a0718SPierre Ossman 
11381c6a0718SPierre Ossman static irqreturn_t sdhci_irq(int irq, void *dev_id)
11391c6a0718SPierre Ossman {
11401c6a0718SPierre Ossman 	irqreturn_t result;
11411c6a0718SPierre Ossman 	struct sdhci_host* host = dev_id;
11421c6a0718SPierre Ossman 	u32 intmask;
1143f75979b7SPierre Ossman 	int cardint = 0;
11441c6a0718SPierre Ossman 
11451c6a0718SPierre Ossman 	spin_lock(&host->lock);
11461c6a0718SPierre Ossman 
11471c6a0718SPierre Ossman 	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
11481c6a0718SPierre Ossman 
11491c6a0718SPierre Ossman 	if (!intmask || intmask == 0xffffffff) {
11501c6a0718SPierre Ossman 		result = IRQ_NONE;
11511c6a0718SPierre Ossman 		goto out;
11521c6a0718SPierre Ossman 	}
11531c6a0718SPierre Ossman 
1154b69c9058SPierre Ossman 	DBG("*** %s got interrupt: 0x%08x\n",
1155b69c9058SPierre Ossman 		mmc_hostname(host->mmc), intmask);
11561c6a0718SPierre Ossman 
11571c6a0718SPierre Ossman 	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
11581c6a0718SPierre Ossman 		writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
11591c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
11601c6a0718SPierre Ossman 		tasklet_schedule(&host->card_tasklet);
11611c6a0718SPierre Ossman 	}
11621c6a0718SPierre Ossman 
11631c6a0718SPierre Ossman 	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
11641c6a0718SPierre Ossman 
11651c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_CMD_MASK) {
11661c6a0718SPierre Ossman 		writel(intmask & SDHCI_INT_CMD_MASK,
11671c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
11681c6a0718SPierre Ossman 		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
11691c6a0718SPierre Ossman 	}
11701c6a0718SPierre Ossman 
11711c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_DATA_MASK) {
11721c6a0718SPierre Ossman 		writel(intmask & SDHCI_INT_DATA_MASK,
11731c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
11741c6a0718SPierre Ossman 		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
11751c6a0718SPierre Ossman 	}
11761c6a0718SPierre Ossman 
11771c6a0718SPierre Ossman 	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
11781c6a0718SPierre Ossman 
1179964f9ce2SPierre Ossman 	intmask &= ~SDHCI_INT_ERROR;
1180964f9ce2SPierre Ossman 
11811c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_BUS_POWER) {
11821c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Card is consuming too much power!\n",
11831c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
11841c6a0718SPierre Ossman 		writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
11851c6a0718SPierre Ossman 	}
11861c6a0718SPierre Ossman 
11879d26a5d3SRolf Eike Beer 	intmask &= ~SDHCI_INT_BUS_POWER;
11881c6a0718SPierre Ossman 
1189f75979b7SPierre Ossman 	if (intmask & SDHCI_INT_CARD_INT)
1190f75979b7SPierre Ossman 		cardint = 1;
1191f75979b7SPierre Ossman 
1192f75979b7SPierre Ossman 	intmask &= ~SDHCI_INT_CARD_INT;
1193f75979b7SPierre Ossman 
11941c6a0718SPierre Ossman 	if (intmask) {
11951c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
11961c6a0718SPierre Ossman 			mmc_hostname(host->mmc), intmask);
11971c6a0718SPierre Ossman 		sdhci_dumpregs(host);
11981c6a0718SPierre Ossman 
11991c6a0718SPierre Ossman 		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
12001c6a0718SPierre Ossman 	}
12011c6a0718SPierre Ossman 
12021c6a0718SPierre Ossman 	result = IRQ_HANDLED;
12031c6a0718SPierre Ossman 
12041c6a0718SPierre Ossman 	mmiowb();
12051c6a0718SPierre Ossman out:
12061c6a0718SPierre Ossman 	spin_unlock(&host->lock);
12071c6a0718SPierre Ossman 
1208f75979b7SPierre Ossman 	/*
1209f75979b7SPierre Ossman 	 * We have to delay this as it calls back into the driver.
1210f75979b7SPierre Ossman 	 */
1211f75979b7SPierre Ossman 	if (cardint)
1212f75979b7SPierre Ossman 		mmc_signal_sdio_irq(host->mmc);
1213f75979b7SPierre Ossman 
12141c6a0718SPierre Ossman 	return result;
12151c6a0718SPierre Ossman }
12161c6a0718SPierre Ossman 
12171c6a0718SPierre Ossman /*****************************************************************************\
12181c6a0718SPierre Ossman  *                                                                           *
12191c6a0718SPierre Ossman  * Suspend/resume                                                            *
12201c6a0718SPierre Ossman  *                                                                           *
12211c6a0718SPierre Ossman \*****************************************************************************/
12221c6a0718SPierre Ossman 
12231c6a0718SPierre Ossman #ifdef CONFIG_PM
12241c6a0718SPierre Ossman 
12251c6a0718SPierre Ossman static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
12261c6a0718SPierre Ossman {
12271c6a0718SPierre Ossman 	struct sdhci_chip *chip;
12281c6a0718SPierre Ossman 	int i, ret;
12291c6a0718SPierre Ossman 
12301c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
12311c6a0718SPierre Ossman 	if (!chip)
12321c6a0718SPierre Ossman 		return 0;
12331c6a0718SPierre Ossman 
12341c6a0718SPierre Ossman 	DBG("Suspending...\n");
12351c6a0718SPierre Ossman 
12361c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
12371c6a0718SPierre Ossman 		if (!chip->hosts[i])
12381c6a0718SPierre Ossman 			continue;
12391c6a0718SPierre Ossman 		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
12401c6a0718SPierre Ossman 		if (ret) {
12411c6a0718SPierre Ossman 			for (i--;i >= 0;i--)
12421c6a0718SPierre Ossman 				mmc_resume_host(chip->hosts[i]->mmc);
12431c6a0718SPierre Ossman 			return ret;
12441c6a0718SPierre Ossman 		}
12451c6a0718SPierre Ossman 	}
12461c6a0718SPierre Ossman 
12471c6a0718SPierre Ossman 	pci_save_state(pdev);
12481c6a0718SPierre Ossman 	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
12491c6a0718SPierre Ossman 
12501c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
12511c6a0718SPierre Ossman 		if (!chip->hosts[i])
12521c6a0718SPierre Ossman 			continue;
12531c6a0718SPierre Ossman 		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
12541c6a0718SPierre Ossman 	}
12551c6a0718SPierre Ossman 
12561c6a0718SPierre Ossman 	pci_disable_device(pdev);
12571c6a0718SPierre Ossman 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
12581c6a0718SPierre Ossman 
12591c6a0718SPierre Ossman 	return 0;
12601c6a0718SPierre Ossman }
12611c6a0718SPierre Ossman 
12621c6a0718SPierre Ossman static int sdhci_resume (struct pci_dev *pdev)
12631c6a0718SPierre Ossman {
12641c6a0718SPierre Ossman 	struct sdhci_chip *chip;
12651c6a0718SPierre Ossman 	int i, ret;
12661c6a0718SPierre Ossman 
12671c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
12681c6a0718SPierre Ossman 	if (!chip)
12691c6a0718SPierre Ossman 		return 0;
12701c6a0718SPierre Ossman 
12711c6a0718SPierre Ossman 	DBG("Resuming...\n");
12721c6a0718SPierre Ossman 
12731c6a0718SPierre Ossman 	pci_set_power_state(pdev, PCI_D0);
12741c6a0718SPierre Ossman 	pci_restore_state(pdev);
12751c6a0718SPierre Ossman 	ret = pci_enable_device(pdev);
12761c6a0718SPierre Ossman 	if (ret)
12771c6a0718SPierre Ossman 		return ret;
12781c6a0718SPierre Ossman 
12791c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
12801c6a0718SPierre Ossman 		if (!chip->hosts[i])
12811c6a0718SPierre Ossman 			continue;
12821c6a0718SPierre Ossman 		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
12831c6a0718SPierre Ossman 			pci_set_master(pdev);
12841c6a0718SPierre Ossman 		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
1285b69c9058SPierre Ossman 			IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc),
12861c6a0718SPierre Ossman 			chip->hosts[i]);
12871c6a0718SPierre Ossman 		if (ret)
12881c6a0718SPierre Ossman 			return ret;
12891c6a0718SPierre Ossman 		sdhci_init(chip->hosts[i]);
12901c6a0718SPierre Ossman 		mmiowb();
12911c6a0718SPierre Ossman 		ret = mmc_resume_host(chip->hosts[i]->mmc);
12921c6a0718SPierre Ossman 		if (ret)
12931c6a0718SPierre Ossman 			return ret;
12941c6a0718SPierre Ossman 	}
12951c6a0718SPierre Ossman 
12961c6a0718SPierre Ossman 	return 0;
12971c6a0718SPierre Ossman }
12981c6a0718SPierre Ossman 
12991c6a0718SPierre Ossman #else /* CONFIG_PM */
13001c6a0718SPierre Ossman 
13011c6a0718SPierre Ossman #define sdhci_suspend NULL
13021c6a0718SPierre Ossman #define sdhci_resume NULL
13031c6a0718SPierre Ossman 
13041c6a0718SPierre Ossman #endif /* CONFIG_PM */
13051c6a0718SPierre Ossman 
13061c6a0718SPierre Ossman /*****************************************************************************\
13071c6a0718SPierre Ossman  *                                                                           *
13081c6a0718SPierre Ossman  * Device probing/removal                                                    *
13091c6a0718SPierre Ossman  *                                                                           *
13101c6a0718SPierre Ossman \*****************************************************************************/
13111c6a0718SPierre Ossman 
13121c6a0718SPierre Ossman static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
13131c6a0718SPierre Ossman {
13141c6a0718SPierre Ossman 	int ret;
13151c6a0718SPierre Ossman 	unsigned int version;
13161c6a0718SPierre Ossman 	struct sdhci_chip *chip;
13171c6a0718SPierre Ossman 	struct mmc_host *mmc;
13181c6a0718SPierre Ossman 	struct sdhci_host *host;
13191c6a0718SPierre Ossman 
13201c6a0718SPierre Ossman 	u8 first_bar;
13211c6a0718SPierre Ossman 	unsigned int caps;
13221c6a0718SPierre Ossman 
13231c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
13241c6a0718SPierre Ossman 	BUG_ON(!chip);
13251c6a0718SPierre Ossman 
13261c6a0718SPierre Ossman 	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
13271c6a0718SPierre Ossman 	if (ret)
13281c6a0718SPierre Ossman 		return ret;
13291c6a0718SPierre Ossman 
13301c6a0718SPierre Ossman 	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
13311c6a0718SPierre Ossman 
13321c6a0718SPierre Ossman 	if (first_bar > 5) {
13331c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
13341c6a0718SPierre Ossman 		return -ENODEV;
13351c6a0718SPierre Ossman 	}
13361c6a0718SPierre Ossman 
13371c6a0718SPierre Ossman 	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
13381c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
13391c6a0718SPierre Ossman 		return -ENODEV;
13401c6a0718SPierre Ossman 	}
13411c6a0718SPierre Ossman 
13421c6a0718SPierre Ossman 	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
13431c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
13441c6a0718SPierre Ossman 			"You may experience problems.\n");
13451c6a0718SPierre Ossman 	}
13461c6a0718SPierre Ossman 
13471c6a0718SPierre Ossman 	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
13481c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
13491c6a0718SPierre Ossman 		return -ENODEV;
13501c6a0718SPierre Ossman 	}
13511c6a0718SPierre Ossman 
13521c6a0718SPierre Ossman 	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
13531c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
13541c6a0718SPierre Ossman 		return -ENODEV;
13551c6a0718SPierre Ossman 	}
13561c6a0718SPierre Ossman 
13571c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
13581c6a0718SPierre Ossman 	if (!mmc)
13591c6a0718SPierre Ossman 		return -ENOMEM;
13601c6a0718SPierre Ossman 
13611c6a0718SPierre Ossman 	host = mmc_priv(mmc);
13621c6a0718SPierre Ossman 	host->mmc = mmc;
13631c6a0718SPierre Ossman 
13641c6a0718SPierre Ossman 	host->chip = chip;
13651c6a0718SPierre Ossman 	chip->hosts[slot] = host;
13661c6a0718SPierre Ossman 
13671c6a0718SPierre Ossman 	host->bar = first_bar + slot;
13681c6a0718SPierre Ossman 
13691c6a0718SPierre Ossman 	host->addr = pci_resource_start(pdev, host->bar);
13701c6a0718SPierre Ossman 	host->irq = pdev->irq;
13711c6a0718SPierre Ossman 
13721c6a0718SPierre Ossman 	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
13731c6a0718SPierre Ossman 
1374b69c9058SPierre Ossman 	ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc));
13751c6a0718SPierre Ossman 	if (ret)
13761c6a0718SPierre Ossman 		goto free;
13771c6a0718SPierre Ossman 
13781c6a0718SPierre Ossman 	host->ioaddr = ioremap_nocache(host->addr,
13791c6a0718SPierre Ossman 		pci_resource_len(pdev, host->bar));
13801c6a0718SPierre Ossman 	if (!host->ioaddr) {
13811c6a0718SPierre Ossman 		ret = -ENOMEM;
13821c6a0718SPierre Ossman 		goto release;
13831c6a0718SPierre Ossman 	}
13841c6a0718SPierre Ossman 
13851c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
13861c6a0718SPierre Ossman 
13871c6a0718SPierre Ossman 	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
13881c6a0718SPierre Ossman 	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
1389c6573c94SPierre Ossman 	if (version > 1) {
13901c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unknown controller version (%d). "
1391b69c9058SPierre Ossman 			"You may experience problems.\n", mmc_hostname(mmc),
13921c6a0718SPierre Ossman 			version);
13931c6a0718SPierre Ossman 	}
13941c6a0718SPierre Ossman 
13951c6a0718SPierre Ossman 	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
13961c6a0718SPierre Ossman 
1397d6f8deecSPierre Ossman 	if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
13981c6a0718SPierre Ossman 		host->flags |= SDHCI_USE_DMA;
13991c6a0718SPierre Ossman 	else if (!(caps & SDHCI_CAN_DO_DMA))
14001c6a0718SPierre Ossman 		DBG("Controller doesn't have DMA capability\n");
14011c6a0718SPierre Ossman 	else
14021c6a0718SPierre Ossman 		host->flags |= SDHCI_USE_DMA;
14031c6a0718SPierre Ossman 
14047c168e3dSFeng Tang 	if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
14057c168e3dSFeng Tang 		(host->flags & SDHCI_USE_DMA)) {
1406cee687ceSRolf Eike Beer 		DBG("Disabling DMA as it is marked broken\n");
14077c168e3dSFeng Tang 		host->flags &= ~SDHCI_USE_DMA;
14087c168e3dSFeng Tang 	}
14097c168e3dSFeng Tang 
141056e71efeSFeng Tang 	if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
141156e71efeSFeng Tang 		(host->flags & SDHCI_USE_DMA)) {
141256e71efeSFeng Tang 		printk(KERN_WARNING "%s: Will use DMA "
141356e71efeSFeng Tang 			"mode even though HW doesn't fully "
1414b69c9058SPierre Ossman 			"claim to support it.\n", mmc_hostname(mmc));
141556e71efeSFeng Tang 	}
141656e71efeSFeng Tang 
14171c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA) {
14181c6a0718SPierre Ossman 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
14191c6a0718SPierre Ossman 			printk(KERN_WARNING "%s: No suitable DMA available. "
1420b69c9058SPierre Ossman 				"Falling back to PIO.\n", mmc_hostname(mmc));
14211c6a0718SPierre Ossman 			host->flags &= ~SDHCI_USE_DMA;
14221c6a0718SPierre Ossman 		}
14231c6a0718SPierre Ossman 	}
14241c6a0718SPierre Ossman 
14251c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
14261c6a0718SPierre Ossman 		pci_set_master(pdev);
14271c6a0718SPierre Ossman 	else /* XXX: Hack to get MMC layer to avoid highmem */
14281c6a0718SPierre Ossman 		pdev->dma_mask = 0;
14291c6a0718SPierre Ossman 
14301c6a0718SPierre Ossman 	host->max_clk =
14311c6a0718SPierre Ossman 		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
14321c6a0718SPierre Ossman 	if (host->max_clk == 0) {
14331c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
1434b69c9058SPierre Ossman 			"frequency.\n", mmc_hostname(mmc));
14351c6a0718SPierre Ossman 		ret = -ENODEV;
14361c6a0718SPierre Ossman 		goto unmap;
14371c6a0718SPierre Ossman 	}
14381c6a0718SPierre Ossman 	host->max_clk *= 1000000;
14391c6a0718SPierre Ossman 
14401c6a0718SPierre Ossman 	host->timeout_clk =
14411c6a0718SPierre Ossman 		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
14421c6a0718SPierre Ossman 	if (host->timeout_clk == 0) {
14431c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
1444b69c9058SPierre Ossman 			"frequency.\n", mmc_hostname(mmc));
14451c6a0718SPierre Ossman 		ret = -ENODEV;
14461c6a0718SPierre Ossman 		goto unmap;
14471c6a0718SPierre Ossman 	}
14481c6a0718SPierre Ossman 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
14491c6a0718SPierre Ossman 		host->timeout_clk *= 1000;
14501c6a0718SPierre Ossman 
14511c6a0718SPierre Ossman 	/*
14521c6a0718SPierre Ossman 	 * Set host parameters.
14531c6a0718SPierre Ossman 	 */
14541c6a0718SPierre Ossman 	mmc->ops = &sdhci_ops;
14551c6a0718SPierre Ossman 	mmc->f_min = host->max_clk / 256;
14561c6a0718SPierre Ossman 	mmc->f_max = host->max_clk;
1457f75979b7SPierre Ossman 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
14581c6a0718SPierre Ossman 
14591c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_DO_HISPD)
14601c6a0718SPierre Ossman 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
14611c6a0718SPierre Ossman 
14621c6a0718SPierre Ossman 	mmc->ocr_avail = 0;
14631c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_330)
14641c6a0718SPierre Ossman 		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
14651c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_300)
14661c6a0718SPierre Ossman 		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
14671c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_180)
146855556da0SPhilip Langdale 		mmc->ocr_avail |= MMC_VDD_165_195;
14691c6a0718SPierre Ossman 
14701c6a0718SPierre Ossman 	if (mmc->ocr_avail == 0) {
14711c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't report any "
1472b69c9058SPierre Ossman 			"support voltages.\n", mmc_hostname(mmc));
14731c6a0718SPierre Ossman 		ret = -ENODEV;
14741c6a0718SPierre Ossman 		goto unmap;
14751c6a0718SPierre Ossman 	}
14761c6a0718SPierre Ossman 
14771c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
14781c6a0718SPierre Ossman 
14791c6a0718SPierre Ossman 	/*
14801c6a0718SPierre Ossman 	 * Maximum number of segments. Hardware cannot do scatter lists.
14811c6a0718SPierre Ossman 	 */
14821c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
14831c6a0718SPierre Ossman 		mmc->max_hw_segs = 1;
14841c6a0718SPierre Ossman 	else
14851c6a0718SPierre Ossman 		mmc->max_hw_segs = 16;
14861c6a0718SPierre Ossman 	mmc->max_phys_segs = 16;
14871c6a0718SPierre Ossman 
14881c6a0718SPierre Ossman 	/*
14891c6a0718SPierre Ossman 	 * Maximum number of sectors in one transfer. Limited by DMA boundary
14901c6a0718SPierre Ossman 	 * size (512KiB).
14911c6a0718SPierre Ossman 	 */
14921c6a0718SPierre Ossman 	mmc->max_req_size = 524288;
14931c6a0718SPierre Ossman 
14941c6a0718SPierre Ossman 	/*
14951c6a0718SPierre Ossman 	 * Maximum segment size. Could be one segment with the maximum number
14961c6a0718SPierre Ossman 	 * of bytes.
14971c6a0718SPierre Ossman 	 */
14981c6a0718SPierre Ossman 	mmc->max_seg_size = mmc->max_req_size;
14991c6a0718SPierre Ossman 
15001c6a0718SPierre Ossman 	/*
15011c6a0718SPierre Ossman 	 * Maximum block size. This varies from controller to controller and
15021c6a0718SPierre Ossman 	 * is specified in the capabilities register.
15031c6a0718SPierre Ossman 	 */
15041c6a0718SPierre Ossman 	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
15051c6a0718SPierre Ossman 	if (mmc->max_blk_size >= 3) {
1506b69c9058SPierre Ossman 		printk(KERN_WARNING "%s: Invalid maximum block size, "
1507b69c9058SPierre Ossman 			"assuming 512 bytes\n", mmc_hostname(mmc));
150803f8590dSDavid Vrabel 		mmc->max_blk_size = 512;
150903f8590dSDavid Vrabel 	} else
15101c6a0718SPierre Ossman 		mmc->max_blk_size = 512 << mmc->max_blk_size;
15111c6a0718SPierre Ossman 
15121c6a0718SPierre Ossman 	/*
15131c6a0718SPierre Ossman 	 * Maximum block count.
15141c6a0718SPierre Ossman 	 */
15151c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
15161c6a0718SPierre Ossman 
15171c6a0718SPierre Ossman 	/*
15181c6a0718SPierre Ossman 	 * Init tasklets.
15191c6a0718SPierre Ossman 	 */
15201c6a0718SPierre Ossman 	tasklet_init(&host->card_tasklet,
15211c6a0718SPierre Ossman 		sdhci_tasklet_card, (unsigned long)host);
15221c6a0718SPierre Ossman 	tasklet_init(&host->finish_tasklet,
15231c6a0718SPierre Ossman 		sdhci_tasklet_finish, (unsigned long)host);
15241c6a0718SPierre Ossman 
15251c6a0718SPierre Ossman 	setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
15261c6a0718SPierre Ossman 
15271c6a0718SPierre Ossman 	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
1528b69c9058SPierre Ossman 		mmc_hostname(mmc), host);
15291c6a0718SPierre Ossman 	if (ret)
15301c6a0718SPierre Ossman 		goto untasklet;
15311c6a0718SPierre Ossman 
15321c6a0718SPierre Ossman 	sdhci_init(host);
15331c6a0718SPierre Ossman 
15341c6a0718SPierre Ossman #ifdef CONFIG_MMC_DEBUG
15351c6a0718SPierre Ossman 	sdhci_dumpregs(host);
15361c6a0718SPierre Ossman #endif
15371c6a0718SPierre Ossman 
15382f730fecSPierre Ossman #ifdef CONFIG_LEDS_CLASS
15392f730fecSPierre Ossman 	host->led.name = mmc_hostname(mmc);
15402f730fecSPierre Ossman 	host->led.brightness = LED_OFF;
15412f730fecSPierre Ossman 	host->led.default_trigger = mmc_hostname(mmc);
15422f730fecSPierre Ossman 	host->led.brightness_set = sdhci_led_control;
15432f730fecSPierre Ossman 
15442f730fecSPierre Ossman 	ret = led_classdev_register(&pdev->dev, &host->led);
15452f730fecSPierre Ossman 	if (ret)
15462f730fecSPierre Ossman 		goto reset;
15472f730fecSPierre Ossman #endif
15482f730fecSPierre Ossman 
15491c6a0718SPierre Ossman 	mmiowb();
15501c6a0718SPierre Ossman 
15511c6a0718SPierre Ossman 	mmc_add_host(mmc);
15521c6a0718SPierre Ossman 
1553b69c9058SPierre Ossman 	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n",
1554b69c9058SPierre Ossman 		mmc_hostname(mmc), host->addr, host->irq,
15551c6a0718SPierre Ossman 		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
15561c6a0718SPierre Ossman 
15571c6a0718SPierre Ossman 	return 0;
15581c6a0718SPierre Ossman 
15592f730fecSPierre Ossman #ifdef CONFIG_LEDS_CLASS
15602f730fecSPierre Ossman reset:
15612f730fecSPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
15622f730fecSPierre Ossman 	free_irq(host->irq, host);
15632f730fecSPierre Ossman #endif
15641c6a0718SPierre Ossman untasklet:
15651c6a0718SPierre Ossman 	tasklet_kill(&host->card_tasklet);
15661c6a0718SPierre Ossman 	tasklet_kill(&host->finish_tasklet);
15671c6a0718SPierre Ossman unmap:
15681c6a0718SPierre Ossman 	iounmap(host->ioaddr);
15691c6a0718SPierre Ossman release:
15701c6a0718SPierre Ossman 	pci_release_region(pdev, host->bar);
15711c6a0718SPierre Ossman free:
15721c6a0718SPierre Ossman 	mmc_free_host(mmc);
15731c6a0718SPierre Ossman 
15741c6a0718SPierre Ossman 	return ret;
15751c6a0718SPierre Ossman }
15761c6a0718SPierre Ossman 
15771c6a0718SPierre Ossman static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
15781c6a0718SPierre Ossman {
15791c6a0718SPierre Ossman 	struct sdhci_chip *chip;
15801c6a0718SPierre Ossman 	struct mmc_host *mmc;
15811c6a0718SPierre Ossman 	struct sdhci_host *host;
15821c6a0718SPierre Ossman 
15831c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
15841c6a0718SPierre Ossman 	host = chip->hosts[slot];
15851c6a0718SPierre Ossman 	mmc = host->mmc;
15861c6a0718SPierre Ossman 
15871c6a0718SPierre Ossman 	chip->hosts[slot] = NULL;
15881c6a0718SPierre Ossman 
15891c6a0718SPierre Ossman 	mmc_remove_host(mmc);
15901c6a0718SPierre Ossman 
15912f730fecSPierre Ossman #ifdef CONFIG_LEDS_CLASS
15922f730fecSPierre Ossman 	led_classdev_unregister(&host->led);
15932f730fecSPierre Ossman #endif
15942f730fecSPierre Ossman 
15951c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
15961c6a0718SPierre Ossman 
15971c6a0718SPierre Ossman 	free_irq(host->irq, host);
15981c6a0718SPierre Ossman 
15991c6a0718SPierre Ossman 	del_timer_sync(&host->timer);
16001c6a0718SPierre Ossman 
16011c6a0718SPierre Ossman 	tasklet_kill(&host->card_tasklet);
16021c6a0718SPierre Ossman 	tasklet_kill(&host->finish_tasklet);
16031c6a0718SPierre Ossman 
16041c6a0718SPierre Ossman 	iounmap(host->ioaddr);
16051c6a0718SPierre Ossman 
16061c6a0718SPierre Ossman 	pci_release_region(pdev, host->bar);
16071c6a0718SPierre Ossman 
16081c6a0718SPierre Ossman 	mmc_free_host(mmc);
16091c6a0718SPierre Ossman }
16101c6a0718SPierre Ossman 
16111c6a0718SPierre Ossman static int __devinit sdhci_probe(struct pci_dev *pdev,
16121c6a0718SPierre Ossman 	const struct pci_device_id *ent)
16131c6a0718SPierre Ossman {
16141c6a0718SPierre Ossman 	int ret, i;
16151c6a0718SPierre Ossman 	u8 slots, rev;
16161c6a0718SPierre Ossman 	struct sdhci_chip *chip;
16171c6a0718SPierre Ossman 
16181c6a0718SPierre Ossman 	BUG_ON(pdev == NULL);
16191c6a0718SPierre Ossman 	BUG_ON(ent == NULL);
16201c6a0718SPierre Ossman 
16211c6a0718SPierre Ossman 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
16221c6a0718SPierre Ossman 
16231c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME
16241c6a0718SPierre Ossman 		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
16251c6a0718SPierre Ossman 		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
16261c6a0718SPierre Ossman 		(int)rev);
16271c6a0718SPierre Ossman 
16281c6a0718SPierre Ossman 	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
16291c6a0718SPierre Ossman 	if (ret)
16301c6a0718SPierre Ossman 		return ret;
16311c6a0718SPierre Ossman 
16321c6a0718SPierre Ossman 	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
16331c6a0718SPierre Ossman 	DBG("found %d slot(s)\n", slots);
16341c6a0718SPierre Ossman 	if (slots == 0)
16351c6a0718SPierre Ossman 		return -ENODEV;
16361c6a0718SPierre Ossman 
16371c6a0718SPierre Ossman 	ret = pci_enable_device(pdev);
16381c6a0718SPierre Ossman 	if (ret)
16391c6a0718SPierre Ossman 		return ret;
16401c6a0718SPierre Ossman 
16411c6a0718SPierre Ossman 	chip = kzalloc(sizeof(struct sdhci_chip) +
16421c6a0718SPierre Ossman 		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
16431c6a0718SPierre Ossman 	if (!chip) {
16441c6a0718SPierre Ossman 		ret = -ENOMEM;
16451c6a0718SPierre Ossman 		goto err;
16461c6a0718SPierre Ossman 	}
16471c6a0718SPierre Ossman 
16481c6a0718SPierre Ossman 	chip->pdev = pdev;
16491c6a0718SPierre Ossman 	chip->quirks = ent->driver_data;
16501c6a0718SPierre Ossman 
16511c6a0718SPierre Ossman 	if (debug_quirks)
16521c6a0718SPierre Ossman 		chip->quirks = debug_quirks;
16531c6a0718SPierre Ossman 
16541c6a0718SPierre Ossman 	chip->num_slots = slots;
16551c6a0718SPierre Ossman 	pci_set_drvdata(pdev, chip);
16561c6a0718SPierre Ossman 
16571c6a0718SPierre Ossman 	for (i = 0;i < slots;i++) {
16581c6a0718SPierre Ossman 		ret = sdhci_probe_slot(pdev, i);
16591c6a0718SPierre Ossman 		if (ret) {
16601c6a0718SPierre Ossman 			for (i--;i >= 0;i--)
16611c6a0718SPierre Ossman 				sdhci_remove_slot(pdev, i);
16621c6a0718SPierre Ossman 			goto free;
16631c6a0718SPierre Ossman 		}
16641c6a0718SPierre Ossman 	}
16651c6a0718SPierre Ossman 
16661c6a0718SPierre Ossman 	return 0;
16671c6a0718SPierre Ossman 
16681c6a0718SPierre Ossman free:
16691c6a0718SPierre Ossman 	pci_set_drvdata(pdev, NULL);
16701c6a0718SPierre Ossman 	kfree(chip);
16711c6a0718SPierre Ossman 
16721c6a0718SPierre Ossman err:
16731c6a0718SPierre Ossman 	pci_disable_device(pdev);
16741c6a0718SPierre Ossman 	return ret;
16751c6a0718SPierre Ossman }
16761c6a0718SPierre Ossman 
16771c6a0718SPierre Ossman static void __devexit sdhci_remove(struct pci_dev *pdev)
16781c6a0718SPierre Ossman {
16791c6a0718SPierre Ossman 	int i;
16801c6a0718SPierre Ossman 	struct sdhci_chip *chip;
16811c6a0718SPierre Ossman 
16821c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
16831c6a0718SPierre Ossman 
16841c6a0718SPierre Ossman 	if (chip) {
16851c6a0718SPierre Ossman 		for (i = 0;i < chip->num_slots;i++)
16861c6a0718SPierre Ossman 			sdhci_remove_slot(pdev, i);
16871c6a0718SPierre Ossman 
16881c6a0718SPierre Ossman 		pci_set_drvdata(pdev, NULL);
16891c6a0718SPierre Ossman 
16901c6a0718SPierre Ossman 		kfree(chip);
16911c6a0718SPierre Ossman 	}
16921c6a0718SPierre Ossman 
16931c6a0718SPierre Ossman 	pci_disable_device(pdev);
16941c6a0718SPierre Ossman }
16951c6a0718SPierre Ossman 
16961c6a0718SPierre Ossman static struct pci_driver sdhci_driver = {
16971c6a0718SPierre Ossman 	.name = 	DRIVER_NAME,
16981c6a0718SPierre Ossman 	.id_table =	pci_ids,
16991c6a0718SPierre Ossman 	.probe = 	sdhci_probe,
17001c6a0718SPierre Ossman 	.remove =	__devexit_p(sdhci_remove),
17011c6a0718SPierre Ossman 	.suspend =	sdhci_suspend,
17021c6a0718SPierre Ossman 	.resume	=	sdhci_resume,
17031c6a0718SPierre Ossman };
17041c6a0718SPierre Ossman 
17051c6a0718SPierre Ossman /*****************************************************************************\
17061c6a0718SPierre Ossman  *                                                                           *
17071c6a0718SPierre Ossman  * Driver init/exit                                                          *
17081c6a0718SPierre Ossman  *                                                                           *
17091c6a0718SPierre Ossman \*****************************************************************************/
17101c6a0718SPierre Ossman 
17111c6a0718SPierre Ossman static int __init sdhci_drv_init(void)
17121c6a0718SPierre Ossman {
17131c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME
17141c6a0718SPierre Ossman 		": Secure Digital Host Controller Interface driver\n");
17151c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
17161c6a0718SPierre Ossman 
17171c6a0718SPierre Ossman 	return pci_register_driver(&sdhci_driver);
17181c6a0718SPierre Ossman }
17191c6a0718SPierre Ossman 
17201c6a0718SPierre Ossman static void __exit sdhci_drv_exit(void)
17211c6a0718SPierre Ossman {
17221c6a0718SPierre Ossman 	DBG("Exiting\n");
17231c6a0718SPierre Ossman 
17241c6a0718SPierre Ossman 	pci_unregister_driver(&sdhci_driver);
17251c6a0718SPierre Ossman }
17261c6a0718SPierre Ossman 
17271c6a0718SPierre Ossman module_init(sdhci_drv_init);
17281c6a0718SPierre Ossman module_exit(sdhci_drv_exit);
17291c6a0718SPierre Ossman 
17301c6a0718SPierre Ossman module_param(debug_quirks, uint, 0444);
17311c6a0718SPierre Ossman 
17321c6a0718SPierre Ossman MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
17331c6a0718SPierre Ossman MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
17341c6a0718SPierre Ossman MODULE_LICENSE("GPL");
17351c6a0718SPierre Ossman 
17361c6a0718SPierre Ossman MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
1737