diff options
| -rw-r--r-- | drivers/mmc/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/mmc/at91_mci.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/au1xmmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/imxmmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 294 | ||||
| -rw-r--r-- | drivers/mmc/mmc_block.c | 15 | ||||
| -rw-r--r-- | drivers/mmc/mmc_queue.c | 63 | ||||
| -rw-r--r-- | drivers/mmc/mmc_queue.h | 3 | ||||
| -rw-r--r-- | drivers/mmc/mmci.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/omap.c | 272 | ||||
| -rw-r--r-- | drivers/mmc/omap.h | 55 | ||||
| -rw-r--r-- | drivers/mmc/pxamci.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/sdhci.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/sdhci.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/wbsd.c | 2 | ||||
| -rw-r--r-- | include/linux/mmc/card.h | 13 | ||||
| -rw-r--r-- | include/linux/mmc/protocol.h | 74 | 
17 files changed, 593 insertions, 229 deletions
| diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ea41852ec8cd..f4f8ccaf5455 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -40,7 +40,7 @@ config MMC_ARMMMCI  	  If unsure, say N.  config MMC_PXA -	tristate "Intel PXA255 Multimedia Card Interface support" +	tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"  	depends on ARCH_PXA && MMC  	help  	  This selects the Intel(R) PXA(R) Multimedia card Interface. diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 494b23fb0a01..6495cd8a9306 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -793,7 +793,7 @@ int at91_mci_get_ro(struct mmc_host *mmc)  	return read_only;  } -static struct mmc_host_ops at91_mci_ops = { +static const struct mmc_host_ops at91_mci_ops = {  	.request	= at91_mci_request,  	.set_ios	= at91_mci_set_ios,  	.get_ro		= at91_mci_get_ro, diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 53ffcbb14a97..447fba5825fd 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -875,7 +875,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)  	host->rx_chan = rxchan;  } -struct mmc_host_ops au1xmmc_ops = { +struct const mmc_host_ops au1xmmc_ops = {  	.request	= au1xmmc_request,  	.set_ios	= au1xmmc_set_ios,  }; diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 659d4a822cc5..06e7fcd19221 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -877,7 +877,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	}  } -static struct mmc_host_ops imxmci_ops = { +static const struct mmc_host_ops imxmci_ops = {  	.request	= imxmci_request,  	.set_ios	= imxmci_set_ios,  }; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc54406e5..9d190022a490 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -4,6 +4,7 @@   *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.   *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.   *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -396,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)  		return err;  	/* -	 * Default bus width is 1 bit. -	 */ -	host->ios.bus_width = MMC_BUS_WIDTH_1; - -	/* -	 * We can only change the bus width of the selected -	 * card so therefore we have to put the handling +	 * We can only change the bus width of SD cards when +	 * they are selected so we have to put the handling  	 * here. +	 * +	 * The card is in 1 bit mode by default so +	 * we only need to change if it supports the +	 * wider version.  	 */ -	if (host->caps & MMC_CAP_4_BIT_DATA) { +	if (mmc_card_sd(card) && +		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { +  		/* -		 * The card is in 1 bit mode by default so -		 * we only need to change if it supports the -		 * wider version. -		 */ -		if (mmc_card_sd(card) && -			(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { +		* Default bus width is 1 bit. +		*/ +		host->ios.bus_width = MMC_BUS_WIDTH_1; + +		if (host->caps & MMC_CAP_4_BIT_DATA) {  			struct mmc_command cmd;  			cmd.opcode = SD_APP_SET_BUS_WIDTH;  			cmd.arg = SD_BUS_WIDTH_4; @@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mmc_host *host)  static inline void mmc_delay(unsigned int ms)  { -	if (ms < HZ / 1000) { -		yield(); +	if (ms < 1000 / HZ) { +		cond_resched();  		mdelay(ms);  	} else { -		msleep_interruptible (ms); +		msleep(ms);  	}  } @@ -953,6 +954,137 @@ static void mmc_read_csds(struct mmc_host *host)  	}  } +static void mmc_process_ext_csds(struct mmc_host *host) +{ +	int err; +	struct mmc_card *card; + +	struct mmc_request mrq; +	struct mmc_command cmd; +	struct mmc_data data; + +	struct scatterlist sg; + +	/* +	 * As the ext_csd is so large and mostly unused, we don't store the +	 * raw block in mmc_card. +	 */ +	u8 *ext_csd; +	ext_csd = kmalloc(512, GFP_KERNEL); +	if (!ext_csd) { +		printk("%s: could not allocate a buffer to receive the ext_csd." +		       "mmc v4 cards will be treated as v3.\n", +			mmc_hostname(host)); +		return; +	} + +	list_for_each_entry(card, &host->cards, node) { +		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) +			continue; +		if (mmc_card_sd(card)) +			continue; +		if (card->csd.mmca_vsn < CSD_SPEC_VER_4) +			continue; + +		err = mmc_select_card(host, card); +		if (err != MMC_ERR_NONE) { +			mmc_card_set_dead(card); +			continue; +		} + +		memset(&cmd, 0, sizeof(struct mmc_command)); + +		cmd.opcode = MMC_SEND_EXT_CSD; +		cmd.arg = 0; +		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + +		memset(&data, 0, sizeof(struct mmc_data)); + +		mmc_set_data_timeout(&data, card, 0); + +		data.blksz = 512; +		data.blocks = 1; +		data.flags = MMC_DATA_READ; +		data.sg = &sg; +		data.sg_len = 1; + +		memset(&mrq, 0, sizeof(struct mmc_request)); + +		mrq.cmd = &cmd; +		mrq.data = &data; + +		sg_init_one(&sg, ext_csd, 512); + +		mmc_wait_for_req(host, &mrq); + +		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { +			mmc_card_set_dead(card); +			continue; +		} + +		switch (ext_csd[EXT_CSD_CARD_TYPE]) { +		case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: +			card->ext_csd.hs_max_dtr = 52000000; +			break; +		case EXT_CSD_CARD_TYPE_26: +			card->ext_csd.hs_max_dtr = 26000000; +			break; +		default: +			/* MMC v4 spec says this cannot happen */ +			printk("%s: card is mmc v4 but doesn't support " +			       "any high-speed modes.\n", +				mmc_hostname(card->host)); +			mmc_card_set_bad(card); +			continue; +		} + +		/* Activate highspeed support. */ +		cmd.opcode = MMC_SWITCH; +		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +			  (EXT_CSD_HS_TIMING << 16) | +			  (1 << 8) | +			  EXT_CSD_CMD_SET_NORMAL; +		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + +		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); +		if (err != MMC_ERR_NONE) { +			printk("%s: failed to switch card to mmc v4 " +			       "high-speed mode.\n", +			       mmc_hostname(card->host)); +			continue; +		} + +		mmc_card_set_highspeed(card); + +		/* Check for host support for wide-bus modes. */ +		if (!(host->caps & MMC_CAP_4_BIT_DATA)) { +			continue; +		} + +		/* Activate 4-bit support. */ +		cmd.opcode = MMC_SWITCH; +		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +			  (EXT_CSD_BUS_WIDTH << 16) | +			  (EXT_CSD_BUS_WIDTH_4 << 8) | +			  EXT_CSD_CMD_SET_NORMAL; +		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + +		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); +		if (err != MMC_ERR_NONE) { +			printk("%s: failed to switch card to " +			       "mmc v4 4-bit bus mode.\n", +			       mmc_hostname(card->host)); +			continue; +		} + +		host->ios.bus_width = MMC_BUS_WIDTH_4; +	} + +	kfree(ext_csd); + +	mmc_deselect_cards(host); +} +  static void mmc_read_scrs(struct mmc_host *host)  {  	int err; @@ -1025,14 +1157,133 @@ static void mmc_read_scrs(struct mmc_host *host)  	mmc_deselect_cards(host);  } +static void mmc_read_switch_caps(struct mmc_host *host) +{ +	int err; +	struct mmc_card *card; +	struct mmc_request mrq; +	struct mmc_command cmd; +	struct mmc_data data; +	unsigned char *status; +	struct scatterlist sg; + +	status = kmalloc(64, GFP_KERNEL); +	if (!status) { +		printk(KERN_WARNING "%s: Unable to allocate buffer for " +			"reading switch capabilities.\n", +			mmc_hostname(host)); +		return; +	} + +	list_for_each_entry(card, &host->cards, node) { +		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) +			continue; +		if (!mmc_card_sd(card)) +			continue; +		if (card->scr.sda_vsn < SCR_SPEC_VER_1) +			continue; + +		err = mmc_select_card(host, card); +		if (err != MMC_ERR_NONE) { +			mmc_card_set_dead(card); +			continue; +		} + +		memset(&cmd, 0, sizeof(struct mmc_command)); + +		cmd.opcode = SD_SWITCH; +		cmd.arg = 0x00FFFFF1; +		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + +		memset(&data, 0, sizeof(struct mmc_data)); + +		mmc_set_data_timeout(&data, card, 0); + +		data.blksz = 64; +		data.blocks = 1; +		data.flags = MMC_DATA_READ; +		data.sg = &sg; +		data.sg_len = 1; + +		memset(&mrq, 0, sizeof(struct mmc_request)); + +		mrq.cmd = &cmd; +		mrq.data = &data; + +		sg_init_one(&sg, status, 64); + +		mmc_wait_for_req(host, &mrq); + +		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { +			mmc_card_set_dead(card); +			continue; +		} + +		if (status[13] & 0x02) +			card->sw_caps.hs_max_dtr = 50000000; + +		memset(&cmd, 0, sizeof(struct mmc_command)); + +		cmd.opcode = SD_SWITCH; +		cmd.arg = 0x80FFFFF1; +		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + +		memset(&data, 0, sizeof(struct mmc_data)); + +		mmc_set_data_timeout(&data, card, 0); + +		data.blksz = 64; +		data.blocks = 1; +		data.flags = MMC_DATA_READ; +		data.sg = &sg; +		data.sg_len = 1; + +		memset(&mrq, 0, sizeof(struct mmc_request)); + +		mrq.cmd = &cmd; +		mrq.data = &data; + +		sg_init_one(&sg, status, 64); + +		mmc_wait_for_req(host, &mrq); + +		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { +			mmc_card_set_dead(card); +			continue; +		} + +		if ((status[16] & 0xF) != 1) { +			printk(KERN_WARNING "%s: Problem switching card " +				"into high-speed mode!\n", +				mmc_hostname(host)); +			continue; +		} + +		mmc_card_set_highspeed(card); +	} + +	kfree(status); + +	mmc_deselect_cards(host); +} +  static unsigned int mmc_calculate_clock(struct mmc_host *host)  {  	struct mmc_card *card;  	unsigned int max_dtr = host->f_max;  	list_for_each_entry(card, &host->cards, node) -		if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) -			max_dtr = card->csd.max_dtr; +		if (!mmc_card_dead(card)) { +			if (mmc_card_highspeed(card) && mmc_card_sd(card)) { +				if (max_dtr > card->sw_caps.hs_max_dtr) +					max_dtr = card->sw_caps.hs_max_dtr; +			} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { +				if (max_dtr > card->ext_csd.hs_max_dtr) +					max_dtr = card->ext_csd.hs_max_dtr; +			} else if (max_dtr > card->csd.max_dtr) { +				max_dtr = card->csd.max_dtr; +			} +		}  	pr_debug("%s: selected %d.%03dMHz transfer rate\n",  		 mmc_hostname(host), @@ -1150,8 +1401,11 @@ static void mmc_setup(struct mmc_host *host)  	mmc_read_csds(host); -	if (host->mode == MMC_MODE_SD) +	if (host->mode == MMC_MODE_SD) {  		mmc_read_scrs(host); +		mmc_read_switch_caps(host); +	} else +		mmc_process_ext_csds(host);  } diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index f9027c8db792..87713572293f 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -83,7 +83,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)  	md->usage--;  	if (md->usage == 0) {  		put_disk(md->disk); -		mmc_cleanup_queue(&md->queue);  		kfree(md);  	}  	mutex_unlock(&open_lock); @@ -225,10 +224,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  	struct mmc_blk_data *md = mq->data;  	struct mmc_card *card = md->queue.card;  	struct mmc_blk_request brq; -	int ret; +	int ret = 1;  	if (mmc_card_claim_host(card)) -		goto cmd_err; +		goto flush_queue;  	do {  		struct mmc_command cmd; @@ -345,8 +344,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  	return 1;   cmd_err: -	ret = 1; -   	/*   	 * If this is an SD card and we're writing, we can first   	 * mark the known good sectors as ok. @@ -380,6 +377,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  	mmc_card_release_host(card); +flush_queue:  	spin_lock_irq(&md->lock);  	while (ret) {  		ret = end_that_request_chunk(req, 0, @@ -553,12 +551,11 @@ static void mmc_blk_remove(struct mmc_card *card)  	if (md) {  		int devidx; +		/* Stop new requests from getting into the queue */  		del_gendisk(md->disk); -		/* -		 * I think this is needed. -		 */ -		md->disk->queue = NULL; +		/* Then flush out any already in there */ +		mmc_cleanup_queue(&md->queue);  		devidx = md->disk->first_minor >> MMC_SHIFT;  		__clear_bit(devidx, dev_use); diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 61a1de85cb23..a17423a4ed8f 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -10,13 +10,13 @@   */  #include <linux/module.h>  #include <linux/blkdev.h> +#include <linux/kthread.h>  #include <linux/mmc/card.h>  #include <linux/mmc/host.h>  #include "mmc_queue.h" -#define MMC_QUEUE_EXIT		(1 << 0) -#define MMC_QUEUE_SUSPENDED	(1 << 1) +#define MMC_QUEUE_SUSPENDED	(1 << 0)  /*   * Prepare a MMC request.  Essentially, this means passing the @@ -59,7 +59,6 @@ static int mmc_queue_thread(void *d)  {  	struct mmc_queue *mq = d;  	struct request_queue *q = mq->queue; -	DECLARE_WAITQUEUE(wait, current);  	/*  	 * Set iothread to ensure that we aren't put to sleep by @@ -67,12 +66,7 @@ static int mmc_queue_thread(void *d)  	 */  	current->flags |= PF_MEMALLOC|PF_NOFREEZE; -	daemonize("mmcqd"); - -	complete(&mq->thread_complete); -  	down(&mq->thread_sem); -	add_wait_queue(&mq->thread_wq, &wait);  	do {  		struct request *req = NULL; @@ -84,7 +78,7 @@ static int mmc_queue_thread(void *d)  		spin_unlock_irq(q->queue_lock);  		if (!req) { -			if (mq->flags & MMC_QUEUE_EXIT) +			if (kthread_should_stop())  				break;  			up(&mq->thread_sem);  			schedule(); @@ -95,10 +89,8 @@ static int mmc_queue_thread(void *d)  		mq->issue_fn(mq, req);  	} while (1); -	remove_wait_queue(&mq->thread_wq, &wait);  	up(&mq->thread_sem); -	complete_and_exit(&mq->thread_complete, 0);  	return 0;  } @@ -111,9 +103,22 @@ static int mmc_queue_thread(void *d)  static void mmc_request(request_queue_t *q)  {  	struct mmc_queue *mq = q->queuedata; +	struct request *req; +	int ret; + +	if (!mq) { +		printk(KERN_ERR "MMC: killing requests for dead queue\n"); +		while ((req = elv_next_request(q)) != NULL) { +			do { +				ret = end_that_request_chunk(req, 0, +					req->current_nr_sectors << 9); +			} while (ret); +		} +		return; +	}  	if (!mq->req) -		wake_up(&mq->thread_wq); +		wake_up_process(mq->thread);  }  /** @@ -152,36 +157,40 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock  			 GFP_KERNEL);  	if (!mq->sg) {  		ret = -ENOMEM; -		goto cleanup; +		goto cleanup_queue;  	} -	init_completion(&mq->thread_complete); -	init_waitqueue_head(&mq->thread_wq);  	init_MUTEX(&mq->thread_sem); -	ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); -	if (ret >= 0) { -		wait_for_completion(&mq->thread_complete); -		init_completion(&mq->thread_complete); -		ret = 0; -		goto out; +	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); +	if (IS_ERR(mq->thread)) { +		ret = PTR_ERR(mq->thread); +		goto free_sg;  	} - cleanup: +	return 0; + + free_sg:  	kfree(mq->sg);  	mq->sg = NULL; - + cleanup_queue:  	blk_cleanup_queue(mq->queue); - out:  	return ret;  }  EXPORT_SYMBOL(mmc_init_queue);  void mmc_cleanup_queue(struct mmc_queue *mq)  { -	mq->flags |= MMC_QUEUE_EXIT; -	wake_up(&mq->thread_wq); -	wait_for_completion(&mq->thread_complete); +	request_queue_t *q = mq->queue; +	unsigned long flags; + +	/* Mark that we should start throwing out stragglers */ +	spin_lock_irqsave(q->queue_lock, flags); +	q->queuedata = NULL; +	spin_unlock_irqrestore(q->queue_lock, flags); + +	/* Then terminate our worker thread */ +	kthread_stop(mq->thread);  	kfree(mq->sg);  	mq->sg = NULL; diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/mmc_queue.h index 7182d2f69b4e..c9f139e764f6 100644 --- a/drivers/mmc/mmc_queue.h +++ b/drivers/mmc/mmc_queue.h @@ -6,8 +6,7 @@ struct task_struct;  struct mmc_queue {  	struct mmc_card		*card; -	struct completion	thread_complete; -	wait_queue_head_t	thread_wq; +	struct task_struct	*thread;  	struct semaphore	thread_sem;  	unsigned int		flags;  	struct request		*req; diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 828503c4ee62..e9b80e920266 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -443,7 +443,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	}  } -static struct mmc_host_ops mmci_ops = { +static const struct mmc_host_ops mmci_ops = {  	.request	= mmci_request,  	.set_ios	= mmci_set_ios,  }; diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index d593ef342e75..435d331e772a 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -38,7 +38,57 @@  #include <asm/arch/fpga.h>  #include <asm/arch/tps65010.h> -#include "omap.h" +#define	OMAP_MMC_REG_CMD	0x00 +#define	OMAP_MMC_REG_ARGL	0x04 +#define	OMAP_MMC_REG_ARGH	0x08 +#define	OMAP_MMC_REG_CON	0x0c +#define	OMAP_MMC_REG_STAT	0x10 +#define	OMAP_MMC_REG_IE		0x14 +#define	OMAP_MMC_REG_CTO	0x18 +#define	OMAP_MMC_REG_DTO	0x1c +#define	OMAP_MMC_REG_DATA	0x20 +#define	OMAP_MMC_REG_BLEN	0x24 +#define	OMAP_MMC_REG_NBLK	0x28 +#define	OMAP_MMC_REG_BUF	0x2c +#define OMAP_MMC_REG_SDIO	0x34 +#define	OMAP_MMC_REG_REV	0x3c +#define	OMAP_MMC_REG_RSP0	0x40 +#define	OMAP_MMC_REG_RSP1	0x44 +#define	OMAP_MMC_REG_RSP2	0x48 +#define	OMAP_MMC_REG_RSP3	0x4c +#define	OMAP_MMC_REG_RSP4	0x50 +#define	OMAP_MMC_REG_RSP5	0x54 +#define	OMAP_MMC_REG_RSP6	0x58 +#define	OMAP_MMC_REG_RSP7	0x5c +#define	OMAP_MMC_REG_IOSR	0x60 +#define	OMAP_MMC_REG_SYSC	0x64 +#define	OMAP_MMC_REG_SYSS	0x68 + +#define	OMAP_MMC_STAT_CARD_ERR		(1 << 14) +#define	OMAP_MMC_STAT_CARD_IRQ		(1 << 13) +#define	OMAP_MMC_STAT_OCR_BUSY		(1 << 12) +#define	OMAP_MMC_STAT_A_EMPTY		(1 << 11) +#define	OMAP_MMC_STAT_A_FULL		(1 << 10) +#define	OMAP_MMC_STAT_CMD_CRC		(1 <<  8) +#define	OMAP_MMC_STAT_CMD_TOUT		(1 <<  7) +#define	OMAP_MMC_STAT_DATA_CRC		(1 <<  6) +#define	OMAP_MMC_STAT_DATA_TOUT		(1 <<  5) +#define	OMAP_MMC_STAT_END_BUSY		(1 <<  4) +#define	OMAP_MMC_STAT_END_OF_DATA	(1 <<  3) +#define	OMAP_MMC_STAT_CARD_BUSY		(1 <<  2) +#define	OMAP_MMC_STAT_END_OF_CMD	(1 <<  0) + +#define OMAP_MMC_READ(host, reg)	__raw_readw((host)->virt_base + OMAP_MMC_REG_##reg) +#define OMAP_MMC_WRITE(host, reg, val)	__raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg) + +/* + * Command types + */ +#define OMAP_MMC_CMDTYPE_BC	0 +#define OMAP_MMC_CMDTYPE_BCR	1 +#define OMAP_MMC_CMDTYPE_AC	2 +#define OMAP_MMC_CMDTYPE_ADTC	3 +  #define DRIVER_NAME "mmci-omap"  #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) @@ -60,8 +110,9 @@ struct mmc_omap_host {  	unsigned char		id; /* 16xx chips have 2 MMC blocks */  	struct clk *		iclk;  	struct clk *		fclk; -	struct resource		*res; -	void __iomem		*base; +	struct resource		*mem_res; +	void __iomem		*virt_base; +	unsigned int		phys_base;  	int			irq;  	unsigned char		bus_mode;  	unsigned char		hw_bus_mode; @@ -191,16 +242,16 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)  	clk_enable(host->fclk); -	OMAP_MMC_WRITE(host->base, CTO, 200); -	OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff); -	OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16); -	OMAP_MMC_WRITE(host->base, IE, +	OMAP_MMC_WRITE(host, CTO, 200); +	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); +	OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); +	OMAP_MMC_WRITE(host, IE,  		       OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |  		       OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |  		       OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |  		       OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |  		       OMAP_MMC_STAT_END_OF_DATA); -	OMAP_MMC_WRITE(host->base, CMD, cmdreg); +	OMAP_MMC_WRITE(host, CMD, cmdreg);  }  static void @@ -296,22 +347,22 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)  		if (cmd->flags & MMC_RSP_136) {  			/* response type 2 */  			cmd->resp[3] = -				OMAP_MMC_READ(host->base, RSP0) | -				(OMAP_MMC_READ(host->base, RSP1) << 16); +				OMAP_MMC_READ(host, RSP0) | +				(OMAP_MMC_READ(host, RSP1) << 16);  			cmd->resp[2] = -				OMAP_MMC_READ(host->base, RSP2) | -				(OMAP_MMC_READ(host->base, RSP3) << 16); +				OMAP_MMC_READ(host, RSP2) | +				(OMAP_MMC_READ(host, RSP3) << 16);  			cmd->resp[1] = -				OMAP_MMC_READ(host->base, RSP4) | -				(OMAP_MMC_READ(host->base, RSP5) << 16); +				OMAP_MMC_READ(host, RSP4) | +				(OMAP_MMC_READ(host, RSP5) << 16);  			cmd->resp[0] = -				OMAP_MMC_READ(host->base, RSP6) | -				(OMAP_MMC_READ(host->base, RSP7) << 16); +				OMAP_MMC_READ(host, RSP6) | +				(OMAP_MMC_READ(host, RSP7) << 16);  		} else {  			/* response types 1, 1b, 3, 4, 5, 6 */  			cmd->resp[0] = -				OMAP_MMC_READ(host->base, RSP6) | -				(OMAP_MMC_READ(host->base, RSP7) << 16); +				OMAP_MMC_READ(host, RSP6) | +				(OMAP_MMC_READ(host, RSP7) << 16);  		}  	} @@ -354,9 +405,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)  	host->data->bytes_xfered += n;  	if (write) { -		__raw_writesw(host->base + OMAP_MMC_REG_DATA, host->buffer, n); +		__raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);  	} else { -		__raw_readsw(host->base + OMAP_MMC_REG_DATA, host->buffer, n); +		__raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);  	}  } @@ -386,11 +437,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)  	int transfer_error;  	if (host->cmd == NULL && host->data == NULL) { -		status = OMAP_MMC_READ(host->base, STAT); +		status = OMAP_MMC_READ(host, STAT);  		dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);  		if (status != 0) { -			OMAP_MMC_WRITE(host->base, STAT, status); -			OMAP_MMC_WRITE(host->base, IE, 0); +			OMAP_MMC_WRITE(host, STAT, status); +			OMAP_MMC_WRITE(host, IE, 0);  		}  		return IRQ_HANDLED;  	} @@ -399,8 +450,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)  	end_transfer = 0;  	transfer_error = 0; -	while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) { -		OMAP_MMC_WRITE(host->base, STAT, status); +	while ((status = OMAP_MMC_READ(host, STAT)) != 0) { +		OMAP_MMC_WRITE(host, STAT, status);  #ifdef CONFIG_MMC_DEBUG  		dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",  			status, host->cmd != NULL ? host->cmd->opcode : -1); @@ -470,8 +521,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)  		if (status & OMAP_MMC_STAT_CARD_ERR) {  			if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) { -				u32 response = OMAP_MMC_READ(host->base, RSP6) -					| (OMAP_MMC_READ(host->base, RSP7) << 16); +				u32 response = OMAP_MMC_READ(host, RSP6) +					| (OMAP_MMC_READ(host, RSP7) << 16);  				/* STOP sometimes sets must-ignore bits */  				if (!(response & (R1_CC_ERROR  								| R1_ILLEGAL_COMMAND @@ -530,12 +581,6 @@ static void mmc_omap_switch_timer(unsigned long arg)  	schedule_work(&host->switch_work);  } -/* FIXME: Handle card insertion and removal properly. Maybe use a mask - * for MMC state? */ -static void mmc_omap_switch_callback(unsigned long data, u8 mmc_mask) -{ -} -  static void mmc_omap_switch_handler(void *data)  {  	struct mmc_omap_host *host = (struct mmc_omap_host *) data; @@ -581,7 +626,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)  	int dst_port = 0;  	int sync_dev = 0; -	data_addr = io_v2p((u32) host->base) + OMAP_MMC_REG_DATA; +	data_addr = host->phys_base + OMAP_MMC_REG_DATA;  	frame = data->blksz;  	count = sg_dma_len(sg); @@ -642,7 +687,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)  	/* Max limit for DMA frame count is 0xffff */  	BUG_ON(count > 0xffff); -	OMAP_MMC_WRITE(host->base, BUF, buf); +	OMAP_MMC_WRITE(host, BUF, buf);  	omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,  				     frame, count, OMAP_DMA_SYNC_FRAME,  				     sync_dev, 0); @@ -727,11 +772,11 @@ static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_reques  {  	u16 reg; -	reg = OMAP_MMC_READ(host->base, SDIO); +	reg = OMAP_MMC_READ(host, SDIO);  	reg &= ~(1 << 5); -	OMAP_MMC_WRITE(host->base, SDIO, reg); +	OMAP_MMC_WRITE(host, SDIO, reg);  	/* Set maximum timeout */ -	OMAP_MMC_WRITE(host->base, CTO, 0xff); +	OMAP_MMC_WRITE(host, CTO, 0xff);  }  static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req) @@ -745,14 +790,14 @@ static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_reque  	timeout = req->data->timeout_clks + req->data->timeout_ns / 500;  	/* Check if we need to use timeout multiplier register */ -	reg = OMAP_MMC_READ(host->base, SDIO); +	reg = OMAP_MMC_READ(host, SDIO);  	if (timeout > 0xffff) {  		reg |= (1 << 5);  		timeout /= 1024;  	} else  		reg &= ~(1 << 5); -	OMAP_MMC_WRITE(host->base, SDIO, reg); -	OMAP_MMC_WRITE(host->base, DTO, timeout); +	OMAP_MMC_WRITE(host, SDIO, reg); +	OMAP_MMC_WRITE(host, DTO, timeout);  }  static void @@ -764,19 +809,18 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)  	host->data = data;  	if (data == NULL) { -		OMAP_MMC_WRITE(host->base, BLEN, 0); -		OMAP_MMC_WRITE(host->base, NBLK, 0); -		OMAP_MMC_WRITE(host->base, BUF, 0); +		OMAP_MMC_WRITE(host, BLEN, 0); +		OMAP_MMC_WRITE(host, NBLK, 0); +		OMAP_MMC_WRITE(host, BUF, 0);  		host->dma_in_use = 0;  		set_cmd_timeout(host, req);  		return;  	} -  	block_size = data->blksz; -	OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1); -	OMAP_MMC_WRITE(host->base, BLEN, block_size - 1); +	OMAP_MMC_WRITE(host, NBLK, data->blocks - 1); +	OMAP_MMC_WRITE(host, BLEN, block_size - 1);  	set_data_timeout(host, req);  	/* cope with calling layer confusion; it issues "single @@ -818,7 +862,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)  	/* Revert to PIO? */  	if (!use_dma) { -		OMAP_MMC_WRITE(host->base, BUF, 0x1f1f); +		OMAP_MMC_WRITE(host, BUF, 0x1f1f);  		host->total_bytes_left = data->blocks * block_size;  		host->sg_len = sg_len;  		mmc_omap_sg_to_buf(host); @@ -844,7 +888,6 @@ static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)  static void innovator_fpga_socket_power(int on)  {  #if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX) -  	if (on) {  		fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),  		     OMAP1510_FPGA_POWER); @@ -870,8 +913,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)  			/* GPIO 4 of TPS65010 sends SD_EN signal */  			tps65010_set_gpio_out_value(GPIO4, HIGH);  		else if (cpu_is_omap24xx()) { -			u16 reg = OMAP_MMC_READ(host->base, CON); -			OMAP_MMC_WRITE(host->base, CON, reg | (1 << 11)); +			u16 reg = OMAP_MMC_READ(host, CON); +			OMAP_MMC_WRITE(host, CON, reg | (1 << 11));  		} else  			if (host->power_pin >= 0)  				omap_set_gpio_dataout(host->power_pin, 1); @@ -883,8 +926,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)  		else if (machine_is_omap_h3())  			tps65010_set_gpio_out_value(GPIO4, LOW);  		else if (cpu_is_omap24xx()) { -			u16 reg = OMAP_MMC_READ(host->base, CON); -			OMAP_MMC_WRITE(host->base, CON, reg & ~(1 << 11)); +			u16 reg = OMAP_MMC_READ(host, CON); +			OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));  		} else  			if (host->power_pin >= 0)  				omap_set_gpio_dataout(host->power_pin, 0); @@ -926,7 +969,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	case MMC_POWER_UP:  	case MMC_POWER_ON:  		mmc_omap_power(host, 1); -		dsor |= 1<<11; +		dsor |= 1 << 11;  		break;  	} @@ -940,14 +983,14 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	 * which results in the while loop below getting stuck.  	 * Writing to the CON register twice seems to do the trick. */  	for (i = 0; i < 2; i++) -		OMAP_MMC_WRITE(host->base, CON, dsor); +		OMAP_MMC_WRITE(host, CON, dsor);  	if (ios->power_mode == MMC_POWER_UP) {  		/* Send clock cycles, poll completion */ -		OMAP_MMC_WRITE(host->base, IE, 0); -		OMAP_MMC_WRITE(host->base, STAT, 0xffff); -		OMAP_MMC_WRITE(host->base, CMD, 1<<7); -		while (0 == (OMAP_MMC_READ(host->base, STAT) & 1)); -		OMAP_MMC_WRITE(host->base, STAT, 1); +		OMAP_MMC_WRITE(host, IE, 0); +		OMAP_MMC_WRITE(host, STAT, 0xffff); +		OMAP_MMC_WRITE(host, CMD, 1 << 7); +		while ((OMAP_MMC_READ(host, STAT) & 1) == 0); +		OMAP_MMC_WRITE(host, STAT, 1);  	}  	clk_disable(host->fclk);  } @@ -959,7 +1002,7 @@ static int mmc_omap_get_ro(struct mmc_host *mmc)  	return host->wp_pin && omap_get_gpio_datain(host->wp_pin);  } -static struct mmc_host_ops mmc_omap_ops = { +static const struct mmc_host_ops mmc_omap_ops = {  	.request	= mmc_omap_request,  	.set_ios	= mmc_omap_set_ios,  	.get_ro		= mmc_omap_get_ro, @@ -970,25 +1013,29 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  	struct omap_mmc_conf *minfo = pdev->dev.platform_data;  	struct mmc_host *mmc;  	struct mmc_omap_host *host = NULL; -	struct resource *r; +	struct resource *res;  	int ret = 0;  	int irq; -	 -	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + +	if (minfo == NULL) { +		dev_err(&pdev->dev, "platform data missing\n"); +		return -ENXIO; +	} + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	irq = platform_get_irq(pdev, 0); -	if (!r || irq < 0) +	if (res == NULL || irq < 0)  		return -ENXIO; -	r = request_mem_region(pdev->resource[0].start, -				pdev->resource[0].end - pdev->resource[0].start + 1, -			       pdev->name); -	if (!r) +	res = request_mem_region(res->start, res->end - res->start + 1, +			         pdev->name); +	if (res == NULL)  		return -EBUSY;  	mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev); -	if (!mmc) { +	if (mmc == NULL) {  		ret = -ENOMEM; -		goto out; +		goto err_free_mem_region;  	}  	host = mmc_priv(mmc); @@ -1000,13 +1047,13 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  	host->dma_timer.data = (unsigned long) host;  	host->id = pdev->id; -	host->res = r; +	host->mem_res = res;  	host->irq = irq;  	if (cpu_is_omap24xx()) {  		host->iclk = clk_get(&pdev->dev, "mmc_ick");  		if (IS_ERR(host->iclk)) -			goto out; +			goto err_free_mmc_host;  		clk_enable(host->iclk);  	} @@ -1017,7 +1064,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  	if (IS_ERR(host->fclk)) {  		ret = PTR_ERR(host->fclk); -		goto out; +		goto err_free_iclk;  	}  	/* REVISIT: @@ -1030,14 +1077,15 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  	host->use_dma = 1;  	host->dma_ch = -1; -	host->irq = pdev->resource[1].start; -	host->base = (void __iomem*)IO_ADDRESS(r->start); +	host->irq = irq; +	host->phys_base = host->mem_res->start; +	host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);  	mmc->ops = &mmc_omap_ops;  	mmc->f_min = 400000;  	mmc->f_max = 24000000; -	mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; -	mmc->caps = MMC_CAP_BYTEBLOCK; +	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; +	mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;  	if (minfo->wire4)  		 mmc->caps |= MMC_CAP_4_BIT_DATA; @@ -1055,20 +1103,18 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  		if ((ret = omap_request_gpio(host->power_pin)) != 0) {  			dev_err(mmc_dev(host->mmc),  				"Unable to get GPIO pin for MMC power\n"); -			goto out; +			goto err_free_fclk;  		}  		omap_set_gpio_direction(host->power_pin, 0);  	}  	ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);  	if (ret) -		goto out; +		goto err_free_power_gpio;  	host->dev = &pdev->dev;  	platform_set_drvdata(pdev, host); -	mmc_add_host(mmc); -  	if (host->switch_pin >= 0) {  		INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host);  		init_timer(&host->switch_timer); @@ -1106,10 +1152,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev)  			schedule_work(&host->switch_work);  	} -no_switch: +	mmc_add_host(mmc); +  	return 0; -out: +no_switch:  	/* FIXME: Free other resources too. */  	if (host) {  		if (host->iclk && !IS_ERR(host->iclk)) @@ -1118,6 +1165,20 @@ out:  			clk_put(host->fclk);  		mmc_free_host(host->mmc);  	} +err_free_power_gpio: +	if (host->power_pin >= 0) +		omap_free_gpio(host->power_pin); +err_free_fclk: +	clk_put(host->fclk); +err_free_iclk: +	if (host->iclk != NULL) { +		clk_disable(host->iclk); +		clk_put(host->iclk); +	} +err_free_mmc_host: +	mmc_free_host(host->mmc); +err_free_mem_region: +	release_mem_region(res->start, res->end - res->start + 1);  	return ret;  } @@ -1127,30 +1188,31 @@ static int mmc_omap_remove(struct platform_device *pdev)  	platform_set_drvdata(pdev, NULL); -	if (host) { -		mmc_remove_host(host->mmc); -		free_irq(host->irq, host); - -		if (host->power_pin >= 0) -			omap_free_gpio(host->power_pin); -		if (host->switch_pin >= 0) { -			device_remove_file(&pdev->dev, &dev_attr_enable_poll); -			device_remove_file(&pdev->dev, &dev_attr_cover_switch); -			free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); -			omap_free_gpio(host->switch_pin); -			host->switch_pin = -1; -			del_timer_sync(&host->switch_timer); -			flush_scheduled_work(); -		} -		if (host->iclk && !IS_ERR(host->iclk)) -			clk_put(host->iclk); -		if (host->fclk && !IS_ERR(host->fclk)) -			clk_put(host->fclk); -		mmc_free_host(host->mmc); +	BUG_ON(host == NULL); + +	mmc_remove_host(host->mmc); +	free_irq(host->irq, host); + +	if (host->power_pin >= 0) +		omap_free_gpio(host->power_pin); +	if (host->switch_pin >= 0) { +		device_remove_file(&pdev->dev, &dev_attr_enable_poll); +		device_remove_file(&pdev->dev, &dev_attr_cover_switch); +		free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); +		omap_free_gpio(host->switch_pin); +		host->switch_pin = -1; +		del_timer_sync(&host->switch_timer); +		flush_scheduled_work();  	} +	if (host->iclk && !IS_ERR(host->iclk)) +		clk_put(host->iclk); +	if (host->fclk && !IS_ERR(host->fclk)) +		clk_put(host->fclk);  	release_mem_region(pdev->resource[0].start, -			pdev->resource[0].end - pdev->resource[0].start + 1); +			   pdev->resource[0].end - pdev->resource[0].start + 1); + +	mmc_free_host(host->mmc);  	return 0;  } diff --git a/drivers/mmc/omap.h b/drivers/mmc/omap.h deleted file mode 100644 index c954d355a5e3..000000000000 --- a/drivers/mmc/omap.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef	DRIVERS_MEDIA_MMC_OMAP_H -#define	DRIVERS_MEDIA_MMC_OMAP_H - -#define	OMAP_MMC_REG_CMD	0x00 -#define	OMAP_MMC_REG_ARGL	0x04 -#define	OMAP_MMC_REG_ARGH	0x08 -#define	OMAP_MMC_REG_CON	0x0c -#define	OMAP_MMC_REG_STAT	0x10 -#define	OMAP_MMC_REG_IE		0x14 -#define	OMAP_MMC_REG_CTO	0x18 -#define	OMAP_MMC_REG_DTO	0x1c -#define	OMAP_MMC_REG_DATA	0x20 -#define	OMAP_MMC_REG_BLEN	0x24 -#define	OMAP_MMC_REG_NBLK	0x28 -#define	OMAP_MMC_REG_BUF	0x2c -#define OMAP_MMC_REG_SDIO	0x34 -#define	OMAP_MMC_REG_REV	0x3c -#define	OMAP_MMC_REG_RSP0	0x40 -#define	OMAP_MMC_REG_RSP1	0x44 -#define	OMAP_MMC_REG_RSP2	0x48 -#define	OMAP_MMC_REG_RSP3	0x4c -#define	OMAP_MMC_REG_RSP4	0x50 -#define	OMAP_MMC_REG_RSP5	0x54 -#define	OMAP_MMC_REG_RSP6	0x58 -#define	OMAP_MMC_REG_RSP7	0x5c -#define	OMAP_MMC_REG_IOSR	0x60 -#define	OMAP_MMC_REG_SYSC	0x64 -#define	OMAP_MMC_REG_SYSS	0x68 - -#define	OMAP_MMC_STAT_CARD_ERR		(1 << 14) -#define	OMAP_MMC_STAT_CARD_IRQ		(1 << 13) -#define	OMAP_MMC_STAT_OCR_BUSY		(1 << 12) -#define	OMAP_MMC_STAT_A_EMPTY		(1 << 11) -#define	OMAP_MMC_STAT_A_FULL		(1 << 10) -#define	OMAP_MMC_STAT_CMD_CRC		(1 <<  8) -#define	OMAP_MMC_STAT_CMD_TOUT		(1 <<  7) -#define	OMAP_MMC_STAT_DATA_CRC		(1 <<  6) -#define	OMAP_MMC_STAT_DATA_TOUT		(1 <<  5) -#define	OMAP_MMC_STAT_END_BUSY		(1 <<  4) -#define	OMAP_MMC_STAT_END_OF_DATA	(1 <<  3) -#define	OMAP_MMC_STAT_CARD_BUSY		(1 <<  2) -#define	OMAP_MMC_STAT_END_OF_CMD	(1 <<  0) - -#define OMAP_MMC_READ(base, reg)	__raw_readw((base) + OMAP_MMC_REG_##reg) -#define OMAP_MMC_WRITE(base, reg, val)	__raw_writew((val), (base) + OMAP_MMC_REG_##reg) - -/* - * Command types - */ -#define OMAP_MMC_CMDTYPE_BC	0 -#define OMAP_MMC_CMDTYPE_BCR	1 -#define OMAP_MMC_CMDTYPE_AC	2 -#define OMAP_MMC_CMDTYPE_ADTC	3 - -#endif diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index a526698b8c91..471e9f4e0530 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -393,7 +393,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		 host->clkrt, host->cmdat);  } -static struct mmc_host_ops pxamci_ops = { +static const struct mmc_host_ops pxamci_ops = {  	.request	= pxamci_request,  	.get_ro		= pxamci_get_ro,  	.set_ios	= pxamci_set_ios, diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 9a7d39b7cdbf..cd98117632d3 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -616,6 +616,7 @@ static void sdhci_finish_command(struct sdhci_host *host)  static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  {  	int div; +	u8 ctrl;  	u16 clk;  	unsigned long timeout; @@ -624,6 +625,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); +	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); +	if (clock > 25000000) +		ctrl |= SDHCI_CTRL_HISPD; +	else +		ctrl &= ~SDHCI_CTRL_HISPD; +	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); +  	if (clock == 0)  		goto out; @@ -784,7 +792,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)  	return !(present & SDHCI_WRITE_PROTECT);  } -static struct mmc_host_ops sdhci_ops = { +static const struct mmc_host_ops sdhci_ops = {  	.request	= sdhci_request,  	.set_ios	= sdhci_set_ios,  	.get_ro		= sdhci_get_ro, @@ -1291,6 +1299,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)  	else if (caps & SDHCI_CAN_VDD_180)  		mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; +	if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) { +		printk(KERN_ERR "%s: Controller reports > 25 MHz base clock," +			" but no high speed support.\n", +			host->slot_descr); +		mmc->f_max = 25000000; +	} +  	if (mmc->ocr_avail == 0) {  		printk(KERN_ERR "%s: Hardware doesn't report any "  			"support voltages.\n", host->slot_descr); diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h index 72a67937afe0..f9d1a0a6f03a 100644 --- a/drivers/mmc/sdhci.h +++ b/drivers/mmc/sdhci.h @@ -71,6 +71,7 @@  #define SDHCI_HOST_CONTROL 	0x28  #define  SDHCI_CTRL_LED		0x01  #define  SDHCI_CTRL_4BITBUS	0x02 +#define  SDHCI_CTRL_HISPD	0x04  #define SDHCI_POWER_CONTROL	0x29  #define  SDHCI_POWER_ON		0x01 @@ -138,6 +139,7 @@  #define  SDHCI_CLOCK_BASE_SHIFT	8  #define  SDHCI_MAX_BLOCK_MASK	0x00030000  #define  SDHCI_MAX_BLOCK_SHIFT  16 +#define  SDHCI_CAN_DO_HISPD	0x00200000  #define  SDHCI_CAN_DO_DMA	0x00400000  #define  SDHCI_CAN_VDD_330	0x01000000  #define  SDHCI_CAN_VDD_300	0x02000000 diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 682e62b0b09d..7a282672f8e9 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1021,7 +1021,7 @@ static int wbsd_get_ro(struct mmc_host *mmc)  	return csr & WBSD_WRPT;  } -static struct mmc_host_ops wbsd_ops = { +static const struct mmc_host_ops wbsd_ops = {  	.request	= wbsd_request,  	.set_ios	= wbsd_set_ios,  	.get_ro		= wbsd_get_ro, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 991a37382a22..d0e6a5497614 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -39,6 +39,10 @@ struct mmc_csd {  				write_misalign:1;  }; +struct mmc_ext_csd { +	unsigned int		hs_max_dtr; +}; +  struct sd_scr {  	unsigned char		sda_vsn;  	unsigned char		bus_widths; @@ -46,6 +50,10 @@ struct sd_scr {  #define SD_SCR_BUS_WIDTH_4	(1<<2)  }; +struct sd_switch_caps { +	unsigned int		hs_max_dtr; +}; +  struct mmc_host;  /* @@ -62,12 +70,15 @@ struct mmc_card {  #define MMC_STATE_BAD		(1<<2)		/* unrecognised device */  #define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */  #define MMC_STATE_READONLY	(1<<4)		/* card is read-only */ +#define MMC_STATE_HIGHSPEED	(1<<5)		/* card is in high speed mode */  	u32			raw_cid[4];	/* raw card CID */  	u32			raw_csd[4];	/* raw card CSD */  	u32			raw_scr[2];	/* raw card SCR */  	struct mmc_cid		cid;		/* card identification */  	struct mmc_csd		csd;		/* card specific */ +	struct mmc_ext_csd	ext_csd;	/* mmc v4 extended card specific */  	struct sd_scr		scr;		/* extra SD information */ +	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */  };  #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT) @@ -75,12 +86,14 @@ struct mmc_card {  #define mmc_card_bad(c)		((c)->state & MMC_STATE_BAD)  #define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY) +#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)  #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)  #define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)  #define mmc_card_set_bad(c)	((c)->state |= MMC_STATE_BAD)  #define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)  #define mmc_card_name(c)	((c)->cid.prod_name)  #define mmc_card_id(c)		((c)->dev.bus_id) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 08dec8d9e703..2dce60c43f4b 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -25,14 +25,16 @@  #ifndef MMC_MMC_PROTOCOL_H  #define MMC_MMC_PROTOCOL_H -/* Standard MMC commands (3.1)           type  argument     response */ +/* Standard MMC commands (4.1)           type  argument     response */     /* class 1 */  #define	MMC_GO_IDLE_STATE         0   /* bc                          */  #define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */  #define MMC_ALL_SEND_CID          2   /* bcr                     R2  */  #define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */  #define MMC_SET_DSR               4   /* bc   [31:16] RCA            */ +#define MMC_SWITCH                6   /* ac   [31:0] See below   R1b */  #define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */ +#define MMC_SEND_EXT_CSD          8   /* adtc                    R1  */  #define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */  #define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */  #define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */ @@ -80,6 +82,7 @@    /* class 8 */  /* This is basically the same command as for MMC with some quirks. */  #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */ +#define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */    /* Application commands */  #define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */ @@ -88,6 +91,30 @@  #define SD_APP_SEND_SCR          51   /* adtc                    R1  */  /* + * MMC_SWITCH argument format: + * + *	[31:26] Always 0 + *	[25:24] Access Mode + *	[23:16] Location of target Byte in EXT_CSD + *	[15:08] Value Byte + *	[07:03] Always 0 + *	[02:00] Command Set + */ + +/* + * SD_SWITCH argument format: + * + *      [31] Check (0) or switch (1) + *      [30:24] Reserved (0) + *      [23:20] Function group 6 + *      [19:16] Function group 5 + *      [15:12] Function group 4 + *      [11:8] Function group 3 + *      [7:4] Function group 2 + *      [3:0] Function group 1 + */ + +/*    MMC status in R1    Type    	e : error bit @@ -230,13 +257,54 @@ struct _mmc_csd {  #define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */  #define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */ -#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1       */ +#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD  3           /* Version is coded in CSD_STRUCTURE in EXT_CSD */  #define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */  #define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */  #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */ -#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4      4           /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH	183	/* R/W */ +#define EXT_CSD_HS_TIMING	185	/* R/W */ +#define EXT_CSD_CARD_TYPE	196	/* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL		(1<<0) +#define EXT_CSD_CMD_SET_SECURE		(1<<1) +#define EXT_CSD_CMD_SET_CPSECURE	(1<<2) + +#define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */ + +#define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */ + +/* + * MMC_SWITCH access modes + */ + +#define MMC_SWITCH_MODE_CMD_SET		0x00	/* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS	0x01	/* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS	0x02	/* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE	0x03	/* Set target to value */ + +/* + * SCR field definitions + */ +#define SCR_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1      1           /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2      2           /* Implements system specification 2.00 */  /*   * SD bus widths | 
