sdhci.c revision e08c1694d9e2138204f2b79b73f0f159074ce2f5
1d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/* 270f10482c668301c483acded13bf68780ad352b9Pierre Ossman * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver 3d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * 4b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. 5d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * 6d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * This program is free software; you can redistribute it and/or modify 7643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * it under the terms of the GNU General Public License as published by 8643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 9643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * your option) any later version. 1084c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman * 1184c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman * Thanks to the following companies for their support: 1284c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman * 1384c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman * - JMicron (hardware and technical support) 14d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 15d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 16d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/delay.h> 17d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/highmem.h> 18d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/pci.h> 19d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/dma-mapping.h> 20117636092a87a28a013a4acb5de5492645ed620fRalf Baechle#include <linux/scatterlist.h> 21d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 222f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#include <linux/leds.h> 232f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 24d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/mmc/host.h> 25d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 26d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include "sdhci.h" 27d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 28d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define DRIVER_NAME "sdhci" 29d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 30d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define DBG(f, x...) \ 31c65631781eb0f2e81865017c1484e9aef76e1b61Russell King pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) 32d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 33df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanstatic unsigned int debug_quirks = 0; 346743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 35dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* 36dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman * Different quirks to handle when the hardware deviates from a strict 37dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman * interpretation of the SDHCI specification. 38dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman */ 39dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman 40dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* Controller doesn't honor resets unless we touch the clock register */ 41645289dca5021224279e67b4655796cafdfdad00Pierre Ossman#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) 42dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* Controller has bad caps bits, but really supports DMA */ 4398608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman#define SDHCI_QUIRK_FORCE_DMA (1<<1) 440b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman/* Controller doesn't like to be reset when there is no card inserted. */ 458a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) 46dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* Controller doesn't like clearing the power reg before a change */ 479e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) 48dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* Controller has flaky internal state so reset it on each ios change */ 49b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) 50dc93441b3f5879a096dd117a81df541b0855ebbbPierre Ossman/* Controller has an unusable DMA engine */ 517c168e3db7d900008ee304574057e0dc1a8505afFeng Tang#define SDHCI_QUIRK_BROKEN_DMA (1<<5) 52c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman/* Controller can only DMA from 32-bit aligned addresses */ 53c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<6) 54c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ 55c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<7) 5684c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman/* Controller needs to be reset after each request to stay stable */ 5784c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) 58e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon/* Controller needs voltage and power writes to happen separately */ 59e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) 60645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 61d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic const struct pci_device_id pci_ids[] __devinitdata = { 62645289dca5021224279e67b4655796cafdfdad00Pierre Ossman { 63645289dca5021224279e67b4655796cafdfdad00Pierre Ossman .vendor = PCI_VENDOR_ID_RICOH, 64645289dca5021224279e67b4655796cafdfdad00Pierre Ossman .device = PCI_DEVICE_ID_RICOH_R5C822, 65645289dca5021224279e67b4655796cafdfdad00Pierre Ossman .subvendor = PCI_VENDOR_ID_IBM, 66645289dca5021224279e67b4655796cafdfdad00Pierre Ossman .subdevice = PCI_ANY_ID, 6798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .driver_data = SDHCI_QUIRK_CLOCK_BEFORE_RESET | 6898608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman SDHCI_QUIRK_FORCE_DMA, 6998608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman }, 7098608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman 7198608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman { 7298608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .vendor = PCI_VENDOR_ID_RICOH, 7398608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .device = PCI_DEVICE_ID_RICOH_R5C822, 740b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .subvendor = PCI_VENDOR_ID_SAMSUNG, 7598608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .subdevice = PCI_ANY_ID, 768a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman .driver_data = SDHCI_QUIRK_FORCE_DMA | 778a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman SDHCI_QUIRK_NO_CARD_NO_RESET, 7898608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman }, 7998608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman 8098608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman { 810b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .vendor = PCI_VENDOR_ID_RICOH, 820b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .device = PCI_DEVICE_ID_RICOH_R5C822, 830b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .subvendor = PCI_ANY_ID, 840b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .subdevice = PCI_ANY_ID, 850b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman .driver_data = SDHCI_QUIRK_FORCE_DMA, 860b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman }, 870b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman 880b82684c3c19aff092bb303959a31dbe5c965922Pierre Ossman { 8998608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .vendor = PCI_VENDOR_ID_TI, 9098608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .device = PCI_DEVICE_ID_TI_XX21_XX11_SD, 9198608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .subvendor = PCI_ANY_ID, 9298608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .subdevice = PCI_ANY_ID, 9398608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman .driver_data = SDHCI_QUIRK_FORCE_DMA, 94645289dca5021224279e67b4655796cafdfdad00Pierre Ossman }, 95645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 969e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt { 979e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt .vendor = PCI_VENDOR_ID_ENE, 989e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt .device = PCI_DEVICE_ID_ENE_CB712_SD, 999e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt .subvendor = PCI_ANY_ID, 1009e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt .subdevice = PCI_ANY_ID, 1017c168e3db7d900008ee304574057e0dc1a8505afFeng Tang .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | 1027c168e3db7d900008ee304574057e0dc1a8505afFeng Tang SDHCI_QUIRK_BROKEN_DMA, 1039e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt }, 1049e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt 1057de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov { 1067de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov .vendor = PCI_VENDOR_ID_ENE, 1077de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov .device = PCI_DEVICE_ID_ENE_CB712_SD_2, 1087de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov .subvendor = PCI_ANY_ID, 1097de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov .subdevice = PCI_ANY_ID, 1107c168e3db7d900008ee304574057e0dc1a8505afFeng Tang .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | 1117c168e3db7d900008ee304574057e0dc1a8505afFeng Tang SDHCI_QUIRK_BROKEN_DMA, 1127de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov }, 1137de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov 114b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo { 115b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .vendor = PCI_VENDOR_ID_ENE, 116b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .device = PCI_DEVICE_ID_ENE_CB714_SD, 117b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .subvendor = PCI_ANY_ID, 118b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .subdevice = PCI_ANY_ID, 119b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | 120b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, 121b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo }, 122b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo 123b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo { 124b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .vendor = PCI_VENDOR_ID_ENE, 125b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .device = PCI_DEVICE_ID_ENE_CB714_SD_2, 126b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .subvendor = PCI_ANY_ID, 127b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .subdevice = PCI_ANY_ID, 128b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | 129b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, 130b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo }, 131b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo 13284c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman { 133e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon .vendor = PCI_VENDOR_ID_MARVELL, 134e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon .device = PCI_DEVICE_ID_MARVELL_CAFE_SD, 135e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon .subvendor = PCI_ANY_ID, 136e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon .subdevice = PCI_ANY_ID, 137e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon .driver_data = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, 138e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon }, 139e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon 140e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon { 14184c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman .vendor = PCI_VENDOR_ID_JMICRON, 14284c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD, 14384c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman .subvendor = PCI_ANY_ID, 14484c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman .subdevice = PCI_ANY_ID, 14584c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman .driver_data = SDHCI_QUIRK_32BIT_DMA_ADDR | 14684c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman SDHCI_QUIRK_32BIT_DMA_SIZE | 14784c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman SDHCI_QUIRK_RESET_AFTER_REQUEST, 14884c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman }, 14984c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman 150645289dca5021224279e67b4655796cafdfdad00Pierre Ossman { /* Generic SD host controller */ 151645289dca5021224279e67b4655796cafdfdad00Pierre Ossman PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) 152645289dca5021224279e67b4655796cafdfdad00Pierre Ossman }, 153645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 154d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman { /* end: all zeroes */ }, 155d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}; 156d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 157d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_DEVICE_TABLE(pci, pci_ids); 158d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 159d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *); 160d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *); 161d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 162d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *, struct mmc_command *); 163d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *); 164d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 165d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_dumpregs(struct sdhci_host *host) 166d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 167d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); 168d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", 170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_DMA_ADDRESS), 171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_HOST_VERSION)); 172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", 173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_BLOCK_SIZE), 174d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_BLOCK_COUNT)); 175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", 176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_ARGUMENT), 177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_TRANSFER_MODE)); 178d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", 179d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_PRESENT_STATE), 180d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_HOST_CONTROL)); 181d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", 182d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_POWER_CONTROL), 183d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); 184d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", 1852df3b71b2746469b5b344cf7da5facecd4110cc9Nicolas Pitre readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL), 186d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); 187d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", 188d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), 189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_INT_STATUS)); 190d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", 191d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_INT_ENABLE), 192d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); 193d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", 194d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_ACMD12_ERR), 195d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_SLOT_INT_STATUS)); 196d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", 197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_CAPABILITIES), 198d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_MAX_CURRENT)); 199d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 200d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); 201d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 202d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 204d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Low level functions * 206d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 208d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 209d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_reset(struct sdhci_host *host, u8 mask) 210d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 211e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman unsigned long timeout; 212e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman 2138a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { 2148a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 2158a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman SDHCI_CARD_PRESENT)) 2168a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman return; 2178a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman } 2188a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman 219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET); 220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 221e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman if (mask & SDHCI_RESET_ALL) 222d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->clock = 0; 223d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 224e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman /* Wait max 100 ms */ 225e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman timeout = 100; 226e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman 227e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman /* hw clears the bit when it's done */ 228e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) { 229e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman if (timeout == 0) { 230acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Reset 0x%x never completed.\n", 231e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman mmc_hostname(host->mmc), (int)mask); 232e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman sdhci_dumpregs(host); 233e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman return; 234e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman } 235e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman timeout--; 236e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman mdelay(1); 237d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 238d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 240d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_init(struct sdhci_host *host) 241d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 242d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u32 intmask; 243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 244d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 245d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2463192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | 2473192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | 2483192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | 2493192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | 250a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | 2513192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; 252d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 253d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); 254d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); 255d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 256d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 257d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_activate_led(struct sdhci_host *host) 258d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 261d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 262d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_LED; 263d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 264d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 265d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 266d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_deactivate_led(struct sdhci_host *host) 267d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 268d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 269d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 270d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 271d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_LED; 272d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 273d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 274d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2752f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 2762f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanstatic void sdhci_led_control(struct led_classdev *led, 2772f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman enum led_brightness brightness) 2782f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman{ 2792f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman struct sdhci_host *host = container_of(led, struct sdhci_host, led); 2802f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman unsigned long flags; 2812f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 2822f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_lock_irqsave(&host->lock, flags); 2832f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 2842f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (brightness == LED_OFF) 2852f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_deactivate_led(host); 2862f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman else 2872f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_activate_led(host); 2882f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 2892f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 2902f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman} 2912f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 2922f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 293d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 294d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 295d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Core functions * 296d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 297d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 298d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2992a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossmanstatic inline char* sdhci_sg_to_buffer(struct sdhci_host* host) 300d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 30145711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe return sg_virt(host->cur_sg); 302d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 303d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 304d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic inline int sdhci_next_sg(struct sdhci_host* host) 305d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 306d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 307d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Skip to next SG entry. 308d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 309d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cur_sg++; 310d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->num_sg--; 311d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 312d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 313d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Any entries left? 314d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 315d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->num_sg > 0) { 316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset = 0; 317d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain = host->cur_sg->length; 318d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 319d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 320d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return host->num_sg; 321d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 322d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 323a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_read_block_pio(struct sdhci_host *host) 324d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 325a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int blksize, chunk_remain; 326a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 data; 327d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman char *buffer; 328a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int size; 329d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 330a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO reading\n"); 331d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 332a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 333a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = 0; 334a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = 0; 335d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 3362a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host) + host->offset; 337d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 338a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 339a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (chunk_remain == 0) { 340a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = readl(host->ioaddr + SDHCI_BUFFER); 341a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = min(blksize, 4); 342a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 343d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 34414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov size = min(host->remain, chunk_remain); 345d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 346a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain -= size; 347a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize -= size; 348a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman host->offset += size; 349a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman host->remain -= size; 35014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 351a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (size) { 352a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman *buffer = data & 0xFF; 353a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman buffer++; 354a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data >>= 8; 355a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman size--; 356a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 357d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 358a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->remain == 0) { 359a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (sdhci_next_sg(host) == 0) { 360a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(blksize != 0); 361a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman return; 362a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 3632a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host); 364d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 365a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 366a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 367d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 368a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_write_block_pio(struct sdhci_host *host) 369a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 370a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int blksize, chunk_remain; 371a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 data; 372a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman char *buffer; 373a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int bytes, size; 374d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 375a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO writing\n"); 376a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 377a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 378a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = 4; 379a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = 0; 380d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 381a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman bytes = 0; 3822a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host) + host->offset; 383d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 384a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 38514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov size = min(host->remain, chunk_remain); 386a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 387a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain -= size; 388a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize -= size; 389d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset += size; 390d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain -= size; 39114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 392a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (size) { 393a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data >>= 8; 394a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data |= (u32)*buffer << 24; 395a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman buffer++; 396a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman size--; 397a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 398a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 399a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (chunk_remain == 0) { 400a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman writel(data, host->ioaddr + SDHCI_BUFFER); 401a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = min(blksize, 4); 402a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 403d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 404d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->remain == 0) { 405d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (sdhci_next_sg(host) == 0) { 406a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(blksize != 0); 407d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 408d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 4092a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host); 410d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 411d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 412a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 413a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 414a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_transfer_pio(struct sdhci_host *host) 415a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 416a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 mask; 417a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 418a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(!host->data); 419a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 42014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 421a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman return; 422a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 423a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 424a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_DATA_AVAILABLE; 425a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 426a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_SPACE_AVAILABLE; 427a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 428a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 429a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 430a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_read_block_pio(host); 431a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 432a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_write_block_pio(host); 433d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 43414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 435a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman break; 436a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 437d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 438a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO transfer complete.\n"); 439d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 440d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 441d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) 442d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 4431c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman u8 count; 4441c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman unsigned target_timeout, current_timeout; 445d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 446d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->data); 447d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 448c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data == NULL) 449d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 450d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 451bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman /* Sanity checks */ 452bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman BUG_ON(data->blksz * data->blocks > 524288); 453fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman BUG_ON(data->blksz > host->mmc->max_blk_size); 4541d676e02970d9e511c9b96101501da90954ee265Pierre Ossman BUG_ON(data->blocks > 65535); 455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 456e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman host->data = data; 457e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman host->data_early = 0; 458e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 4591c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* timeout in us */ 4601c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman target_timeout = data->timeout_ns / 1000 + 4611c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman data->timeout_clks / host->clock; 462d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 4631c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* 4641c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * Figure out needed cycles. 4651c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * We do this in steps in order to fit inside a 32 bit int. 4661c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * The first step is the minimum timeout, which will have a 4671c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * minimum resolution of 6 bits: 4681c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) 2^13*1000 > 2^22, 4691c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (2) host->timeout_clk < 2^16 4701c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * => 4711c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) / (2) > 2^6 4721c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman */ 4731c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0; 4741c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout = (1 << 13) * 1000 / host->timeout_clk; 4751c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman while (current_timeout < target_timeout) { 4761c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count++; 4771c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout <<= 1; 4781c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) 4791c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman break; 4801c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 4811c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 4821c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) { 4831c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_WARNING "%s: Too large timeout requested!\n", 4841c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman mmc_hostname(host->mmc)); 4851c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0xE; 4861c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 4871c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 4881c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); 489d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 490c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_USE_DMA) 491c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags |= SDHCI_REQ_USE_DMA; 492c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 493c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && 494c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && 495c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman ((data->blksz * data->blocks) & 0x3))) { 496c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman DBG("Reverting to PIO because of transfer size (%d)\n", 497c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman data->blksz * data->blocks); 498c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 499c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 500c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 501c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman /* 502c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * The assumption here being that alignment is the same after 503c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * translation to device address space. 504c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman */ 505c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && 506c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && 507c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman (data->sg->offset & 0x3))) { 508c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman DBG("Reverting to PIO because of bad alignment\n"); 509c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 510c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 511c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 512c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 513d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int count; 514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 515d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, 516d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); 517d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(count != 1); 518d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 519d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); 520d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 521d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cur_sg = data->sg; 522d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->num_sg = data->sg_len; 523d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 524d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset = 0; 525d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain = host->cur_sg->length; 526d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 527c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 528bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman /* We do not handle DMA boundaries, so set it to max (512 KiB) */ 529bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman writew(SDHCI_MAKE_BLKSZ(7, data->blksz), 530bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman host->ioaddr + SDHCI_BLOCK_SIZE); 531c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT); 532c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman} 533c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 534c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossmanstatic void sdhci_set_transfer_mode(struct sdhci_host *host, 535c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman struct mmc_data *data) 536c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman{ 537c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman u16 mode; 538c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 539c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data == NULL) 540c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman return; 541c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 542e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman WARN_ON(!host->data); 543e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 544c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode = SDHCI_TRNS_BLK_CNT_EN; 545c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->blocks > 1) 546c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_MULTI; 547c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->flags & MMC_DATA_READ) 548c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_READ; 549c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) 550c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_DMA; 551c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 552c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); 553d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 554d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 555d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *host) 556d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 557d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_data *data; 558d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u16 blocks; 559d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 560d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(!host->data); 561d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 562d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman data = host->data; 563d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 564d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 565c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 566d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, 567d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); 568d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 569d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 570d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 571d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Controller doesn't count down when in single block mode. 572d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 5732b061973404802fb87db93175b856ee0dfbe38e4Pierre Ossman if (data->blocks == 1) 57417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman blocks = (data->error == 0) ? 0 : 1; 575d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 576d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); 577a3fd4a1b9ced850ac1a9d5bb9f8fab494d07f3faRussell King data->bytes_xfered = data->blksz * (data->blocks - blocks); 578d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 57917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!data->error && blocks) { 580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Controller signalled completion even " 581acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "though there were blocks left.\n", 582acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman mmc_hostname(host->mmc)); 58317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EIO; 584d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 585d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 586d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (data->stop) { 587d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 588d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 589d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 590d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 59117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data->error) { 592d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 593d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 594d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 595d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 596d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, data->stop); 597d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 600d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) 602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int flags; 604fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman u32 mask; 6057cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 607d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->cmd); 608d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 609d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 6107cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 611fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 612fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask = SDHCI_CMD_INHIBIT; 613fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) 614fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask |= SDHCI_DATA_INHIBIT; 615fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 616fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman /* We shouldn't wait for data inihibit for stop commands, even 617fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman though they might use busy signaling */ 618fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if (host->mrq->data && (cmd == host->mrq->data->stop)) 619fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask &= ~SDHCI_DATA_INHIBIT; 620fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 621fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 6227cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 623d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Controller never released " 624acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "inhibit bit(s).\n", mmc_hostname(host->mmc)); 625d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 62617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EIO; 627d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 628d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 629d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 6307cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 6317cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 6327cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 633d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 634d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mod_timer(&host->timer, jiffies + 10 * HZ); 635d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 636d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = cmd; 637d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 638d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_prepare_data(host, cmd->data); 639d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 640d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); 641d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 642c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman sdhci_set_transfer_mode(host, cmd->data); 643c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 644d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { 645acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unsupported response type!\n", 646d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 64717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EINVAL; 648d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 649d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 650d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 651d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 652d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(cmd->flags & MMC_RSP_PRESENT)) 653d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_NONE; 654d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_136) 655d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_LONG; 656d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_BUSY) 657d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT_BUSY; 658d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 659d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT; 660d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 661d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_CRC) 662d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_CRC; 663d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_OPCODE) 664d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_INDEX; 665d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->data) 666d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_DATA; 667d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 668fb61e2895170920564410baadf71c5b3561dbf42Pierre Ossman writew(SDHCI_MAKE_CMD(cmd->opcode, flags), 669d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_COMMAND); 670d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 671d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 672d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *host) 673d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 674d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i; 675d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 676d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(host->cmd == NULL); 677d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 678d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_PRESENT) { 679d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_136) { 680d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* CRC is stripped so we need to do some shifting. */ 681d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < 4;i++) { 682d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] = readl(host->ioaddr + 683d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4) << 8; 684d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (i != 3) 685d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] |= 686d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + 687d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4-1); 688d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 689d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 690d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE); 691d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 692d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 693d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 69417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = 0; 695d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 696e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->data && host->data_early) 697e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 698e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 699e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (!host->cmd->data) 700d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 701d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 702d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 703d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 704d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 706d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 707d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int div; 708d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u16 clk; 7097cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 710d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 711d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == host->clock) 712d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 713d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 714d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); 715d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 716d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == 0) 717d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 718d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 719d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (div = 1;div < 256;div *= 2) { 720d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((host->max_clk / div) <= clock) 721d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman break; 722d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 723d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman div >>= 1; 724d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 725d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk = div << SDHCI_DIVIDER_SHIFT; 726d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_INT_EN; 727d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 728d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 729d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 7307cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 7317cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL)) 7327cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman & SDHCI_CLOCK_INT_STABLE)) { 7337cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 734acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Internal clock never " 735acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "stabilised.\n", mmc_hostname(host->mmc)); 736d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 737d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 738d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 7397cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 7407cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 7417cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 742d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 743d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_CARD_EN; 744d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 745d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 746d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 747d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->clock = clock; 748d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 749d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 750146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanstatic void sdhci_set_power(struct sdhci_host *host, unsigned short power) 751146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman{ 752146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman u8 pwr; 753146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 754146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (host->power == power) 755146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman return; 756146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 7579e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt if (power == (unsigned short)-1) { 7589e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 759146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman goto out; 7609e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt } 7619e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt 7629e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt /* 7639e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * Spec says that we should clear the power reg before setting 7649e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * a new value. Some controllers don't seem to like this though. 7659e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt */ 7669e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) 7679e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 768146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 769146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr = SDHCI_POWER_ON; 770146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 7714be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale switch (1 << power) { 77255556da01284af8c2174b786b3eca8e11301b656Philip Langdale case MMC_VDD_165_195: 773146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_180; 774146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 7754be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_29_30: 7764be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_30_31: 777146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_300; 778146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 7794be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_32_33: 7804be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_33_34: 781146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_330; 782146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 783146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman default: 784146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman BUG(); 785146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 786146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 787e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon /* 788e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon * At least the CaFe chip gets confused if we set the voltage 789e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon * and set turn on power at the same time, so set the voltage first. 790e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon */ 791e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)) 792e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon writeb(pwr & ~SDHCI_POWER_ON, 793e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon host->ioaddr + SDHCI_POWER_CONTROL); 794e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon 795146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); 796146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 797146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanout: 798146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman host->power = power; 799146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman} 800146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 801d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 802d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 803d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * MMC callbacks * 804d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 805d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 806d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 807d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 808d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 809d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 810d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 811d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 812d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 813d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 814d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 815d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 816d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->mrq != NULL); 817d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 8182f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 819d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_activate_led(host); 8202f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 821d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 822d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = mrq; 823d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 824d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { 82517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 826d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 827d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 828d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, mrq->cmd); 829d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 8305f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 831d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 832d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 833d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 834d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 835d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 836d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 837d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 838d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 839d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 840d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 841d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 842d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 843d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 844d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 845d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Reset the chip on each power off. 846d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Should clear out any weird states. 847d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 848d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) { 849d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE); 850d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 851d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 852d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 853d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_set_clock(host, ios->clock); 854d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 855d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) 856146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, -1); 857d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 858146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, ios->vdd); 859d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 860d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 861cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 862d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->bus_width == MMC_BUS_WIDTH_4) 863d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_4BITBUS; 864d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 865d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_4BITBUS; 866cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 867cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (ios->timing == MMC_TIMING_SD_HS) 868cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl |= SDHCI_CTRL_HISPD; 869cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman else 870cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl &= ~SDHCI_CTRL_HISPD; 871cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 872d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 873d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 874b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo /* 875b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * Some (ENE) controllers go apeshit on some ios operation, 876b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * signalling timeout and CRC errors even on CMD0. Resetting 877b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * it on each ios seems to solve the problem. 878b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo */ 879b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) 880b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 881b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo 8825f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 883d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 884d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 885d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 886d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_get_ro(struct mmc_host *mmc) 887d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 888d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 889d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 890d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int present; 891d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 892d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 893d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 894d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 895d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 896d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman present = readl(host->ioaddr + SDHCI_PRESENT_STATE); 897d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 898d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 899d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 900d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return !(present & SDHCI_WRITE_PROTECT); 901d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 902d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 903f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossmanstatic void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) 904f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman{ 905f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman struct sdhci_host *host; 906f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman unsigned long flags; 907f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman u32 ier; 908f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 909f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman host = mmc_priv(mmc); 910f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 911f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_lock_irqsave(&host->lock, flags); 912f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 913f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier = readl(host->ioaddr + SDHCI_INT_ENABLE); 914f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 915f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier &= ~SDHCI_INT_CARD_INT; 916f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (enable) 917f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier |= SDHCI_INT_CARD_INT; 918f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 919f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_INT_ENABLE); 920f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); 921f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 922f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmiowb(); 923f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 924f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 925f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman} 926f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 927ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops sdhci_ops = { 928d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .request = sdhci_request, 929d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .set_ios = sdhci_set_ios, 930d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .get_ro = sdhci_get_ro, 931f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman .enable_sdio_irq = sdhci_enable_sdio_irq, 932d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}; 933d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 934d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 935d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 936d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Tasklets * 937d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 938d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 939d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 940d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_card(unsigned long param) 941d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 942d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 943d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 944d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 945d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 946d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 947d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 948d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 949d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { 950d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 951d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Card removed during transfer!\n", 952d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 953d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Resetting controller.\n", 954d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 955d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 956d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 957d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 958d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 95917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 960d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 961d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 962d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 963d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 964d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 965d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 966d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_detect_change(host->mmc, msecs_to_jiffies(500)); 967d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 968d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 969d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_finish(unsigned long param) 970d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 971d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 972d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 973d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_request *mrq; 974d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 975d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 976d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 977d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 978d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 979d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer(&host->timer); 980d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 981d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mrq = host->mrq; 982d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 983d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 984d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 985d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 986d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 98717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (mrq->cmd->error || 98817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman (mrq->data && (mrq->data->error || 98984c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman (mrq->data->stop && mrq->data->stop->error))) || 99084c46a53fc4ea4ff36df783a20187b2f65dd21ccPierre Ossman (host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { 991645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 992645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Some controllers need this kick or reset won't work here */ 993645289dca5021224279e67b4655796cafdfdad00Pierre Ossman if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { 994645289dca5021224279e67b4655796cafdfdad00Pierre Ossman unsigned int clock; 995645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 996645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* This is to force an update */ 997645289dca5021224279e67b4655796cafdfdad00Pierre Ossman clock = host->clock; 998645289dca5021224279e67b4655796cafdfdad00Pierre Ossman host->clock = 0; 999645289dca5021224279e67b4655796cafdfdad00Pierre Ossman sdhci_set_clock(host, clock); 1000645289dca5021224279e67b4655796cafdfdad00Pierre Ossman } 1001645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 1002645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Spec says we should do both at the same time, but Ricoh 1003645289dca5021224279e67b4655796cafdfdad00Pierre Ossman controllers do not like that. */ 1004d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 1005d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 1006d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1007d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1008d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = NULL; 1009d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 1010d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 1011d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10122f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 1013d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_deactivate_led(host); 10142f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 1015d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10165f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1017d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1018d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1019d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_request_done(host->mmc, mrq); 1020d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1021d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1022d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_timeout_timer(unsigned long data) 1023d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1024d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1025d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1026d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1027d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)data; 1028d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1029d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1030d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1031d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 1032acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Timeout waiting for hardware " 1033acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "interrupt.\n", mmc_hostname(host->mmc)); 1034d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1035d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1036d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->data) { 103717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 1038d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 1039d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 1040d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd) 104117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 1042d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 104317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ETIMEDOUT; 1044d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1045d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 1046d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1047d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1048d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10495f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1050d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1051d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1052d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1053d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1054d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1055d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Interrupt handling * 1056d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1057d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1058d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1059d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) 1060d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1061d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 1062d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1063d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->cmd) { 1064b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got command interrupt 0x%08x even " 1065b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no command operation was in progress.\n", 1066b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 1067d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1068d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1069d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1070d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 107143b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman if (intmask & SDHCI_INT_TIMEOUT) 107217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 107317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | 107417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman SDHCI_INT_INDEX)) 107517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -EILSEQ; 107643b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman 107717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->cmd->error) 1078d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 107943b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman else if (intmask & SDHCI_INT_RESPONSE) 108043b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman sdhci_finish_command(host); 1081d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1082d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1083d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_data_irq(struct sdhci_host *host, u32 intmask) 1084d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1085d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 1086d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1087d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->data) { 1088d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1089d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * A data end interrupt is sent together with the response 1090d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * for the stop command. 1091d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1092d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_END) 1093d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1094d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1095b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got data interrupt 0x%08x even " 1096b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no data operation was in progress.\n", 1097b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 1098d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1099d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1100d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1101d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1102d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1103d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_TIMEOUT) 110417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 110517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) 110617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -EILSEQ; 1107d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 110817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->data->error) 1109d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 1110d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else { 1111a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) 1112d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_transfer_pio(host); 1113d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11146ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman /* 11156ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * We currently don't do anything fancy with DMA 11166ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * boundaries, but as we can't disable the feature 11176ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * we need to at least restart the transfer. 11186ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman */ 11196ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman if (intmask & SDHCI_INT_DMA_END) 11206ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), 11216ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman host->ioaddr + SDHCI_DMA_ADDRESS); 11226ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman 1123e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (intmask & SDHCI_INT_DATA_END) { 1124e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->cmd) { 1125e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman /* 1126e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * Data managed to finish before the 1127e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * command completed. Make sure we do 1128e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * things in the proper order. 1129e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman */ 1130e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman host->data_early = 1; 1131e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } else { 1132e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 1133e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1134e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1136d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11387d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sdhci_irq(int irq, void *dev_id) 1139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman irqreturn_t result; 1141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host* host = dev_id; 1142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u32 intmask; 1143f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman int cardint = 0; 1144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock(&host->lock); 1146d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask = readl(host->ioaddr + SDHCI_INT_STATUS); 1148d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 114962df67a523acd7a22d936bf946b1889dbd60ca98Mark Lord if (!intmask || intmask == 0xffffffff) { 1150d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_NONE; 1151d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 1152d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1153d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1154b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman DBG("*** %s got interrupt: 0x%08x\n", 1155b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(host->mmc), intmask); 1156d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11573192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { 11583192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), 11593192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 1160d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->card_tasklet); 11613192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1162d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11633192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); 1164d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11653192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & SDHCI_INT_CMD_MASK) { 1166d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_CMD_MASK, 1167d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 11683192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); 1169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_MASK) { 1172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_DATA_MASK, 1173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 11743192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); 1175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); 1178d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1179964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman intmask &= ~SDHCI_INT_ERROR; 1180964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman 1181d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_BUS_POWER) { 11823192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman printk(KERN_ERR "%s: Card is consuming too much power!\n", 1183d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 11843192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS); 1185d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1186d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11879d26a5d3f2b9c4fe4b2ba491683c6989ecd6ae04Rolf Eike Beer intmask &= ~SDHCI_INT_BUS_POWER; 11883192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman 1189f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (intmask & SDHCI_INT_CARD_INT) 1190f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman cardint = 1; 1191f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1192f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman intmask &= ~SDHCI_INT_CARD_INT; 1193f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 11943192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask) { 1195acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", 11963192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman mmc_hostname(host->mmc), intmask); 1197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1198d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1199d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_STATUS); 12003192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1201d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1202d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_HANDLED; 1203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12045f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 1206d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock(&host->lock); 1207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1208f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman /* 1209f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman * We have to delay this as it calls back into the driver. 1210f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman */ 1211f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (cardint) 1212f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmc_signal_sdio_irq(host->mmc); 1213f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1214d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return result; 1215d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1216d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1217d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1218d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Suspend/resume * 1220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1221d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1222d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1223d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_PM 1224d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1225d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_suspend (struct pci_dev *pdev, pm_message_t state) 1226d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1227d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1228d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i, ret; 1229d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1230d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = pci_get_drvdata(pdev); 1231d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!chip) 1232d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1233d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1234d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman DBG("Suspending...\n"); 1235d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1236d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < chip->num_slots;i++) { 1237d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!chip->hosts[i]) 1238d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman continue; 1239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = mmc_suspend_host(chip->hosts[i]->mmc, state); 1240d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) { 1241d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i--;i >= 0;i--) 1242d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_resume_host(chip->hosts[i]->mmc); 1243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1244d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1245d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1246d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1247d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_save_state(pdev); 1248d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); 1249a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1250a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman for (i = 0;i < chip->num_slots;i++) { 1251a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman if (!chip->hosts[i]) 1252a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman continue; 1253a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman free_irq(chip->hosts[i]->irq, chip->hosts[i]); 1254a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman } 1255a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1256d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_disable_device(pdev); 1257d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_power_state(pdev, pci_choose_state(pdev, state)); 1258d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1261d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1262d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_resume (struct pci_dev *pdev) 1263d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1264d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1265d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i, ret; 1266d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1267d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = pci_get_drvdata(pdev); 1268d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!chip) 1269d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1270d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1271d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman DBG("Resuming...\n"); 1272d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1273d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_power_state(pdev, PCI_D0); 1274d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_restore_state(pdev); 1275df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman ret = pci_enable_device(pdev); 1276df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman if (ret) 1277df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman return ret; 1278d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1279d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < chip->num_slots;i++) { 1280d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!chip->hosts[i]) 1281d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman continue; 1282d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (chip->hosts[i]->flags & SDHCI_USE_DMA) 1283d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_master(pdev); 1284a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman ret = request_irq(chip->hosts[i]->irq, sdhci_irq, 1285b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc), 1286a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman chip->hosts[i]); 1287a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman if (ret) 1288a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman return ret; 1289d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(chip->hosts[i]); 12905f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1291d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = mmc_resume_host(chip->hosts[i]->mmc); 1292d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 1293d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1294d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1295d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1296d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1297d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1298d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1299d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#else /* CONFIG_PM */ 1300d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1301d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define sdhci_suspend NULL 1302d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define sdhci_resume NULL 1303d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1304d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif /* CONFIG_PM */ 1305d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1306d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1307d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1308d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Device probing/removal * 1309d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1310d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1311d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1312d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) 1313d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1314d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int ret; 13154a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman unsigned int version; 1316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1317d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_host *mmc; 1318d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1319d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1320d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 first_bar; 1321d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned int caps; 1322d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1323d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = pci_get_drvdata(pdev); 1324d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(!chip); 1325d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1326d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); 1327d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 1328d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1329d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1330d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; 1331d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1332d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (first_bar > 5) { 1333d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n"); 1334d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return -ENODEV; 1335d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1336d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1337d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) { 1338d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n"); 1339d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return -ENODEV; 1340d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1341d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1342d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (pci_resource_len(pdev, first_bar + slot) != 0x100) { 1343a98087cf81e91999a91ceedb2d2e3a95827c651fPierre Ossman printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. " 1344a98087cf81e91999a91ceedb2d2e3a95827c651fPierre Ossman "You may experience problems.\n"); 1345d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1346d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13476743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { 13486743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n"); 13496743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman return -ENODEV; 13506743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman } 13516743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 13526743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { 13536743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n"); 13546743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman return -ENODEV; 13556743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman } 13566743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1357d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev); 1358d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!mmc) 1359d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return -ENOMEM; 1360d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1361d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 1362d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mmc = mmc; 1363d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13648a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman host->chip = chip; 13658a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman chip->hosts[slot] = host; 13668a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman 1367d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->bar = first_bar + slot; 1368d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1369d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->addr = pci_resource_start(pdev, host->bar); 1370d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->irq = pdev->irq; 1371d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1372d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); 1373d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1374b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc)); 1375d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 1376d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto free; 1377d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1378d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr = ioremap_nocache(host->addr, 1379d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_resource_len(pdev, host->bar)); 1380d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->ioaddr) { 1381d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = -ENOMEM; 1382d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto release; 1383d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1384d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1385d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1386d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman 13874a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version = readw(host->ioaddr + SDHCI_HOST_VERSION); 13884a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; 1389c6573c94670882079174e2ea0da4abf1a0da51fePierre Ossman if (version > 1) { 13904a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman printk(KERN_ERR "%s: Unknown controller version (%d). " 1391b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "You may experience problems.\n", mmc_hostname(mmc), 13924a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version); 13934a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman } 13944a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman 1395d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman caps = readl(host->ioaddr + SDHCI_CAPABILITIES); 1396d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1397d6f8deecefc133cac044f6029bdb349a1cb8753aPierre Ossman if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) 139898608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman host->flags |= SDHCI_USE_DMA; 13996743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else if (!(caps & SDHCI_CAN_DO_DMA)) 14006743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman DBG("Controller doesn't have DMA capability\n"); 14016743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else 1402d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->flags |= SDHCI_USE_DMA; 1403d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 14047c168e3db7d900008ee304574057e0dc1a8505afFeng Tang if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) && 14057c168e3db7d900008ee304574057e0dc1a8505afFeng Tang (host->flags & SDHCI_USE_DMA)) { 1406cee687ce4ab1197e20d4dacc09df01531362fdbdRolf Eike Beer DBG("Disabling DMA as it is marked broken\n"); 14077c168e3db7d900008ee304574057e0dc1a8505afFeng Tang host->flags &= ~SDHCI_USE_DMA; 14087c168e3db7d900008ee304574057e0dc1a8505afFeng Tang } 14097c168e3db7d900008ee304574057e0dc1a8505afFeng Tang 141056e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && 141156e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang (host->flags & SDHCI_USE_DMA)) { 141256e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang printk(KERN_WARNING "%s: Will use DMA " 141356e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang "mode even though HW doesn't fully " 1414b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "claim to support it.\n", mmc_hostname(mmc)); 141556e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang } 141656e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang 1417d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) { 1418d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { 1419d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_WARNING "%s: No suitable DMA available. " 1420b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "Falling back to PIO.\n", mmc_hostname(mmc)); 1421d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->flags &= ~SDHCI_USE_DMA; 1422d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1423d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1424d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1425d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) 1426d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_master(pdev); 1427d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else /* XXX: Hack to get MMC layer to avoid highmem */ 1428d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pdev->dma_mask = 0; 1429d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 14308ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman host->max_clk = 14318ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; 14328ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman if (host->max_clk == 0) { 14338ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify base clock " 1434b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 14358ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman ret = -ENODEV; 14368ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman goto unmap; 14378ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman } 1438d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->max_clk *= 1000000; 1439d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 14401c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk = 14411c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; 14421c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (host->timeout_clk == 0) { 14431c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " 1444b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 14451c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman ret = -ENODEV; 14461c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman goto unmap; 14471c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 14481c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (caps & SDHCI_TIMEOUT_CLK_UNIT) 14491c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk *= 1000; 1450d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1451d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1452d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Set host parameters. 1453d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1454d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->ops = &sdhci_ops; 1455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_min = host->max_clk / 256; 1456d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_max = host->max_clk; 1457f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ; 1458d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1459cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (caps & SDHCI_CAN_DO_HISPD) 1460cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman mmc->caps |= MMC_CAP_SD_HIGHSPEED; 1461cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1462146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail = 0; 1463146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (caps & SDHCI_CAN_VDD_330) 1464146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; 1465c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_300) 1466146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; 1467c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_180) 146855556da01284af8c2174b786b3eca8e11301b656Philip Langdale mmc->ocr_avail |= MMC_VDD_165_195; 1469146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1470146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (mmc->ocr_avail == 0) { 1471146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman printk(KERN_ERR "%s: Hardware doesn't report any " 1472b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "support voltages.\n", mmc_hostname(mmc)); 1473146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman ret = -ENODEV; 1474146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman goto unmap; 1475146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 1476146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1477d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_init(&host->lock); 1478d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1479d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1480d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Maximum number of segments. Hardware cannot do scatter lists. 1481d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1482d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) 1483d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_hw_segs = 1; 1484d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 1485d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_hw_segs = 16; 1486d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_phys_segs = 16; 1487d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1488d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1489bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman * Maximum number of sectors in one transfer. Limited by DMA boundary 149055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * size (512KiB). 1491d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 149255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 524288; 1493d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1494d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1495d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Maximum segment size. Could be one segment with the maximum number 149655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * of bytes. 1497d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 149855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_seg_size = mmc->max_req_size; 1499d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1500d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1501fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Maximum block size. This varies from controller to controller and 1502fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * is specified in the capabilities register. 1503fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 1504fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; 1505fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman if (mmc->max_blk_size >= 3) { 1506b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman printk(KERN_WARNING "%s: Invalid maximum block size, " 1507b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "assuming 512 bytes\n", mmc_hostname(mmc)); 150803f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512; 150903f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel } else 151003f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512 << mmc->max_blk_size; 1511fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 1512fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 151355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Maximum block count. 151455db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 151555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = 65535; 151655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 151755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 1518d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Init tasklets. 1519d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1520d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->card_tasklet, 1521d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_card, (unsigned long)host); 1522d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->finish_tasklet, 1523d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_finish, (unsigned long)host); 1524d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1525e4cad1b5a4851c90c1bcf460062074a2fa10815bAl Viro setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); 1526d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1527dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 1528b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(mmc), host); 1529d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 15308ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman goto untasklet; 1531d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1532d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 1533d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1534d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_MMC_DEBUG 1535d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1536d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif 1537d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15382f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 15392f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.name = mmc_hostname(mmc); 15402f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness = LED_OFF; 15412f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.default_trigger = mmc_hostname(mmc); 15422f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness_set = sdhci_led_control; 15432f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 15442f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman ret = led_classdev_register(&pdev->dev, &host->led); 15452f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (ret) 15462f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman goto reset; 15472f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 15482f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 15495f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 15505f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman 1551d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_add_host(mmc); 1552d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1553b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", 1554b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(mmc), host->addr, host->irq, 1555d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); 1556d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1557d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1558d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15592f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 15602f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanreset: 15612f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 15622f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman free_irq(host->irq, host); 15632f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 15648ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanuntasklet: 1565d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1566d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 15678ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanunmap: 1568d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman iounmap(host->ioaddr); 1569d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanrelease: 1570d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_release_region(pdev, host->bar); 1571d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanfree: 1572d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_free_host(mmc); 1573d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1574d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1575d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1576d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1577d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_remove_slot(struct pci_dev *pdev, int slot) 1578d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1579d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_host *mmc; 1581d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1582d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1583d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = pci_get_drvdata(pdev); 1584d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = chip->hosts[slot]; 1585d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc = host->mmc; 1586d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1587d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip->hosts[slot] = NULL; 1588d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1589d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_remove_host(mmc); 1590d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15912f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 15922f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman led_classdev_unregister(&host->led); 15932f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 15942f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1595d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1596d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1597d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman free_irq(host->irq, host); 1598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer_sync(&host->timer); 1600d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 1603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1604d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman iounmap(host->ioaddr); 1605d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_release_region(pdev, host->bar); 1607d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1608d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_free_host(mmc); 1609d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1610d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1611d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __devinit sdhci_probe(struct pci_dev *pdev, 1612d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman const struct pci_device_id *ent) 1613d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1614d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int ret, i; 161551f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman u8 slots, rev; 1616d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1617d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1618d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(pdev == NULL); 1619d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(ent == NULL); 1620d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 162151f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); 162251f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman 162351f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman printk(KERN_INFO DRIVER_NAME 162451f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman ": SDHCI controller found at %s [%04x:%04x] (rev %x)\n", 162551f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman pci_name(pdev), (int)pdev->vendor, (int)pdev->device, 162651f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman (int)rev); 1627d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1628d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); 1629d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 1630d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1631d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1632d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman slots = PCI_SLOT_INFO_SLOTS(slots) + 1; 1633d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman DBG("found %d slot(s)\n", slots); 1634d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (slots == 0) 1635d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return -ENODEV; 1636d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1637d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = pci_enable_device(pdev); 1638d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 1639d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1640d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1641d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = kzalloc(sizeof(struct sdhci_chip) + 1642d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sizeof(struct sdhci_host*) * slots, GFP_KERNEL); 1643d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!chip) { 1644d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = -ENOMEM; 1645d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto err; 1646d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1647d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1648d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip->pdev = pdev; 1649df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman chip->quirks = ent->driver_data; 1650df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman 1651df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman if (debug_quirks) 1652df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman chip->quirks = debug_quirks; 1653d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1654d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip->num_slots = slots; 1655d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_drvdata(pdev, chip); 1656d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1657d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < slots;i++) { 1658d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ret = sdhci_probe_slot(pdev, i); 1659d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) { 1660d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i--;i >= 0;i--) 1661d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_remove_slot(pdev, i); 1662d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto free; 1663d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1664d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1665d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1666d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1667d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1668d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanfree: 1669d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_drvdata(pdev, NULL); 1670d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman kfree(chip); 1671d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1672d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanerr: 1673d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_disable_device(pdev); 1674d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1675d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1676d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1677d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __devexit sdhci_remove(struct pci_dev *pdev) 1678d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1679d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i; 1680d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_chip *chip; 1681d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1682d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman chip = pci_get_drvdata(pdev); 1683d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1684d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (chip) { 1685d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < chip->num_slots;i++) 1686d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_remove_slot(pdev, i); 1687d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1688d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_set_drvdata(pdev, NULL); 1689d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1690d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman kfree(chip); 1691d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1692d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1693d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_disable_device(pdev); 1694d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1695d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1696d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic struct pci_driver sdhci_driver = { 1697d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .name = DRIVER_NAME, 1698d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .id_table = pci_ids, 1699d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .probe = sdhci_probe, 1700d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .remove = __devexit_p(sdhci_remove), 1701d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .suspend = sdhci_suspend, 1702d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .resume = sdhci_resume, 1703d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}; 1704d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1706d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1707d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Driver init/exit * 1708d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1709d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1710d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1711d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __init sdhci_drv_init(void) 1712d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1713d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME 171452fbf9c976b36654e08e94c3107ddbaac7e2da33Pierre Ossman ": Secure Digital Host Controller Interface driver\n"); 1715d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); 1716d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1717d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return pci_register_driver(&sdhci_driver); 1718d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1719d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1720d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __exit sdhci_drv_exit(void) 1721d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1722d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman DBG("Exiting\n"); 1723d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1724d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman pci_unregister_driver(&sdhci_driver); 1725d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1726d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1727d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_init(sdhci_drv_init); 1728d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_exit(sdhci_drv_exit); 1729d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1730df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanmodule_param(debug_quirks, uint, 0444); 17316743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1732d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); 1733d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); 1734d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_LICENSE("GPL"); 17356743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1736df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre OssmanMODULE_PARM_DESC(debug_quirks, "Force certain quirks."); 1737