sdhci.c revision 980167b7fb20fb181766218b4771fc7420a7bbb4
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> 18b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman#include <linux/io.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 35d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *); 36d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *); 37d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 38d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *, struct mmc_command *); 39d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *); 40d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 41d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_dumpregs(struct sdhci_host *host) 42d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 43d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); 44d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 45d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", 46d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_DMA_ADDRESS), 47d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_HOST_VERSION)); 48d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", 49d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_BLOCK_SIZE), 50d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_BLOCK_COUNT)); 51d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", 52d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_ARGUMENT), 53d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_TRANSFER_MODE)); 54d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", 55d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_PRESENT_STATE), 56d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_HOST_CONTROL)); 57d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", 58d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_POWER_CONTROL), 59d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); 60d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", 612df3b71b2746469b5b344cf7da5facecd4110cc9Nicolas Pitre readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL), 62d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); 63d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", 64d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), 65d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_INT_STATUS)); 66d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", 67d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_INT_ENABLE), 68d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); 69d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", 70d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_ACMD12_ERR), 71d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readw(host->ioaddr + SDHCI_SLOT_INT_STATUS)); 72d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", 73d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_CAPABILITIES), 74d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readl(host->ioaddr + SDHCI_MAX_CURRENT)); 75d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 76d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); 77d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 78d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 79d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 80d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 81d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Low level functions * 82d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 83d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 84d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 85d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_reset(struct sdhci_host *host, u8 mask) 86d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 87e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman unsigned long timeout; 88e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman 89b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { 908a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 918a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman SDHCI_CARD_PRESENT)) 928a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman return; 938a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman } 948a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman 95d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET); 96d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 97e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman if (mask & SDHCI_RESET_ALL) 98d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->clock = 0; 99d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 100e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman /* Wait max 100 ms */ 101e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman timeout = 100; 102e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman 103e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman /* hw clears the bit when it's done */ 104e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) { 105e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman if (timeout == 0) { 106acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Reset 0x%x never completed.\n", 107e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman mmc_hostname(host->mmc), (int)mask); 108e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman sdhci_dumpregs(host); 109e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman return; 110e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman } 111e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman timeout--; 112e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman mdelay(1); 113d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 114d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 115d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 116d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_init(struct sdhci_host *host) 117d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 118d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u32 intmask; 119d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 120d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 121d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1223192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | 1233192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | 1243192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | 1253192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | 126a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | 1272134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | 1282134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman SDHCI_INT_ADMA_ERROR; 129d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); 131d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); 132d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 133d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 134d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_activate_led(struct sdhci_host *host) 135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 136d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_LED; 140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_deactivate_led(struct sdhci_host *host) 144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 146d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 148d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_LED; 149d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 150d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 151d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1522f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 1532f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanstatic void sdhci_led_control(struct led_classdev *led, 1542f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman enum led_brightness brightness) 1552f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman{ 1562f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman struct sdhci_host *host = container_of(led, struct sdhci_host, led); 1572f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman unsigned long flags; 1582f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1592f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1602f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1612f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (brightness == LED_OFF) 1622f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_deactivate_led(host); 1632f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman else 1642f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_activate_led(host); 1652f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1662f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1672f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman} 1682f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 1692f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Core functions * 173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 174d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 176a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_read_block_pio(struct sdhci_host *host) 177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1787659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman unsigned long flags; 1797659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman size_t blksize, len, chunk; 1807659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman u32 scratch; 1817659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman u8 *buf; 182d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 183a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO reading\n"); 184d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 185a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 1867659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk = 0; 187d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1887659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman local_irq_save(flags); 189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 190a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 1917659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (!sg_miter_next(&host->sg_miter)) 1927659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman BUG(); 193d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1947659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman len = min(host->sg_miter.length, blksize); 195d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1967659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman blksize -= len; 1977659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman host->sg_miter.consumed = len; 19814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 1997659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman buf = host->sg_miter.addr; 200d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2017659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman while (len) { 2027659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (chunk == 0) { 2037659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman scratch = readl(host->ioaddr + SDHCI_BUFFER); 2047659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk = 4; 205a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 2067659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2077659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman *buf = scratch & 0xFF; 2087659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2097659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman buf++; 2107659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman scratch >>= 8; 2117659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk--; 2127659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman len--; 213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 214a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 2157659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2167659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman sg_miter_stop(&host->sg_miter); 2177659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2187659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman local_irq_restore(flags); 219a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 221a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_write_block_pio(struct sdhci_host *host) 222a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 2237659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman unsigned long flags; 2247659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman size_t blksize, len, chunk; 2257659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman u32 scratch; 2267659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman u8 *buf; 227d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 228a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO writing\n"); 229a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 230a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 2317659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk = 0; 2327659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman scratch = 0; 233d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2347659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman local_irq_save(flags); 235d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 236a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 2377659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (!sg_miter_next(&host->sg_miter)) 2387659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman BUG(); 239a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 2407659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman len = min(host->sg_miter.length, blksize); 2417659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2427659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman blksize -= len; 2437659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman host->sg_miter.consumed = len; 2447659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2457659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman buf = host->sg_miter.addr; 246d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2477659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman while (len) { 2487659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman scratch |= (u32)*buf << (chunk * 8); 2497659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2507659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman buf++; 2517659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk++; 2527659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman len--; 2537659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2547659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if ((chunk == 4) || ((len == 0) && (blksize == 0))) { 2557659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman writel(scratch, host->ioaddr + SDHCI_BUFFER); 2567659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman chunk = 0; 2577659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman scratch = 0; 258d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 2617659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2627659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman sg_miter_stop(&host->sg_miter); 2637659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman 2647659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman local_irq_restore(flags); 265a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 266a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 267a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_transfer_pio(struct sdhci_host *host) 268a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 269a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 mask; 270a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 271a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(!host->data); 272a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 2737659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (host->blocks == 0) 274a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman return; 275a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 276a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 277a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_DATA_AVAILABLE; 278a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 279a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_SPACE_AVAILABLE; 280a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 2814a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman /* 2824a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman * Some controllers (JMicron JMB38x) mess up the buffer bits 2834a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman * for transfers < 4 bytes. As long as it is just one block, 2844a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman * we can ignore the bits. 2854a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman */ 2864a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) && 2874a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman (host->data->blocks == 1)) 2884a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman mask = ~0; 2894a3cba32cb514168bb2516c045b178e6660421d1Pierre Ossman 290a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 291a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 292a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_read_block_pio(host); 293a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 294a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_write_block_pio(host); 295d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2967659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman host->blocks--; 2977659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (host->blocks == 0) 298a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman break; 299a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 300d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 301a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO transfer complete.\n"); 302d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 303d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 3042134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossmanstatic char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) 3052134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman{ 3062134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman local_irq_save(*flags); 3072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; 3082134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman} 3092134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3102134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossmanstatic void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) 3112134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman{ 3122134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman kunmap_atomic(buffer, KM_BIO_SRC_IRQ); 3132134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman local_irq_restore(*flags); 3142134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman} 3152134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3168f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossmanstatic int sdhci_adma_table_pre(struct sdhci_host *host, 3172134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct mmc_data *data) 3182134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman{ 3192134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int direction; 3202134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3212134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman u8 *desc; 3222134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman u8 *align; 3232134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_addr_t addr; 3242134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_addr_t align_addr; 3252134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int len, offset; 3262134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3272134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct scatterlist *sg; 3282134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int i; 3292134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman char *buffer; 3302134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman unsigned long flags; 3312134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3322134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 3332134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * The spec does not specify endianness of descriptor table. 3342134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * We currently guess that it is LE. 3352134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 3362134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3372134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (data->flags & MMC_DATA_READ) 3382134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman direction = DMA_FROM_DEVICE; 3392134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else 3402134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman direction = DMA_TO_DEVICE; 3412134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3422134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 3432134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * The ADMA descriptor table is mapped further down as we 3442134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * need to fill it with data first. 3452134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 3462134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->align_addr = dma_map_single(mmc_dev(host->mmc), 3482134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->align_buffer, 128 * 4, direction); 3498d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) 3508f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman goto fail; 3512134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman BUG_ON(host->align_addr & 0x3); 3522134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3532134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->sg_count = dma_map_sg(mmc_dev(host->mmc), 3542134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman data->sg, data->sg_len, direction); 3558f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman if (host->sg_count == 0) 3568f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman goto unmap_align; 3572134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3582134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc = host->adma_desc; 3592134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align = host->align_buffer; 3602134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3612134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align_addr = host->align_addr; 3622134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3632134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman for_each_sg(data->sg, sg, host->sg_count, i) { 3642134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman addr = sg_dma_address(sg); 3652134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman len = sg_dma_len(sg); 3662134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3672134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 3682134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * The SDHCI specification states that ADMA 3692134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * addresses must be 32-bit aligned. If they 3702134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * aren't, then we use a bounce buffer for 3712134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * the (up to three) bytes that screw up the 3722134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * alignment. 3732134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 3742134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman offset = (4 - (addr & 0x3)) & 0x3; 3752134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (offset) { 3762134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (data->flags & MMC_DATA_WRITE) { 3772134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman buffer = sdhci_kmap_atomic(sg, &flags); 3786cefd05f35177ad5d22d44519c680cf43f2ac86dPierre Ossman WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); 3792134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman memcpy(align, buffer, offset); 3802134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman sdhci_kunmap_atomic(buffer, &flags); 3812134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 3822134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3832134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[7] = (align_addr >> 24) & 0xff; 3842134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[6] = (align_addr >> 16) & 0xff; 3852134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[5] = (align_addr >> 8) & 0xff; 3862134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[4] = (align_addr >> 0) & 0xff; 3872134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3882134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman BUG_ON(offset > 65536); 3892134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3902134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[3] = (offset >> 8) & 0xff; 3912134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[2] = (offset >> 0) & 0xff; 3922134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3932134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[1] = 0x00; 3942134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[0] = 0x21; /* tran, valid */ 3952134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3962134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align += 4; 3972134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align_addr += 4; 3982134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 3992134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc += 8; 4002134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4012134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman addr += offset; 4022134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman len -= offset; 4032134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 4042134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4052134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[7] = (addr >> 24) & 0xff; 4062134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[6] = (addr >> 16) & 0xff; 4072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[5] = (addr >> 8) & 0xff; 4082134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[4] = (addr >> 0) & 0xff; 4092134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4102134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman BUG_ON(len > 65536); 4112134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4122134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[3] = (len >> 8) & 0xff; 4132134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[2] = (len >> 0) & 0xff; 4142134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4152134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[1] = 0x00; 4162134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[0] = 0x21; /* tran, valid */ 4172134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4182134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc += 8; 4192134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4202134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 4212134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * If this triggers then we have a calculation bug 4222134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * somewhere. :/ 4232134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 4242134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); 4252134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 4262134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4272134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 4282134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * Add a terminating entry. 4292134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 4302134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[7] = 0; 4312134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[6] = 0; 4322134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[5] = 0; 4332134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[4] = 0; 4342134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4352134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[3] = 0; 4362134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[2] = 0; 4372134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4382134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[1] = 0x00; 4392134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman desc[0] = 0x03; /* nop, end, valid */ 4402134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4412134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 4422134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * Resync align buffer as we might have changed it. 4432134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 4442134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (data->flags & MMC_DATA_WRITE) { 4452134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_sync_single_for_device(mmc_dev(host->mmc), 4462134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->align_addr, 128 * 4, direction); 4472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 4482134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4492134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->adma_addr = dma_map_single(mmc_dev(host->mmc), 4502134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); 451980167b7fb20fb181766218b4771fc7420a7bbb4Pierre Ossman if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) 4528f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman goto unmap_entries; 4532134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman BUG_ON(host->adma_addr & 0x3); 4548f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman 4558f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman return 0; 4568f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman 4578f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossmanunmap_entries: 4588f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman dma_unmap_sg(mmc_dev(host->mmc), data->sg, 4598f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman data->sg_len, direction); 4608f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossmanunmap_align: 4618f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman dma_unmap_single(mmc_dev(host->mmc), host->align_addr, 4628f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman 128 * 4, direction); 4638f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossmanfail: 4648f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman return -EINVAL; 4652134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman} 4662134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4672134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossmanstatic void sdhci_adma_table_post(struct sdhci_host *host, 4682134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct mmc_data *data) 4692134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman{ 4702134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int direction; 4712134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4722134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct scatterlist *sg; 4732134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int i, size; 4742134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman u8 *align; 4752134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman char *buffer; 4762134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman unsigned long flags; 4772134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4782134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (data->flags & MMC_DATA_READ) 4792134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman direction = DMA_FROM_DEVICE; 4802134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else 4812134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman direction = DMA_TO_DEVICE; 4822134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4832134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_unmap_single(mmc_dev(host->mmc), host->adma_addr, 4842134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman (128 * 2 + 1) * 4, DMA_TO_DEVICE); 4852134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4862134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_unmap_single(mmc_dev(host->mmc), host->align_addr, 4872134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 128 * 4, direction); 4882134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4892134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (data->flags & MMC_DATA_READ) { 4902134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, 4912134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman data->sg_len, direction); 4922134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4932134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align = host->align_buffer; 4942134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4952134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman for_each_sg(data->sg, sg, host->sg_count, i) { 4962134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (sg_dma_address(sg) & 0x3) { 4972134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman size = 4 - (sg_dma_address(sg) & 0x3); 4982134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 4992134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman buffer = sdhci_kmap_atomic(sg, &flags); 5006cefd05f35177ad5d22d44519c680cf43f2ac86dPierre Ossman WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); 5012134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman memcpy(buffer, align, size); 5022134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman sdhci_kunmap_atomic(buffer, &flags); 5032134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 5042134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman align += 4; 5052134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 5062134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 5072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 5082134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 5092134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_unmap_sg(mmc_dev(host->mmc), data->sg, 5102134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman data->sg_len, direction); 5112134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman} 5122134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 513ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossmanstatic u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) 514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 5151c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman u8 count; 5161c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman unsigned target_timeout, current_timeout; 517d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 518ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman /* 519ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * If the host controller provides us with an incorrect timeout 520ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * value, just skip the check and use 0xE. The hardware may take 521ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * longer to time out, but that's much better than having a too-short 522ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * timeout value. 523ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman */ 524ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)) 525ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return 0xE; 526e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 5271c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* timeout in us */ 5281c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman target_timeout = data->timeout_ns / 1000 + 5291c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman data->timeout_clks / host->clock; 530d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 5311c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* 5321c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * Figure out needed cycles. 5331c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * We do this in steps in order to fit inside a 32 bit int. 5341c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * The first step is the minimum timeout, which will have a 5351c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * minimum resolution of 6 bits: 5361c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) 2^13*1000 > 2^22, 5371c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (2) host->timeout_clk < 2^16 5381c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * => 5391c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) / (2) > 2^6 5401c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman */ 5411c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0; 5421c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout = (1 << 13) * 1000 / host->timeout_clk; 5431c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman while (current_timeout < target_timeout) { 5441c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count++; 5451c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout <<= 1; 5461c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) 5471c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman break; 5481c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 5491c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 5501c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) { 5511c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_WARNING "%s: Too large timeout requested!\n", 5521c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman mmc_hostname(host->mmc)); 5531c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0xE; 5541c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 5551c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 556ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return count; 557ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman} 558ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 559ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) 560ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman{ 561ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman u8 count; 5622134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman u8 ctrl; 5638f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman int ret; 564ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 565ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman WARN_ON(host->data); 566ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 567ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman if (data == NULL) 568ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return; 569ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 570ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman /* Sanity checks */ 571ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blksz * data->blocks > 524288); 572ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blksz > host->mmc->max_blk_size); 573ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blocks > 65535); 574ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 575ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman host->data = data; 576ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman host->data_early = 0; 577ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 578ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman count = sdhci_calc_timeout(host, data); 5791c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); 580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 581c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_USE_DMA) 582c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags |= SDHCI_REQ_USE_DMA; 583c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 5842134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 5852134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * FIXME: This doesn't account for merging when mapping the 5862134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * scatterlist. 5872134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 5882134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 5892134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int broken, i; 5902134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct scatterlist *sg; 5912134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 5922134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 0; 5932134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) { 5942134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) 5952134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 1; 5962134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } else { 5972134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) 5982134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 1; 5992134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6002134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 6012134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (unlikely(broken)) { 6022134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman for_each_sg(data->sg, sg, data->sg_len, i) { 6032134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (sg->length & 0x3) { 6042134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman DBG("Reverting to PIO because of " 6052134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman "transfer size (%d)\n", 6062134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman sg->length); 6072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 6082134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman break; 6092134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6102134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6112134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 612c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 613c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 614c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman /* 615c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * The assumption here being that alignment is the same after 616c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * translation to device address space. 617c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman */ 6182134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 6192134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman int broken, i; 6202134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman struct scatterlist *sg; 6212134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 6222134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 0; 6232134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) { 6242134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 6252134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * As we use 3 byte chunks to work around 6262134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * alignment problems, we need to check this 6272134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * quirk. 6282134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 6292134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) 6302134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 1; 6312134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } else { 6322134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) 6332134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman broken = 1; 6342134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6352134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 6362134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (unlikely(broken)) { 6372134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman for_each_sg(data->sg, sg, data->sg_len, i) { 6382134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (sg->offset & 0x3) { 6392134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman DBG("Reverting to PIO because of " 6402134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman "bad alignment\n"); 6412134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 6422134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman break; 6432134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6442134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6452134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6462134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 6472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 6488f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 6498f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman if (host->flags & SDHCI_USE_ADMA) { 6508f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman ret = sdhci_adma_table_pre(host, data); 6518f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman if (ret) { 6528f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman /* 6538f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman * This only happens when someone fed 6548f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman * us an invalid request. 6558f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman */ 6568f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman WARN_ON(1); 657ebd6d357848edb8709dd9bed4b93834d1b4d7044Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 6588f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } else { 6598f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman writel(host->adma_addr, 6608f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman host->ioaddr + SDHCI_ADMA_ADDRESS); 6618f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } 6628f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } else { 663c8b3e02eb250ceb661437e9b198757eff0eb6fd2Tomas Winkler int sg_cnt; 6648f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman 665c8b3e02eb250ceb661437e9b198757eff0eb6fd2Tomas Winkler sg_cnt = dma_map_sg(mmc_dev(host->mmc), 6668f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman data->sg, data->sg_len, 6678f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman (data->flags & MMC_DATA_READ) ? 6688f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman DMA_FROM_DEVICE : 6698f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman DMA_TO_DEVICE); 670c8b3e02eb250ceb661437e9b198757eff0eb6fd2Tomas Winkler if (sg_cnt == 0) { 6718f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman /* 6728f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman * This only happens when someone fed 6738f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman * us an invalid request. 6748f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman */ 6758f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman WARN_ON(1); 676ebd6d357848edb8709dd9bed4b93834d1b4d7044Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 6778f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } else { 678719a61b452ff74cf81a96e4212748d9d63bcc924Pierre Ossman WARN_ON(sg_cnt != 1); 6798f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman writel(sg_dma_address(data->sg), 6808f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman host->ioaddr + SDHCI_DMA_ADDRESS); 6818f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } 6828f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } 6838f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman } 6848f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman 6852134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 6862134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * Always adjust the DMA selection as some controllers 6872134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * (e.g. JMicron) can't do PIO properly when the selection 6882134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * is ADMA. 6892134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 6902134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->version >= SDHCI_SPEC_200) { 6912134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 6922134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman ctrl &= ~SDHCI_CTRL_DMA_MASK; 6932134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if ((host->flags & SDHCI_REQ_USE_DMA) && 6942134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman (host->flags & SDHCI_USE_ADMA)) 6952134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman ctrl |= SDHCI_CTRL_ADMA32; 6962134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else 6972134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman ctrl |= SDHCI_CTRL_SDMA; 6982134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 699c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 700c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 7018f1934ce784bd8f2eaf06f190526500f7f3f9c74Pierre Ossman if (!(host->flags & SDHCI_REQ_USE_DMA)) { 7027659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman sg_miter_start(&host->sg_miter, 7037659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman data->sg, data->sg_len, SG_MITER_ATOMIC); 7047659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman host->blocks = data->blocks; 705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 706c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 707bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman /* We do not handle DMA boundaries, so set it to max (512 KiB) */ 708bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman writew(SDHCI_MAKE_BLKSZ(7, data->blksz), 709bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman host->ioaddr + SDHCI_BLOCK_SIZE); 710c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT); 711c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman} 712c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 713c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossmanstatic void sdhci_set_transfer_mode(struct sdhci_host *host, 714c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman struct mmc_data *data) 715c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman{ 716c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman u16 mode; 717c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 718c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data == NULL) 719c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman return; 720c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 721e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman WARN_ON(!host->data); 722e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 723c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode = SDHCI_TRNS_BLK_CNT_EN; 724c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->blocks > 1) 725c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_MULTI; 726c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->flags & MMC_DATA_READ) 727c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_READ; 728c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) 729c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_DMA; 730c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 731c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); 732d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 733d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 734d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *host) 735d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 736d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_data *data; 737d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 738d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(!host->data); 739d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 740d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman data = host->data; 741d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 742d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 743c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 7442134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) 7452134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman sdhci_adma_table_post(host, data); 7462134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else { 7472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman dma_unmap_sg(mmc_dev(host->mmc), data->sg, 7482134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman data->sg_len, (data->flags & MMC_DATA_READ) ? 7492134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman DMA_FROM_DEVICE : DMA_TO_DEVICE); 7502134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 751d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 752d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 753d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 754c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * The specification states that the block count register must 755c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * be updated, but it does not specify at what point in the 756c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * data flow. That makes the register entirely useless to read 757c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * back so we have to assume that nothing made it to the card 758c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * in the event of an error. 759d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 760c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman if (data->error) 761c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman data->bytes_xfered = 0; 762d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 763c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman data->bytes_xfered = data->blksz * data->blocks; 764d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 765d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (data->stop) { 766d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 767d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 768d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 769d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 77017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data->error) { 771d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 772d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 773d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 774d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 775d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, data->stop); 776d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 777d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 778d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 779d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 780d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) 781d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 782d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int flags; 783fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman u32 mask; 7847cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 785d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 786d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->cmd); 787d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 788d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 7897cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 790fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 791fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask = SDHCI_CMD_INHIBIT; 792fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) 793fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask |= SDHCI_DATA_INHIBIT; 794fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 795fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman /* We shouldn't wait for data inihibit for stop commands, even 796fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman though they might use busy signaling */ 797fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if (host->mrq->data && (cmd == host->mrq->data->stop)) 798fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask &= ~SDHCI_DATA_INHIBIT; 799fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 800fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 8017cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 802d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Controller never released " 803acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "inhibit bit(s).\n", mmc_hostname(host->mmc)); 804d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 80517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EIO; 806d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 807d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 808d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 8097cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 8107cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 8117cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 812d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 813d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mod_timer(&host->timer, jiffies + 10 * HZ); 814d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 815d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = cmd; 816d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 817d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_prepare_data(host, cmd->data); 818d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 819d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); 820d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 821c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman sdhci_set_transfer_mode(host, cmd->data); 822c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 823d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { 824acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unsupported response type!\n", 825d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 82617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EINVAL; 827d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 828d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 829d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 830d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 831d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(cmd->flags & MMC_RSP_PRESENT)) 832d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_NONE; 833d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_136) 834d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_LONG; 835d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_BUSY) 836d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT_BUSY; 837d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 838d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT; 839d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 840d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_CRC) 841d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_CRC; 842d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_OPCODE) 843d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_INDEX; 844d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->data) 845d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_DATA; 846d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 847fb61e2895170920564410baadf71c5b3561dbf42Pierre Ossman writew(SDHCI_MAKE_CMD(cmd->opcode, flags), 848d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_COMMAND); 849d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 850d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 851d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *host) 852d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 853d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i; 854d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 855d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(host->cmd == NULL); 856d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 857d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_PRESENT) { 858d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_136) { 859d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* CRC is stripped so we need to do some shifting. */ 860d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < 4;i++) { 861d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] = readl(host->ioaddr + 862d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4) << 8; 863d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (i != 3) 864d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] |= 865d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + 866d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4-1); 867d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 868d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 869d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE); 870d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 871d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 872d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 87317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = 0; 874d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 875e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->data && host->data_early) 876e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 877e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 878e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (!host->cmd->data) 879d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 880d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 881d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 882d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 883d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 884d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 885d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 886d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int div; 887d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u16 clk; 8887cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 889d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 890d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == host->clock) 891d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 892d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 893d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); 894d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 895d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == 0) 896d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 897d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 898d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (div = 1;div < 256;div *= 2) { 899d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((host->max_clk / div) <= clock) 900d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman break; 901d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 902d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman div >>= 1; 903d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 904d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk = div << SDHCI_DIVIDER_SHIFT; 905d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_INT_EN; 906d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 907d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 908d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 9097cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 9107cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL)) 9117cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman & SDHCI_CLOCK_INT_STABLE)) { 9127cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 913acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Internal clock never " 914acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "stabilised.\n", mmc_hostname(host->mmc)); 915d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 916d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 917d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 9187cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 9197cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 9207cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 921d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 922d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_CARD_EN; 923d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 924d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 925d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 926d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->clock = clock; 927d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 928d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 929146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanstatic void sdhci_set_power(struct sdhci_host *host, unsigned short power) 930146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman{ 931146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman u8 pwr; 932146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 933146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (host->power == power) 934146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman return; 935146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 9369e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt if (power == (unsigned short)-1) { 9379e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 938146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman goto out; 9399e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt } 9409e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt 9419e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt /* 9429e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * Spec says that we should clear the power reg before setting 9439e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * a new value. Some controllers don't seem to like this though. 9449e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt */ 945b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) 9469e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 947146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 948146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr = SDHCI_POWER_ON; 949146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 9504be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale switch (1 << power) { 95155556da01284af8c2174b786b3eca8e11301b656Philip Langdale case MMC_VDD_165_195: 952146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_180; 953146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 9544be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_29_30: 9554be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_30_31: 956146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_300; 957146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 9584be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_32_33: 9594be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_33_34: 960146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_330; 961146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 962146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman default: 963146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman BUG(); 964146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 965146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 966e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon /* 967c71f65129a1fb67bc6b9b8d03b493675b5c9302bAndres Salomon * At least the Marvell CaFe chip gets confused if we set the voltage 968e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon * and set turn on power at the same time, so set the voltage first. 969e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon */ 970b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)) 971e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon writeb(pwr & ~SDHCI_POWER_ON, 972e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon host->ioaddr + SDHCI_POWER_CONTROL); 973e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon 974146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); 975146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 976146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanout: 977146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman host->power = power; 978146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman} 979146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 980d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 981d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 982d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * MMC callbacks * 983d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 984d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 985d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 986d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 987d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 988d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 989d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 990d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 991d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 992d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 993d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 994d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 995d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->mrq != NULL); 996d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 9972f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 998d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_activate_led(host); 9992f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 1000d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1001d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = mrq; 1002d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10031e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) 10041e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman || (host->flags & SDHCI_DEVICE_DEAD)) { 100517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 1006d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 1007d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 1008d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, mrq->cmd); 1009d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10105f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1011d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1012d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1013d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1014d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1015d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1016d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1017d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1018d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 1019d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1020d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 1021d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1022d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1023d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10241e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 10251e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman goto out; 10261e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 1027d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1028d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Reset the chip on each power off. 1029d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Should clear out any weird states. 1030d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1031d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) { 1032d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE); 1033d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 1034d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1035d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1036d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_set_clock(host, ios->clock); 1037d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1038d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) 1039146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, -1); 1040d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 1041146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, ios->vdd); 1042d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1043d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 1044cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1045d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->bus_width == MMC_BUS_WIDTH_4) 1046d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_4BITBUS; 1047d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 1048d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_4BITBUS; 1049cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1050cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (ios->timing == MMC_TIMING_SD_HS) 1051cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl |= SDHCI_CTRL_HISPD; 1052cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman else 1053cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl &= ~SDHCI_CTRL_HISPD; 1054cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1055d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 1056d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1057b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo /* 1058b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * Some (ENE) controllers go apeshit on some ios operation, 1059b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * signalling timeout and CRC errors even on CMD0. Resetting 1060b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * it on each ios seems to solve the problem. 1061b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo */ 1062b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) 1063b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 1064b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo 10651e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanout: 10665f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1067d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1068d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1069d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1070d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_get_ro(struct mmc_host *mmc) 1071d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1072d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1073d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1074d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int present; 1075d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1076d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 1077d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1078d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1079d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10801e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 10811e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman present = 0; 10821e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman else 10831e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman present = readl(host->ioaddr + SDHCI_PRESENT_STATE); 1084d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1085d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1086d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1087d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return !(present & SDHCI_WRITE_PROTECT); 1088d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1089d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1090f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossmanstatic void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) 1091f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman{ 1092f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman struct sdhci_host *host; 1093f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman unsigned long flags; 1094f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman u32 ier; 1095f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1096f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman host = mmc_priv(mmc); 1097f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1098f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1099f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 11001e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 11011e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman goto out; 11021e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 1103f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier = readl(host->ioaddr + SDHCI_INT_ENABLE); 1104f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1105f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier &= ~SDHCI_INT_CARD_INT; 1106f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (enable) 1107f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier |= SDHCI_INT_CARD_INT; 1108f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1109f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_INT_ENABLE); 1110f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); 1111f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 11121e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanout: 1113f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmiowb(); 1114f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1115f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1116f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman} 1117f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1118ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops sdhci_ops = { 1119d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .request = sdhci_request, 1120d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .set_ios = sdhci_set_ios, 1121d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .get_ro = sdhci_get_ro, 1122f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman .enable_sdio_irq = sdhci_enable_sdio_irq, 1123d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}; 1124d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1125d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1126d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1127d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Tasklets * 1128d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1129d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1131d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_card(unsigned long param) 1132d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1133d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1134d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1136d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 1137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { 1141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 1142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Card removed during transfer!\n", 1143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 1144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Resetting controller.\n", 1145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 1146d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 1148d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 1149d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 115017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 1151d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 1152d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1153d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1154d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1155d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1156d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1157d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_detect_change(host->mmc, msecs_to_jiffies(500)); 1158d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1159d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1160d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_finish(unsigned long param) 1161d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1162d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1163d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1164d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_request *mrq; 1165d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1166d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 1167d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1168d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer(&host->timer); 1171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mrq = host->mrq; 1173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1174d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 1176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 1177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 11781e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!(host->flags & SDHCI_DEVICE_DEAD) && 11791e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->cmd->error || 11801e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->data && (mrq->data->error || 11811e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->data->stop && mrq->data->stop->error))) || 11821e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { 1183645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 1184645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Some controllers need this kick or reset won't work here */ 1185b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { 1186645289dca5021224279e67b4655796cafdfdad00Pierre Ossman unsigned int clock; 1187645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 1188645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* This is to force an update */ 1189645289dca5021224279e67b4655796cafdfdad00Pierre Ossman clock = host->clock; 1190645289dca5021224279e67b4655796cafdfdad00Pierre Ossman host->clock = 0; 1191645289dca5021224279e67b4655796cafdfdad00Pierre Ossman sdhci_set_clock(host, clock); 1192645289dca5021224279e67b4655796cafdfdad00Pierre Ossman } 1193645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 1194645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Spec says we should do both at the same time, but Ricoh 1195645289dca5021224279e67b4655796cafdfdad00Pierre Ossman controllers do not like that. */ 1196d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 1197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 1198d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1199d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1200d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = NULL; 1201d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 1202d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 1203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12042f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 1205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_deactivate_led(host); 12062f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 1207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12085f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1209d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1210d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1211d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_request_done(host->mmc, mrq); 1212d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1214d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_timeout_timer(unsigned long data) 1215d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1216d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1217d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 1218d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)data; 1220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1221d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1222d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1223d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 1224acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Timeout waiting for hardware " 1225acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "interrupt.\n", mmc_hostname(host->mmc)); 1226d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1227d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1228d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->data) { 122917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 1230d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 1231d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 1232d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd) 123317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 1234d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 123517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ETIMEDOUT; 1236d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1237d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 1238d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1240d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12415f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1242d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1244d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1245d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1246d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1247d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Interrupt handling * 1248d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1249d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1250d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1251d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) 1252d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1253d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 1254d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1255d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->cmd) { 1256b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got command interrupt 0x%08x even " 1257b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no command operation was in progress.\n", 1258b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 1259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1261d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1262d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 126343b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman if (intmask & SDHCI_INT_TIMEOUT) 126417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 126517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | 126617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman SDHCI_INT_INDEX)) 126717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -EILSEQ; 126843b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman 126917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->cmd->error) 1270d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 127143b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman else if (intmask & SDHCI_INT_RESPONSE) 127243b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman sdhci_finish_command(host); 1273d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1274d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1275d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_data_irq(struct sdhci_host *host, u32 intmask) 1276d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1277d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 1278d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1279d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->data) { 1280d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1281d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * A data end interrupt is sent together with the response 1282d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * for the stop command. 1283d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1284d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_END) 1285d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1286d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1287b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got data interrupt 0x%08x even " 1288b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no data operation was in progress.\n", 1289b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 1290d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1291d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1292d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1293d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1294d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1295d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_TIMEOUT) 129617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 129717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) 129817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -EILSEQ; 12992134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else if (intmask & SDHCI_INT_ADMA_ERROR) 13002134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->data->error = -EIO; 1301d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 130217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->data->error) 1303d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 1304d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else { 1305a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) 1306d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_transfer_pio(host); 1307d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13086ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman /* 13096ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * We currently don't do anything fancy with DMA 13106ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * boundaries, but as we can't disable the feature 13116ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * we need to at least restart the transfer. 13126ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman */ 13136ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman if (intmask & SDHCI_INT_DMA_END) 13146ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), 13156ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman host->ioaddr + SDHCI_DMA_ADDRESS); 13166ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman 1317e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (intmask & SDHCI_INT_DATA_END) { 1318e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->cmd) { 1319e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman /* 1320e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * Data managed to finish before the 1321e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * command completed. Make sure we do 1322e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * things in the proper order. 1323e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman */ 1324e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman host->data_early = 1; 1325e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } else { 1326e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 1327e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1328e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1329d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1330d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1331d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13327d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sdhci_irq(int irq, void *dev_id) 1333d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1334d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman irqreturn_t result; 1335d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host* host = dev_id; 1336d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u32 intmask; 1337f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman int cardint = 0; 1338d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1339d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock(&host->lock); 1340d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1341d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask = readl(host->ioaddr + SDHCI_INT_STATUS); 1342d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 134362df67a523acd7a22d936bf946b1889dbd60ca98Mark Lord if (!intmask || intmask == 0xffffffff) { 1344d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_NONE; 1345d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 1346d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1347d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1348b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman DBG("*** %s got interrupt: 0x%08x\n", 1349b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(host->mmc), intmask); 1350d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13513192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { 13523192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), 13533192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 1354d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->card_tasklet); 13553192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1356d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13573192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); 1358d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13593192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & SDHCI_INT_CMD_MASK) { 1360d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_CMD_MASK, 1361d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 13623192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); 1363d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1364d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1365d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_MASK) { 1366d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_DATA_MASK, 1367d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 13683192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); 1369d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1370d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1371d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); 1372d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1373964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman intmask &= ~SDHCI_INT_ERROR; 1374964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman 1375d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_BUS_POWER) { 13763192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman printk(KERN_ERR "%s: Card is consuming too much power!\n", 1377d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 13783192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS); 1379d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1380d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13819d26a5d3f2b9c4fe4b2ba491683c6989ecd6ae04Rolf Eike Beer intmask &= ~SDHCI_INT_BUS_POWER; 13823192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman 1383f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (intmask & SDHCI_INT_CARD_INT) 1384f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman cardint = 1; 1385f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1386f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman intmask &= ~SDHCI_INT_CARD_INT; 1387f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 13883192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask) { 1389acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", 13903192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman mmc_hostname(host->mmc), intmask); 1391d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1392d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1393d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_STATUS); 13943192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1395d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1396d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_HANDLED; 1397d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13985f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1399d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 1400d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock(&host->lock); 1401d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1402f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman /* 1403f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman * We have to delay this as it calls back into the driver. 1404f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman */ 1405f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (cardint) 1406f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmc_signal_sdio_irq(host->mmc); 1407f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1408d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return result; 1409d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1410d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1411d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1412d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1413d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Suspend/resume * 1414d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1415d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1416d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1417d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_PM 1418d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1419b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) 1420d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1421b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1422a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1423b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = mmc_suspend_host(host->mmc, state); 1424b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (ret) 1425b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ret; 1426a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1427b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman free_irq(host->irq, host); 1428d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1429d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1430d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1431d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1432b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_suspend_host); 1433d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1434b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_resume_host(struct sdhci_host *host) 1435b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 1436b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1437d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1438b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->flags & SDHCI_USE_DMA) { 1439b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma) 1440b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->ops->enable_dma(host); 1441b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman } 1442d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1443b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 1444b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(host->mmc), host); 1445df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman if (ret) 1446df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman return ret; 1447d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1448b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman sdhci_init(host); 1449b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmiowb(); 1450b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman 1451b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = mmc_resume_host(host->mmc); 1452b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (ret) 1453b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ret; 1454d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1456d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1457d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1458b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_resume_host); 1459d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1460d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif /* CONFIG_PM */ 1461d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1462d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1463d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1464b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman * Device allocation/registration * 1465d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1466d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1467d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1468b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanstruct sdhci_host *sdhci_alloc_host(struct device *dev, 1469b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman size_t priv_size) 1470d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1471d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_host *mmc; 1472d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1473d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1474b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman WARN_ON(dev == NULL); 1475d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1476b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); 1477d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!mmc) 1478b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ERR_PTR(-ENOMEM); 1479d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1480d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 1481d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mmc = mmc; 1482d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1483b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return host; 1484b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman} 14858a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman 1486b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_alloc_host); 1487d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1488b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_add_host(struct sdhci_host *host) 1489b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 1490b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman struct mmc_host *mmc; 1491b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman unsigned int caps; 1492b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1493d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1494b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman WARN_ON(host == NULL); 1495b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host == NULL) 1496b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -EINVAL; 1497d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1498b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc = host->mmc; 1499d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1500b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (debug_quirks) 1501b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->quirks = debug_quirks; 1502d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1503d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1504d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman 15052134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->version = readw(host->ioaddr + SDHCI_HOST_VERSION); 15062134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->version = (host->version & SDHCI_SPEC_VER_MASK) 15072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman >> SDHCI_SPEC_VER_SHIFT; 15082134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->version > SDHCI_SPEC_200) { 15094a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman printk(KERN_ERR "%s: Unknown controller version (%d). " 1510b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "You may experience problems.\n", mmc_hostname(mmc), 15112134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->version); 15124a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman } 15134a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman 1514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman caps = readl(host->ioaddr + SDHCI_CAPABILITIES); 1515d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1516b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->quirks & SDHCI_QUIRK_FORCE_DMA) 151798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman host->flags |= SDHCI_USE_DMA; 15186743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else if (!(caps & SDHCI_CAN_DO_DMA)) 15196743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman DBG("Controller doesn't have DMA capability\n"); 15206743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else 1521d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->flags |= SDHCI_USE_DMA; 1522d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1523b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) && 15247c168e3db7d900008ee304574057e0dc1a8505afFeng Tang (host->flags & SDHCI_USE_DMA)) { 1525cee687ce4ab1197e20d4dacc09df01531362fdbdRolf Eike Beer DBG("Disabling DMA as it is marked broken\n"); 15267c168e3db7d900008ee304574057e0dc1a8505afFeng Tang host->flags &= ~SDHCI_USE_DMA; 15277c168e3db7d900008ee304574057e0dc1a8505afFeng Tang } 15287c168e3db7d900008ee304574057e0dc1a8505afFeng Tang 1529d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) { 15302134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if ((host->version >= SDHCI_SPEC_200) && 15312134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman (caps & SDHCI_CAN_DO_ADMA2)) 15322134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags |= SDHCI_USE_ADMA; 15332134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 15342134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 15352134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) && 15362134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman (host->flags & SDHCI_USE_ADMA)) { 15372134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman DBG("Disabling ADMA as it is marked broken\n"); 15382134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags &= ~SDHCI_USE_ADMA; 15392134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 15402134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 15412134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_DMA) { 1542b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma) { 1543b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma(host)) { 1544b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman printk(KERN_WARNING "%s: No suitable DMA " 1545b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman "available. Falling back to PIO.\n", 1546b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(mmc)); 15472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags &= ~(SDHCI_USE_DMA | SDHCI_USE_ADMA); 1548b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman } 1549d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1550d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1551d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15522134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) { 15532134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman /* 15542134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * We need to allocate descriptors for all sg entries 15552134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * (128) and potentially one alignment transfer for 15562134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * each of those entries. 15572134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman */ 15582134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL); 15592134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); 15602134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (!host->adma_desc || !host->align_buffer) { 15612134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman kfree(host->adma_desc); 15622134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman kfree(host->align_buffer); 15632134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman printk(KERN_WARNING "%s: Unable to allocate ADMA " 15642134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman "buffers. Falling back to standard DMA.\n", 15652134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc_hostname(mmc)); 15662134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->flags &= ~SDHCI_USE_ADMA; 15672134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 15682134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman } 15692134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 15707659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman /* 15717659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman * If we use DMA, then it's up to the caller to set the DMA 15727659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman * mask, but PIO does not need the hw shim so we set a new 15737659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman * mask here in that case. 15747659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman */ 15757659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman if (!(host->flags & SDHCI_USE_DMA)) { 15767659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman host->dma_mask = DMA_BIT_MASK(64); 15777659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman mmc_dev(host->mmc)->dma_mask = &host->dma_mask; 15787659150c60839a2bd31f74e866374abb9be17e43Pierre Ossman } 1579d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15808ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman host->max_clk = 15818ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; 15828ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman if (host->max_clk == 0) { 15838ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify base clock " 1584b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 1585b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 15868ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman } 1587d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->max_clk *= 1000000; 1588d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 15891c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk = 15901c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; 15911c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (host->timeout_clk == 0) { 15921c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " 1593b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 1594b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 15951c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 15961c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (caps & SDHCI_TIMEOUT_CLK_UNIT) 15971c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk *= 1000; 1598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1600d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Set host parameters. 1601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->ops = &sdhci_ops; 1603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_min = host->max_clk / 256; 1604d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_max = host->max_clk; 1605c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 1606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1607cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (caps & SDHCI_CAN_DO_HISPD) 1608cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman mmc->caps |= MMC_CAP_SD_HIGHSPEED; 1609cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1610146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail = 0; 1611146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (caps & SDHCI_CAN_VDD_330) 1612146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; 1613c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_300) 1614146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; 1615c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_180) 161655556da01284af8c2174b786b3eca8e11301b656Philip Langdale mmc->ocr_avail |= MMC_VDD_165_195; 1617146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1618146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (mmc->ocr_avail == 0) { 1619146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman printk(KERN_ERR "%s: Hardware doesn't report any " 1620b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "support voltages.\n", mmc_hostname(mmc)); 1621b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 1622146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 1623146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1624d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_init(&host->lock); 1625d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1626d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 16272134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * Maximum number of segments. Depends on if the hardware 16282134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * can do scatter/gather or not. 1629d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 16302134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) 16312134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc->max_hw_segs = 128; 16322134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else if (host->flags & SDHCI_USE_DMA) 1633d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_hw_segs = 1; 16342134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else /* PIO */ 16352134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc->max_hw_segs = 128; 16362134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc->max_phys_segs = 128; 1637d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1638d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1639bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman * Maximum number of sectors in one transfer. Limited by DMA boundary 164055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * size (512KiB). 1641d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 164255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 524288; 1643d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1644d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1645d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Maximum segment size. Could be one segment with the maximum number 16462134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * of bytes. When doing hardware scatter/gather, each entry cannot 16472134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman * be larger than 64 KiB though. 1648d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 16492134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman if (host->flags & SDHCI_USE_ADMA) 16502134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc->max_seg_size = 65536; 16512134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman else 16522134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman mmc->max_seg_size = mmc->max_req_size; 1653d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1654d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1655fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Maximum block size. This varies from controller to controller and 1656fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * is specified in the capabilities register. 1657fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 1658fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; 1659fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman if (mmc->max_blk_size >= 3) { 1660b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman printk(KERN_WARNING "%s: Invalid maximum block size, " 1661b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "assuming 512 bytes\n", mmc_hostname(mmc)); 166203f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512; 166303f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel } else 166403f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512 << mmc->max_blk_size; 1665fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 1666fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 166755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Maximum block count. 166855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 166955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = 65535; 167055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 167155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 1672d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Init tasklets. 1673d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1674d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->card_tasklet, 1675d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_card, (unsigned long)host); 1676d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->finish_tasklet, 1677d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_finish, (unsigned long)host); 1678d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1679e4cad1b5a4851c90c1bcf460062074a2fa10815bAl Viro setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); 1680d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1681dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 1682b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(mmc), host); 1683d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 16848ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman goto untasklet; 1685d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1686d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 1687d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1688d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_MMC_DEBUG 1689d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1690d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif 1691d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 16922f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 16932f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.name = mmc_hostname(mmc); 16942f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness = LED_OFF; 16952f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.default_trigger = mmc_hostname(mmc); 16962f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness_set = sdhci_led_control; 16972f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1698b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = led_classdev_register(mmc_dev(mmc), &host->led); 16992f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (ret) 17002f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman goto reset; 17012f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 17022f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 17035f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 17045f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman 1705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_add_host(mmc); 1706d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 17072134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s%s\n", 1708b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id, 17092134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman (host->flags & SDHCI_USE_ADMA)?"A":"", 1710d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); 1711d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1712d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1713d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 17142f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 17152f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanreset: 17162f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 17172f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman free_irq(host->irq, host); 17182f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 17198ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanuntasklet: 1720d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1721d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 1722d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1723d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1724d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1725d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1726b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_add_host); 1727d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 17281e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanvoid sdhci_remove_host(struct sdhci_host *host, int dead) 1729b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 17301e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman unsigned long flags; 17311e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 17321e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (dead) { 17331e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman spin_lock_irqsave(&host->lock, flags); 17341e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 17351e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman host->flags |= SDHCI_DEVICE_DEAD; 17361e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 17371e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->mrq) { 17381e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman printk(KERN_ERR "%s: Controller removed during " 17391e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman " transfer!\n", mmc_hostname(host->mmc)); 17401e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 17411e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 17421e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman tasklet_schedule(&host->finish_tasklet); 17431e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman } 17441e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 17451e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 17461e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman } 17471e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 1748b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_remove_host(host->mmc); 1749d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 17502f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 17512f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman led_classdev_unregister(&host->led); 17522f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 17532f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 17541e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!dead) 17551e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1756d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1757d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman free_irq(host->irq, host); 1758d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1759d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer_sync(&host->timer); 1760d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1761d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1762d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 17632134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 17642134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman kfree(host->adma_desc); 17652134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman kfree(host->align_buffer); 17662134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman 17672134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->adma_desc = NULL; 17682134a922c6e75c779983cad5d8aae832275f5a0dPierre Ossman host->align_buffer = NULL; 1769d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1770d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1771b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_remove_host); 1772d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1773b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanvoid sdhci_free_host(struct sdhci_host *host) 1774d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1775b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_free_host(host->mmc); 1776d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1777d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1778b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_free_host); 1779d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1780d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1781d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1782d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Driver init/exit * 1783d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1784d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1785d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1786d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __init sdhci_drv_init(void) 1787d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1788d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME 178952fbf9c976b36654e08e94c3107ddbaac7e2da33Pierre Ossman ": Secure Digital Host Controller Interface driver\n"); 1790d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); 1791d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1792b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return 0; 1793d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1794d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1795d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __exit sdhci_drv_exit(void) 1796d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1797d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1798d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1799d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_init(sdhci_drv_init); 1800d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_exit(sdhci_drv_exit); 1801d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1802df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanmodule_param(debug_quirks, uint, 0444); 18036743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1804d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); 1805b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanMODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); 1806d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_LICENSE("GPL"); 18076743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1808df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre OssmanMODULE_PARM_DESC(debug_quirks, "Force certain quirks."); 1809