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