sdhci.c revision 1e72859e3ae16346d4007024b20d2d4ef387dcc3
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 | 1273192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; 128d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 129d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); 130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); 131d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 132d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 133d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_activate_led(struct sdhci_host *host) 134d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 136d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_LED; 139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_deactivate_led(struct sdhci_host *host) 143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 146d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_LED; 148d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 149d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 150d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1512f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 1522f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanstatic void sdhci_led_control(struct led_classdev *led, 1532f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman enum led_brightness brightness) 1542f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman{ 1552f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman struct sdhci_host *host = container_of(led, struct sdhci_host, led); 1562f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman unsigned long flags; 1572f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1582f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_lock_irqsave(&host->lock, flags); 1592f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1602f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (brightness == LED_OFF) 1612f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_deactivate_led(host); 1622f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman else 1632f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_activate_led(host); 1642f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1652f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1662f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman} 1672f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 1682f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Core functions * 172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 174d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1752a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossmanstatic inline char* sdhci_sg_to_buffer(struct sdhci_host* host) 176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 17745711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe return sg_virt(host->cur_sg); 178d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 179d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 180d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic inline int sdhci_next_sg(struct sdhci_host* host) 181d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 182d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 183d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Skip to next SG entry. 184d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 185d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cur_sg++; 186d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->num_sg--; 187d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 188d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Any entries left? 190d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 191d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->num_sg > 0) { 192d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset = 0; 193d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain = host->cur_sg->length; 194d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 195d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 196d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return host->num_sg; 197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 198d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 199a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_read_block_pio(struct sdhci_host *host) 200d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 201a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int blksize, chunk_remain; 202a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 data; 203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman char *buffer; 204a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int size; 205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 206a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO reading\n"); 207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 208a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 209a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = 0; 210a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = 0; 211d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 2122a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host) + host->offset; 213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 214a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 215a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (chunk_remain == 0) { 216a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = readl(host->ioaddr + SDHCI_BUFFER); 217a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = min(blksize, 4); 218a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 22014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov size = min(host->remain, chunk_remain); 221d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 222a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain -= size; 223a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize -= size; 224a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman host->offset += size; 225a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman host->remain -= size; 22614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 227a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (size) { 228a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman *buffer = data & 0xFF; 229a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman buffer++; 230a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data >>= 8; 231a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman size--; 232a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 233d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 234a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->remain == 0) { 235a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (sdhci_next_sg(host) == 0) { 236a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(blksize != 0); 237a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman return; 238a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 2392a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host); 240d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 241a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 242a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 244a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_write_block_pio(struct sdhci_host *host) 245a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 246a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int blksize, chunk_remain; 247a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 data; 248a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman char *buffer; 249a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman int bytes, size; 250d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 251a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO writing\n"); 252a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 253a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize = host->data->blksz; 254a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = 4; 255a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data = 0; 256d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 257a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman bytes = 0; 2582a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host) + host->offset; 259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 260a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (blksize) { 26114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov size = min(host->remain, chunk_remain); 262a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 263a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain -= size; 264a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman blksize -= size; 265d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset += size; 266d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain -= size; 26714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 268a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (size) { 269a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data >>= 8; 270a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman data |= (u32)*buffer << 24; 271a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman buffer++; 272a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman size--; 273a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 274a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 275a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (chunk_remain == 0) { 276a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman writel(data, host->ioaddr + SDHCI_BUFFER); 277a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman chunk_remain = min(blksize, 4); 278a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 279d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 280d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->remain == 0) { 281d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (sdhci_next_sg(host) == 0) { 282a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(blksize != 0); 283d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 284d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 2852a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman buffer = sdhci_sg_to_buffer(host); 286d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 287d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 288a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman} 289a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 290a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_transfer_pio(struct sdhci_host *host) 291a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{ 292a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman u32 mask; 293a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 294a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman BUG_ON(!host->data); 295a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 29614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 297a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman return; 298a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 299a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 300a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_DATA_AVAILABLE; 301a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 302a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman mask = SDHCI_SPACE_AVAILABLE; 303a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman 304a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 305a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (host->data->flags & MMC_DATA_READ) 306a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_read_block_pio(host); 307a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman else 308a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman sdhci_write_block_pio(host); 309d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 31014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 311a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman break; 312a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman } 313d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 314a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman DBG("PIO transfer complete.\n"); 315d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 317ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossmanstatic u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) 318d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 3191c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman u8 count; 3201c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman unsigned target_timeout, current_timeout; 321d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 322ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman /* 323ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * If the host controller provides us with an incorrect timeout 324ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * value, just skip the check and use 0xE. The hardware may take 325ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * longer to time out, but that's much better than having a too-short 326ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman * timeout value. 327ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman */ 328ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)) 329ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return 0xE; 330e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 3311c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* timeout in us */ 3321c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman target_timeout = data->timeout_ns / 1000 + 3331c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman data->timeout_clks / host->clock; 334d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 3351c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman /* 3361c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * Figure out needed cycles. 3371c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * We do this in steps in order to fit inside a 32 bit int. 3381c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * The first step is the minimum timeout, which will have a 3391c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * minimum resolution of 6 bits: 3401c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) 2^13*1000 > 2^22, 3411c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (2) host->timeout_clk < 2^16 3421c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * => 3431c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman * (1) / (2) > 2^6 3441c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman */ 3451c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0; 3461c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout = (1 << 13) * 1000 / host->timeout_clk; 3471c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman while (current_timeout < target_timeout) { 3481c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count++; 3491c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman current_timeout <<= 1; 3501c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) 3511c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman break; 3521c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 3531c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 3541c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (count >= 0xF) { 3551c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_WARNING "%s: Too large timeout requested!\n", 3561c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman mmc_hostname(host->mmc)); 3571c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman count = 0xE; 3581c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 3591c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman 360ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return count; 361ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman} 362ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 363ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) 364ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman{ 365ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman u8 count; 366ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 367ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman WARN_ON(host->data); 368ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 369ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman if (data == NULL) 370ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman return; 371ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 372ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman /* Sanity checks */ 373ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blksz * data->blocks > 524288); 374ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blksz > host->mmc->max_blk_size); 375ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman BUG_ON(data->blocks > 65535); 376ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 377ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman host->data = data; 378ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman host->data_early = 0; 379ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman 380ee53ab5d73998e502801c024a08de2c39a92c52aPierre Ossman count = sdhci_calc_timeout(host, data); 3811c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); 382d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 383c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_USE_DMA) 384c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags |= SDHCI_REQ_USE_DMA; 385c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 386c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && 387b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && 388c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman ((data->blksz * data->blocks) & 0x3))) { 389c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman DBG("Reverting to PIO because of transfer size (%d)\n", 390c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman data->blksz * data->blocks); 391c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 392c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 393c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 394c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman /* 395c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * The assumption here being that alignment is the same after 396c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman * translation to device address space. 397c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman */ 398c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && 399b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && 400c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman (data->sg->offset & 0x3))) { 401c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman DBG("Reverting to PIO because of bad alignment\n"); 402c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman host->flags &= ~SDHCI_REQ_USE_DMA; 403c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman } 404c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman 405c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 406d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int count; 407d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 408b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 409b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman (data->flags & MMC_DATA_READ) ? 410b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman DMA_FROM_DEVICE : DMA_TO_DEVICE); 411b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman WARN_ON(count != 1); 412d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 413b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman writel(sg_dma_address(data->sg), 414b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->ioaddr + SDHCI_DMA_ADDRESS); 415d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 416d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cur_sg = data->sg; 417d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->num_sg = data->sg_len; 418d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 419d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->offset = 0; 420d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->remain = host->cur_sg->length; 421d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 422c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 423bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman /* We do not handle DMA boundaries, so set it to max (512 KiB) */ 424bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman writew(SDHCI_MAKE_BLKSZ(7, data->blksz), 425bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman host->ioaddr + SDHCI_BLOCK_SIZE); 426c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT); 427c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman} 428c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 429c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossmanstatic void sdhci_set_transfer_mode(struct sdhci_host *host, 430c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman struct mmc_data *data) 431c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman{ 432c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman u16 mode; 433c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 434c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data == NULL) 435c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman return; 436c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 437e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman WARN_ON(!host->data); 438e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 439c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode = SDHCI_TRNS_BLK_CNT_EN; 440c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->blocks > 1) 441c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_MULTI; 442c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman if (data->flags & MMC_DATA_READ) 443c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_READ; 444c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) 445c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman mode |= SDHCI_TRNS_DMA; 446c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 447c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); 448d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 449d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 450d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *host) 451d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 452d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_data *data; 453d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 454d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(!host->data); 455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 456d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman data = host->data; 457d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 458d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 459c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990Pierre Ossman if (host->flags & SDHCI_REQ_USE_DMA) { 460b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 461b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman (data->flags & MMC_DATA_READ) ? 462b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman DMA_FROM_DEVICE : DMA_TO_DEVICE); 463d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 464d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 465d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 466c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * The specification states that the block count register must 467c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * be updated, but it does not specify at what point in the 468c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * data flow. That makes the register entirely useless to read 469c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * back so we have to assume that nothing made it to the card 470c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman * in the event of an error. 471d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 472c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman if (data->error) 473c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman data->bytes_xfered = 0; 474d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 475c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman data->bytes_xfered = data->blksz * data->blocks; 476d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 477d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (data->stop) { 478d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 479d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 480d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 481d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 48217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data->error) { 483d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 484d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 485d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 486d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 487d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, data->stop); 488d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 489d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 490d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 491d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 492d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) 493d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 494d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int flags; 495fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman u32 mask; 4967cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 497d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 498d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->cmd); 499d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 500d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 5017cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 502fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 503fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask = SDHCI_CMD_INHIBIT; 504fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) 505fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask |= SDHCI_DATA_INHIBIT; 506fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 507fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman /* We shouldn't wait for data inihibit for stop commands, even 508fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman though they might use busy signaling */ 509fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman if (host->mrq->data && (cmd == host->mrq->data->stop)) 510fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman mask &= ~SDHCI_DATA_INHIBIT; 511fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman 512fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { 5137cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Controller never released " 515acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "inhibit bit(s).\n", mmc_hostname(host->mmc)); 516d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 51717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EIO; 518d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 519d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 520d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 5217cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 5227cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 5237cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 524d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 525d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mod_timer(&host->timer, jiffies + 10 * HZ); 526d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 527d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = cmd; 528d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 529d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_prepare_data(host, cmd->data); 530d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 531d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); 532d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 533c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman sdhci_set_transfer_mode(host, cmd->data); 534c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman 535d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { 536acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unsupported response type!\n", 537d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 53817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EINVAL; 539d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 540d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 541d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 542d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 543d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(cmd->flags & MMC_RSP_PRESENT)) 544d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_NONE; 545d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_136) 546d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_LONG; 547d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else if (cmd->flags & MMC_RSP_BUSY) 548d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT_BUSY; 549d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 550d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags = SDHCI_CMD_RESP_SHORT; 551d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 552d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_CRC) 553d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_CRC; 554d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->flags & MMC_RSP_OPCODE) 555d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_INDEX; 556d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (cmd->data) 557d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman flags |= SDHCI_CMD_DATA; 558d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 559fb61e2895170920564410baadf71c5b3561dbf42Pierre Ossman writew(SDHCI_MAKE_CMD(cmd->opcode, flags), 560d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_COMMAND); 561d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 562d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 563d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *host) 564d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 565d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int i; 566d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 567d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(host->cmd == NULL); 568d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 569d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_PRESENT) { 570d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd->flags & MMC_RSP_136) { 571d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* CRC is stripped so we need to do some shifting. */ 572d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (i = 0;i < 4;i++) { 573d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] = readl(host->ioaddr + 574d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4) << 8; 575d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (i != 3) 576d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[i] |= 577d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman readb(host->ioaddr + 578d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman SDHCI_RESPONSE + (3-i)*4-1); 579d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 581d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE); 582d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 583d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 584d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 58517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = 0; 586d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 587e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->data && host->data_early) 588e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 589e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman 590e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (!host->cmd->data) 591d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 592d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 593d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 594d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 595d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 596d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 597d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int div; 599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u16 clk; 6007cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman unsigned long timeout; 601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == host->clock) 603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 604d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 605d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); 606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 607d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (clock == 0) 608d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 609d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 610d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman for (div = 1;div < 256;div *= 2) { 611d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if ((host->max_clk / div) <= clock) 612d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman break; 613d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 614d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman div >>= 1; 615d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 616d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk = div << SDHCI_DIVIDER_SHIFT; 617d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_INT_EN; 618d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 619d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 620d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* Wait max 10 ms */ 6217cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout = 10; 6227cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL)) 6237cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman & SDHCI_CLOCK_INT_STABLE)) { 6247cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman if (timeout == 0) { 625acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Internal clock never " 626acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "stabilised.\n", mmc_hostname(host->mmc)); 627d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 628d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 629d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 6307cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman timeout--; 6317cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman mdelay(1); 6327cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman } 633d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 634d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman clk |= SDHCI_CLOCK_CARD_EN; 635d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); 636d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 637d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 638d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->clock = clock; 639d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 640d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 641146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanstatic void sdhci_set_power(struct sdhci_host *host, unsigned short power) 642146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman{ 643146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman u8 pwr; 644146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 645146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (host->power == power) 646146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman return; 647146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 6489e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt if (power == (unsigned short)-1) { 6499e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 650146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman goto out; 6519e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt } 6529e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt 6539e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt /* 6549e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * Spec says that we should clear the power reg before setting 6559e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt * a new value. Some controllers don't seem to like this though. 6569e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt */ 657b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) 6589e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); 659146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 660146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr = SDHCI_POWER_ON; 661146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 6624be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale switch (1 << power) { 66355556da01284af8c2174b786b3eca8e11301b656Philip Langdale case MMC_VDD_165_195: 664146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_180; 665146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 6664be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_29_30: 6674be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_30_31: 668146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_300; 669146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 6704be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_32_33: 6714be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale case MMC_VDD_33_34: 672146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman pwr |= SDHCI_POWER_330; 673146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman break; 674146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman default: 675146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman BUG(); 676146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 677146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 678e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon /* 679e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon * At least the CaFe chip gets confused if we set the voltage 680e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon * and set turn on power at the same time, so set the voltage first. 681e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon */ 682b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)) 683e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon writeb(pwr & ~SDHCI_POWER_ON, 684e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon host->ioaddr + SDHCI_POWER_CONTROL); 685e08c1694d9e2138204f2b79b73f0f159074ce2f5Andres Salomon 686146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); 687146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 688146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanout: 689146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman host->power = power; 690146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman} 691146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 692d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 693d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 694d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * MMC callbacks * 695d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 696d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 697d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 698d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 699d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 700d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 701d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 702d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 703d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 704d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 706d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 707d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman WARN_ON(host->mrq != NULL); 708d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 7092f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 710d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_activate_led(host); 7112f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 712d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 713d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = mrq; 714d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 7151e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) 7161e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman || (host->flags & SDHCI_DEVICE_DEAD)) { 71717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 718d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 719d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else 720d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_send_command(host, mrq->cmd); 721d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 7225f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 723d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 724d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 725d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 726d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 727d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 728d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 729d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 730d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u8 ctrl; 731d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 732d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 733d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 734d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 735d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 7361e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 7371e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman goto out; 7381e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 739d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 740d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Reset the chip on each power off. 741d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Should clear out any weird states. 742d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 743d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) { 744d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE); 745d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 746d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 747d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 748d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_set_clock(host, ios->clock); 749d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 750d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->power_mode == MMC_POWER_OFF) 751146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, -1); 752d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 753146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman sdhci_set_power(host, ios->vdd); 754d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 755d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); 756cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 757d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ios->bus_width == MMC_BUS_WIDTH_4) 758d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl |= SDHCI_CTRL_4BITBUS; 759d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 760d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman ctrl &= ~SDHCI_CTRL_4BITBUS; 761cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 762cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (ios->timing == MMC_TIMING_SD_HS) 763cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl |= SDHCI_CTRL_HISPD; 764cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman else 765cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ctrl &= ~SDHCI_CTRL_HISPD; 766cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 767d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 768d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 769b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo /* 770b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * Some (ENE) controllers go apeshit on some ios operation, 771b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * signalling timeout and CRC errors even on CMD0. Resetting 772b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo * it on each ios seems to solve the problem. 773b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo */ 774b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) 775b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 776b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo 7771e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanout: 7785f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 779d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 780d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 781d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 782d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_get_ro(struct mmc_host *mmc) 783d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 784d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 785d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 786d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman int present; 787d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 788d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 789d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 790d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 791d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 7921e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 7931e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman present = 0; 7941e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman else 7951e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman present = readl(host->ioaddr + SDHCI_PRESENT_STATE); 796d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 797d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 798d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 799d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return !(present & SDHCI_WRITE_PROTECT); 800d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 801d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 802f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossmanstatic void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) 803f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman{ 804f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman struct sdhci_host *host; 805f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman unsigned long flags; 806f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman u32 ier; 807f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 808f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman host = mmc_priv(mmc); 809f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 810f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_lock_irqsave(&host->lock, flags); 811f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 8121e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->flags & SDHCI_DEVICE_DEAD) 8131e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman goto out; 8141e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 815f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier = readl(host->ioaddr + SDHCI_INT_ENABLE); 816f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 817f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier &= ~SDHCI_INT_CARD_INT; 818f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (enable) 819f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman ier |= SDHCI_INT_CARD_INT; 820f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 821f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_INT_ENABLE); 822f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); 823f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 8241e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanout: 825f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmiowb(); 826f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 827f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 828f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman} 829f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 830ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops sdhci_ops = { 831d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .request = sdhci_request, 832d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .set_ios = sdhci_set_ios, 833d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman .get_ro = sdhci_get_ro, 834f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman .enable_sdio_irq = sdhci_enable_sdio_irq, 835d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}; 836d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 837d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 838d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 839d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Tasklets * 840d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 841d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 842d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 843d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_card(unsigned long param) 844d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 845d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 846d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 847d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 848d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 849d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 850d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 851d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 852d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { 853d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 854d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Card removed during transfer!\n", 855d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 856d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_ERR "%s: Resetting controller.\n", 857d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 858d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 859d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 860d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 861d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 86217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 863d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 864d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 865d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 866d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 867d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 868d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 869d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_detect_change(host->mmc, msecs_to_jiffies(500)); 870d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 871d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 872d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_finish(unsigned long param) 873d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 874d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 875d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 876d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_request *mrq; 877d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 878d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)param; 879d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 880d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 881d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 882d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer(&host->timer); 883d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 884d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mrq = host->mrq; 885d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 886d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 887d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * The controller needs a reset of internal state machines 888d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * upon error conditions. 889d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 8901e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!(host->flags & SDHCI_DEVICE_DEAD) && 8911e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->cmd->error || 8921e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->data && (mrq->data->error || 8931e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (mrq->data->stop && mrq->data->stop->error))) || 8941e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { 895645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 896645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Some controllers need this kick or reset won't work here */ 897b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { 898645289dca5021224279e67b4655796cafdfdad00Pierre Ossman unsigned int clock; 899645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 900645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* This is to force an update */ 901645289dca5021224279e67b4655796cafdfdad00Pierre Ossman clock = host->clock; 902645289dca5021224279e67b4655796cafdfdad00Pierre Ossman host->clock = 0; 903645289dca5021224279e67b4655796cafdfdad00Pierre Ossman sdhci_set_clock(host, clock); 904645289dca5021224279e67b4655796cafdfdad00Pierre Ossman } 905645289dca5021224279e67b4655796cafdfdad00Pierre Ossman 906645289dca5021224279e67b4655796cafdfdad00Pierre Ossman /* Spec says we should do both at the same time, but Ricoh 907645289dca5021224279e67b4655796cafdfdad00Pierre Ossman controllers do not like that. */ 908d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_CMD); 909d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_reset(host, SDHCI_RESET_DATA); 910d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 911d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 912d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mrq = NULL; 913d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->cmd = NULL; 914d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->data = NULL; 915d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 9162f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifndef CONFIG_LEDS_CLASS 917d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_deactivate_led(host); 9182f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 919d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 9205f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 921d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 922d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 923d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_request_done(host->mmc, mrq); 924d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 925d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 926d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_timeout_timer(unsigned long data) 927d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 928d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 929d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman unsigned long flags; 930d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 931d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = (struct sdhci_host*)data; 932d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 933d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_irqsave(&host->lock, flags); 934d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 935d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->mrq) { 936acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Timeout waiting for hardware " 937acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman "interrupt.\n", mmc_hostname(host->mmc)); 938d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 939d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 940d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->data) { 94117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 942d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 943d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } else { 944d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->cmd) 94517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 946d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 94717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ETIMEDOUT; 948d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 949d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 950d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 951d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 952d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 9535f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 954d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 955d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 956d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 957d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 958d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 959d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Interrupt handling * 960d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 961d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 962d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 963d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) 964d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 965d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 966d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 967d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->cmd) { 968b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got command interrupt 0x%08x even " 969b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no command operation was in progress.\n", 970b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 971d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 972d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 973d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 974d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 97543b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman if (intmask & SDHCI_INT_TIMEOUT) 97617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -ETIMEDOUT; 97717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | 97817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman SDHCI_INT_INDEX)) 97917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->cmd->error = -EILSEQ; 98043b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman 98117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->cmd->error) 982d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->finish_tasklet); 98343b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman else if (intmask & SDHCI_INT_RESPONSE) 98443b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman sdhci_finish_command(host); 985d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 986d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 987d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_data_irq(struct sdhci_host *host, u32 intmask) 988d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 989d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman BUG_ON(intmask == 0); 990d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 991d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!host->data) { 992d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 993d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * A data end interrupt is sent together with the response 994d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * for the stop command. 995d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 996d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_END) 997d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 998d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 999b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman printk(KERN_ERR "%s: Got data interrupt 0x%08x even " 1000b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman "though no data operation was in progress.\n", 1001b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman mmc_hostname(host->mmc), (unsigned)intmask); 1002d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1003d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1004d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return; 1005d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1006d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1007d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_TIMEOUT) 100817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -ETIMEDOUT; 100917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) 101017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->data->error = -EILSEQ; 1011d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 101217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->data->error) 1013d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_finish_data(host); 1014d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else { 1015a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) 1016d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_transfer_pio(host); 1017d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10186ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman /* 10196ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * We currently don't do anything fancy with DMA 10206ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * boundaries, but as we can't disable the feature 10216ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman * we need to at least restart the transfer. 10226ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman */ 10236ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman if (intmask & SDHCI_INT_DMA_END) 10246ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), 10256ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman host->ioaddr + SDHCI_DMA_ADDRESS); 10266ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman 1027e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (intmask & SDHCI_INT_DATA_END) { 1028e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman if (host->cmd) { 1029e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman /* 1030e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * Data managed to finish before the 1031e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * command completed. Make sure we do 1032e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman * things in the proper order. 1033e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman */ 1034e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman host->data_early = 1; 1035e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } else { 1036e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman sdhci_finish_data(host); 1037e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1038e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman } 1039d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1040d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1041d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10427d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sdhci_irq(int irq, void *dev_id) 1043d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1044d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman irqreturn_t result; 1045d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host* host = dev_id; 1046d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman u32 intmask; 1047f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman int cardint = 0; 1048d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1049d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock(&host->lock); 1050d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1051d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask = readl(host->ioaddr + SDHCI_INT_STATUS); 1052d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 105362df67a523acd7a22d936bf946b1889dbd60ca98Mark Lord if (!intmask || intmask == 0xffffffff) { 1054d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_NONE; 1055d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman goto out; 1056d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1057d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1058b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman DBG("*** %s got interrupt: 0x%08x\n", 1059b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(host->mmc), intmask); 1060d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10613192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { 10623192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), 10633192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 1064d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_schedule(&host->card_tasklet); 10653192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1066d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10673192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); 1068d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10693192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask & SDHCI_INT_CMD_MASK) { 1070d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_CMD_MASK, 1071d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 10723192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); 1073d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1074d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1075d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_DATA_MASK) { 1076d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask & SDHCI_INT_DATA_MASK, 1077d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->ioaddr + SDHCI_INT_STATUS); 10783192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); 1079d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1080d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1081d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); 1082d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1083964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman intmask &= ~SDHCI_INT_ERROR; 1084964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman 1085d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (intmask & SDHCI_INT_BUS_POWER) { 10863192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman printk(KERN_ERR "%s: Card is consuming too much power!\n", 1087d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_hostname(host->mmc)); 10883192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS); 1089d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1090d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 10919d26a5d3f2b9c4fe4b2ba491683c6989ecd6ae04Rolf Eike Beer intmask &= ~SDHCI_INT_BUS_POWER; 10923192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman 1093f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (intmask & SDHCI_INT_CARD_INT) 1094f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman cardint = 1; 1095f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1096f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman intmask &= ~SDHCI_INT_CARD_INT; 1097f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 10983192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman if (intmask) { 1099acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", 11003192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman mmc_hostname(host->mmc), intmask); 1101d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1102d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1103d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman writel(intmask, host->ioaddr + SDHCI_INT_STATUS); 11043192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman } 1105d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1106d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman result = IRQ_HANDLED; 1107d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 11085f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 1109d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout: 1110d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_unlock(&host->lock); 1111d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1112f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman /* 1113f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman * We have to delay this as it calls back into the driver. 1114f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman */ 1115f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman if (cardint) 1116f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman mmc_signal_sdio_irq(host->mmc); 1117f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman 1118d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return result; 1119d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1120d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1121d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1122d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1123d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Suspend/resume * 1124d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1125d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1126d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1127d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_PM 1128d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1129b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) 1130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1131b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1132a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1133b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = mmc_suspend_host(host->mmc, state); 1134b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (ret) 1135b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ret; 1136a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman 1137b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman free_irq(host->irq, host); 1138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1142b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_suspend_host); 1143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1144b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_resume_host(struct sdhci_host *host) 1145b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 1146b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1148b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->flags & SDHCI_USE_DMA) { 1149b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma) 1150b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->ops->enable_dma(host); 1151b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman } 1152d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1153b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 1154b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(host->mmc), host); 1155df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman if (ret) 1156df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman return ret; 1157d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1158b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman sdhci_init(host); 1159b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmiowb(); 1160b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman 1161b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = mmc_resume_host(host->mmc); 1162b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (ret) 1163b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ret; 1164d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1165d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1166d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1167d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1168b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_resume_host); 1169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif /* CONFIG_PM */ 1171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1172d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1174b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman * Device allocation/registration * 1175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1178b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanstruct sdhci_host *sdhci_alloc_host(struct device *dev, 1179b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman size_t priv_size) 1180d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1181d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct mmc_host *mmc; 1182d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman struct sdhci_host *host; 1183d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1184b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman WARN_ON(dev == NULL); 1185d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1186b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); 1187d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (!mmc) 1188b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return ERR_PTR(-ENOMEM); 1189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1190d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host = mmc_priv(mmc); 1191d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->mmc = mmc; 1192d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1193b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return host; 1194b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman} 11958a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman 1196b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_alloc_host); 1197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1198b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanint sdhci_add_host(struct sdhci_host *host) 1199b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 1200b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman struct mmc_host *mmc; 1201b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman unsigned int caps; 1202b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman unsigned int version; 1203b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman int ret; 1204d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1205b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman WARN_ON(host == NULL); 1206b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host == NULL) 1207b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -EINVAL; 1208d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1209b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc = host->mmc; 1210d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1211b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (debug_quirks) 1212b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->quirks = debug_quirks; 1213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1214d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1215d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman 12164a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version = readw(host->ioaddr + SDHCI_HOST_VERSION); 12174a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; 1218c6573c94670882079174e2ea0da4abf1a0da51fePierre Ossman if (version > 1) { 12194a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman printk(KERN_ERR "%s: Unknown controller version (%d). " 1220b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "You may experience problems.\n", mmc_hostname(mmc), 12214a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman version); 12224a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman } 12234a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman 1224d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman caps = readl(host->ioaddr + SDHCI_CAPABILITIES); 1225d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1226b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->quirks & SDHCI_QUIRK_FORCE_DMA) 122798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman host->flags |= SDHCI_USE_DMA; 12286743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else if (!(caps & SDHCI_CAN_DO_DMA)) 12296743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman DBG("Controller doesn't have DMA capability\n"); 12306743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman else 1231d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->flags |= SDHCI_USE_DMA; 1232d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1233b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) && 12347c168e3db7d900008ee304574057e0dc1a8505afFeng Tang (host->flags & SDHCI_USE_DMA)) { 1235cee687ce4ab1197e20d4dacc09df01531362fdbdRolf Eike Beer DBG("Disabling DMA as it is marked broken\n"); 12367c168e3db7d900008ee304574057e0dc1a8505afFeng Tang host->flags &= ~SDHCI_USE_DMA; 12377c168e3db7d900008ee304574057e0dc1a8505afFeng Tang } 12387c168e3db7d900008ee304574057e0dc1a8505afFeng Tang 1239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) { 1240b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma) { 1241b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (host->ops->enable_dma(host)) { 1242b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman printk(KERN_WARNING "%s: No suitable DMA " 1243b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman "available. Falling back to PIO.\n", 1244b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(mmc)); 1245b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman host->flags &= ~SDHCI_USE_DMA; 1246b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman } 1247d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1248d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman } 1249d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1250b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman /* XXX: Hack to get MMC layer to avoid highmem */ 1251b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman if (!(host->flags & SDHCI_USE_DMA)) 1252b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_dev(host->mmc)->dma_mask = 0; 1253d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12548ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman host->max_clk = 12558ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; 12568ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman if (host->max_clk == 0) { 12578ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify base clock " 1258b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 1259b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 12608ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman } 1261d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman host->max_clk *= 1000000; 1262d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 12631c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk = 12641c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; 12651c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (host->timeout_clk == 0) { 12661c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " 1267b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "frequency.\n", mmc_hostname(mmc)); 1268b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 12691c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman } 12701c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman if (caps & SDHCI_TIMEOUT_CLK_UNIT) 12711c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman host->timeout_clk *= 1000; 1272d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1273d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1274d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Set host parameters. 1275d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1276d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->ops = &sdhci_ops; 1277d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_min = host->max_clk / 256; 1278d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->f_max = host->max_clk; 1279c9b74c5b8fb807187f6b1db09012828fcd2d7e73Pierre Ossman mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 1280d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1281cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman if (caps & SDHCI_CAN_DO_HISPD) 1282cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman mmc->caps |= MMC_CAP_SD_HIGHSPEED; 1283cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 1284146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail = 0; 1285146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (caps & SDHCI_CAN_VDD_330) 1286146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; 1287c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_300) 1288146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; 1289c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman if (caps & SDHCI_CAN_VDD_180) 129055556da01284af8c2174b786b3eca8e11301b656Philip Langdale mmc->ocr_avail |= MMC_VDD_165_195; 1291146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1292146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman if (mmc->ocr_avail == 0) { 1293146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman printk(KERN_ERR "%s: Hardware doesn't report any " 1294b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "support voltages.\n", mmc_hostname(mmc)); 1295b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return -ENODEV; 1296146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman } 1297146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman 1298d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman spin_lock_init(&host->lock); 1299d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1300d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1301d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Maximum number of segments. Hardware cannot do scatter lists. 1302d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1303d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (host->flags & SDHCI_USE_DMA) 1304d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_hw_segs = 1; 1305d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman else 1306d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_hw_segs = 16; 1307d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc->max_phys_segs = 16; 1308d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1309d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1310bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman * Maximum number of sectors in one transfer. Limited by DMA boundary 131155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * size (512KiB). 1312d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 131355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 524288; 1314d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1315d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Maximum segment size. Could be one segment with the maximum number 131755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * of bytes. 1318d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 131955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_seg_size = mmc->max_req_size; 1320d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1321d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman /* 1322fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Maximum block size. This varies from controller to controller and 1323fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * is specified in the capabilities register. 1324fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 1325fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; 1326fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman if (mmc->max_blk_size >= 3) { 1327b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman printk(KERN_WARNING "%s: Invalid maximum block size, " 1328b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman "assuming 512 bytes\n", mmc_hostname(mmc)); 132903f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512; 133003f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel } else 133103f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel mmc->max_blk_size = 512 << mmc->max_blk_size; 1332fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 1333fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 133455db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Maximum block count. 133555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 133655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = 65535; 133755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 133855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 1339d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Init tasklets. 1340d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */ 1341d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->card_tasklet, 1342d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_card, (unsigned long)host); 1343d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_init(&host->finish_tasklet, 1344d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_tasklet_finish, (unsigned long)host); 1345d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1346e4cad1b5a4851c90c1bcf460062074a2fa10815bAl Viro setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); 1347d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1348dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 1349b69c9058907642f8e1b32076906755c6623ea060Pierre Ossman mmc_hostname(mmc), host); 1350d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman if (ret) 13518ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman goto untasklet; 1352d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1353d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_init(host); 1354d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1355d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_MMC_DEBUG 1356d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman sdhci_dumpregs(host); 1357d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif 1358d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13592f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 13602f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.name = mmc_hostname(mmc); 13612f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness = LED_OFF; 13622f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.default_trigger = mmc_hostname(mmc); 13632f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman host->led.brightness_set = sdhci_led_control; 13642f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 1365b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman ret = led_classdev_register(mmc_dev(mmc), &host->led); 13662f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman if (ret) 13672f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman goto reset; 13682f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 13692f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 13705f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman mmiowb(); 13715f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman 1372d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman mmc_add_host(mmc); 1373d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1374b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n", 1375b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id, 1376d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); 1377d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1378d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return 0; 1379d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13802f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 13812f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossmanreset: 13822f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 13832f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman free_irq(host->irq, host); 13842f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 13858ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanuntasklet: 1386d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1387d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 1388d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1389d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman return ret; 1390d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1391d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1392b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_add_host); 1393d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 13941e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossmanvoid sdhci_remove_host(struct sdhci_host *host, int dead) 1395b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman{ 13961e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman unsigned long flags; 13971e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 13981e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (dead) { 13991e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman spin_lock_irqsave(&host->lock, flags); 14001e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 14011e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman host->flags |= SDHCI_DEVICE_DEAD; 14021e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 14031e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (host->mrq) { 14041e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman printk(KERN_ERR "%s: Controller removed during " 14051e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman " transfer!\n", mmc_hostname(host->mmc)); 14061e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 14071e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 14081e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman tasklet_schedule(&host->finish_tasklet); 14091e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman } 14101e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 14111e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 14121e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman } 14131e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman 1414b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_remove_host(host->mmc); 1415d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 14162f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#ifdef CONFIG_LEDS_CLASS 14172f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman led_classdev_unregister(&host->led); 14182f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman#endif 14192f730fec83be76f1b3b8f0066b3447f55c50d7a0Pierre Ossman 14201e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman if (!dead) 14211e72859e3ae16346d4007024b20d2d4ef387dcc3Pierre Ossman sdhci_reset(host, SDHCI_RESET_ALL); 1422d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1423d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman free_irq(host->irq, host); 1424d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1425d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman del_timer_sync(&host->timer); 1426d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1427d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->card_tasklet); 1428d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman tasklet_kill(&host->finish_tasklet); 1429d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1430d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1431b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_remove_host); 1432d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1433b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossmanvoid sdhci_free_host(struct sdhci_host *host) 1434d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1435b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman mmc_free_host(host->mmc); 1436d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1437d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1438b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanEXPORT_SYMBOL_GPL(sdhci_free_host); 1439d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1440d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\ 1441d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1442d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Driver init/exit * 1443d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * * 1444d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/ 1445d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1446d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __init sdhci_drv_init(void) 1447d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1448d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME 144952fbf9c976b36654e08e94c3107ddbaac7e2da33Pierre Ossman ": Secure Digital Host Controller Interface driver\n"); 1450d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); 1451d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1452b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre Ossman return 0; 1453d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1454d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __exit sdhci_drv_exit(void) 1456d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{ 1457d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman} 1458d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1459d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_init(sdhci_drv_init); 1460d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_exit(sdhci_drv_exit); 1461d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman 1462df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanmodule_param(debug_quirks, uint, 0444); 14636743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1464d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); 1465b8c86fc5d8deaa5a6dc49c2c1ed144e6838bf0f3Pierre OssmanMODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); 1466d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_LICENSE("GPL"); 14676743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman 1468df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre OssmanMODULE_PARM_DESC(debug_quirks, "Force certain quirks."); 1469