Commit cdb54fac authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc:
  mmc: correct request error handling
  mmc: Flush block queue when removing card
  mmc: sdhci high speed support
  mmc: Support for high speed SD cards
  mmc: Fix mmc_delay() function
  mmc: Add support for mmc v4 wide-bus modes
  [PATCH] mmc: Add support for mmc v4 high speed mode
  trivial change for mmc/Kconfig: MMC_PXA does not mean only PXA255
  Make general code cleanups
  Add MMC_CAP_{MULTIWRITE,BYTEBLOCK} flags
  Platform device error handling cleanup
  Move register definitions away from the header file
  Change OMAP_MMC_{READ,WRITE} macros to use the host pointer
  Replace base with virt_base and phys_base
  mmc: constify mmc_host_ops vectors
  mmc: remove kernel_thread()
parents 37043318 8b7feff8
...@@ -40,7 +40,7 @@ config MMC_ARMMMCI ...@@ -40,7 +40,7 @@ config MMC_ARMMMCI
If unsure, say N. If unsure, say N.
config MMC_PXA config MMC_PXA
tristate "Intel PXA255 Multimedia Card Interface support" tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
depends on ARCH_PXA && MMC depends on ARCH_PXA && MMC
help help
This selects the Intel(R) PXA(R) Multimedia card Interface. This selects the Intel(R) PXA(R) Multimedia card Interface.
......
...@@ -793,7 +793,7 @@ int at91_mci_get_ro(struct mmc_host *mmc) ...@@ -793,7 +793,7 @@ int at91_mci_get_ro(struct mmc_host *mmc)
return read_only; return read_only;
} }
static struct mmc_host_ops at91_mci_ops = { static const struct mmc_host_ops at91_mci_ops = {
.request = at91_mci_request, .request = at91_mci_request,
.set_ios = at91_mci_set_ios, .set_ios = at91_mci_set_ios,
.get_ro = at91_mci_get_ro, .get_ro = at91_mci_get_ro,
......
...@@ -875,7 +875,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host) ...@@ -875,7 +875,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
host->rx_chan = rxchan; host->rx_chan = rxchan;
} }
struct mmc_host_ops au1xmmc_ops = { struct const mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request, .request = au1xmmc_request,
.set_ios = au1xmmc_set_ios, .set_ios = au1xmmc_set_ios,
}; };
......
...@@ -877,7 +877,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -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, .request = imxmci_request,
.set_ios = imxmci_set_ios, .set_ios = imxmci_set_ios,
}; };
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* SD support Copyright (C) 2005 Pierre Ossman, 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 * 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 * 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) ...@@ -396,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
return err; return err;
/* /*
* Default bus width is 1 bit. * We can only change the bus width of SD cards when
*/ * they are selected so we have to put the handling
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
* here. * 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 * Default bus width is 1 bit.
* we only need to change if it supports the */
* wider version. host->ios.bus_width = MMC_BUS_WIDTH_1;
*/
if (mmc_card_sd(card) && if (host->caps & MMC_CAP_4_BIT_DATA) {
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
struct mmc_command cmd; struct mmc_command cmd;
cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.arg = SD_BUS_WIDTH_4; cmd.arg = SD_BUS_WIDTH_4;
...@@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mmc_host *host) ...@@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mmc_host *host)
static inline void mmc_delay(unsigned int ms) static inline void mmc_delay(unsigned int ms)
{ {
if (ms < HZ / 1000) { if (ms < 1000 / HZ) {
yield(); cond_resched();
mdelay(ms); mdelay(ms);
} else { } else {
msleep_interruptible (ms); msleep(ms);
} }
} }
...@@ -953,6 +954,137 @@ static void mmc_read_csds(struct mmc_host *host) ...@@ -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) static void mmc_read_scrs(struct mmc_host *host)
{ {
int err; int err;
...@@ -1025,14 +1157,133 @@ static void mmc_read_scrs(struct mmc_host *host) ...@@ -1025,14 +1157,133 @@ static void mmc_read_scrs(struct mmc_host *host)
mmc_deselect_cards(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) static unsigned int mmc_calculate_clock(struct mmc_host *host)
{ {
struct mmc_card *card; struct mmc_card *card;
unsigned int max_dtr = host->f_max; unsigned int max_dtr = host->f_max;
list_for_each_entry(card, &host->cards, node) list_for_each_entry(card, &host->cards, node)
if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) if (!mmc_card_dead(card)) {
max_dtr = card->csd.max_dtr; 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", pr_debug("%s: selected %d.%03dMHz transfer rate\n",
mmc_hostname(host), mmc_hostname(host),
...@@ -1150,8 +1401,11 @@ static void mmc_setup(struct mmc_host *host) ...@@ -1150,8 +1401,11 @@ static void mmc_setup(struct mmc_host *host)
mmc_read_csds(host); mmc_read_csds(host);
if (host->mode == MMC_MODE_SD) if (host->mode == MMC_MODE_SD) {
mmc_read_scrs(host); mmc_read_scrs(host);
mmc_read_switch_caps(host);
} else
mmc_process_ext_csds(host);
} }
......
...@@ -83,7 +83,6 @@ static void mmc_blk_put(struct mmc_blk_data *md) ...@@ -83,7 +83,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)
md->usage--; md->usage--;
if (md->usage == 0) { if (md->usage == 0) {
put_disk(md->disk); put_disk(md->disk);
mmc_cleanup_queue(&md->queue);
kfree(md); kfree(md);
} }
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
...@@ -225,10 +224,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -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_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card; struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq; struct mmc_blk_request brq;
int ret; int ret = 1;
if (mmc_card_claim_host(card)) if (mmc_card_claim_host(card))
goto cmd_err; goto flush_queue;
do { do {
struct mmc_command cmd; struct mmc_command cmd;
...@@ -345,8 +344,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -345,8 +344,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
return 1; return 1;
cmd_err: cmd_err:
ret = 1;
/* /*
* If this is an SD card and we're writing, we can first * If this is an SD card and we're writing, we can first
* mark the known good sectors as ok. * mark the known good sectors as ok.
...@@ -380,6 +377,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -380,6 +377,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
mmc_card_release_host(card); mmc_card_release_host(card);
flush_queue:
spin_lock_irq(&md->lock); spin_lock_irq(&md->lock);
while (ret) { while (ret) {
ret = end_that_request_chunk(req, 0, ret = end_that_request_chunk(req, 0,
...@@ -553,12 +551,11 @@ static void mmc_blk_remove(struct mmc_card *card) ...@@ -553,12 +551,11 @@ static void mmc_blk_remove(struct mmc_card *card)
if (md) { if (md) {
int devidx; int devidx;
/* Stop new requests from getting into the queue */
del_gendisk(md->disk); del_gendisk(md->disk);
/* /* Then flush out any already in there */
* I think this is needed. mmc_cleanup_queue(&md->queue);
*/
md->disk->queue = NULL;
devidx = md->disk->first_minor >> MMC_SHIFT; devidx = md->disk->first_minor >> MMC_SHIFT;
__clear_bit(devidx, dev_use); __clear_bit(devidx, dev_use);
......
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include "mmc_queue.h" #include "mmc_queue.h"
#define MMC_QUEUE_EXIT (1 << 0) #define MMC_QUEUE_SUSPENDED (1 << 0)
#define MMC_QUEUE_SUSPENDED (1 << 1)
/* /*
* Prepare a MMC request. Essentially, this means passing the * Prepare a MMC request. Essentially, this means passing the
...@@ -59,7 +59,6 @@ static int mmc_queue_thread(void *d) ...@@ -59,7 +59,6 @@ static int mmc_queue_thread(void *d)
{ {
struct mmc_queue *mq = d; struct mmc_queue *mq = d;
struct request_queue *q = mq->queue; struct request_queue *q = mq->queue;
DECLARE_WAITQUEUE(wait, current);
/* /*
* Set iothread to ensure that we aren't put to sleep by * Set iothread to ensure that we aren't put to sleep by
...@@ -67,12 +66,7 @@ static int mmc_queue_thread(void *d) ...@@ -67,12 +66,7 @@ static int mmc_queue_thread(void *d)
*/ */
current->flags |= PF_MEMALLOC|PF_NOFREEZE; current->flags |= PF_MEMALLOC|PF_NOFREEZE;
daemonize("mmcqd");
complete(&mq->thread_complete);
down(&mq->thread_sem); down(&mq->thread_sem);
add_wait_queue(&mq->thread_wq, &wait);
do { do {
struct request *req = NULL; struct request *req = NULL;
...@@ -84,7 +78,7 @@ static int mmc_queue_thread(void *d) ...@@ -84,7 +78,7 @@ static int mmc_queue_thread(void *d)
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
if (!req) { if (!req) {
if (mq->flags & MMC_QUEUE_EXIT) if (kthread_should_stop())
break; break;
up(&mq->thread_sem); up(&mq->thread_sem);
schedule(); schedule();
...@@ -95,10 +89,8 @@ static int mmc_queue_thread(void *d) ...@@ -95,10 +89,8 @@ static int mmc_queue_thread(void *d)
mq->issue_fn(mq, req); mq->issue_fn(mq, req);
} while (1); } while (1);
remove_wait_queue(&mq->thread_wq, &wait);
up(&mq->thread_sem); up(&mq->thread_sem);
complete_and_exit(&mq->thread_complete, 0);
return 0; return 0;
} }
...@@ -111,9 +103,22 @@ static int mmc_queue_thread(void *d) ...@@ -111,9 +103,22 @@ static int mmc_queue_thread(void *d)
static void mmc_request(request_queue_t *q) static void mmc_request(request_queue_t *q)
{ {
struct mmc_queue *mq = q->queuedata; 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) 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 ...@@ -152,36 +157,40 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
GFP_KERNEL); GFP_KERNEL);
if (!mq->sg) { if (!mq->sg) {
ret = -ENOMEM; ret = -ENOMEM;
goto cleanup; goto cleanup_queue;
} }
init_completion(&mq->thread_complete);
init_waitqueue_head(&mq->thread_wq);
init_MUTEX(&mq->thread_sem); init_MUTEX(&mq->thread_sem);
ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
if (ret >= 0) { if (IS_ERR(mq->thread)) {
wait_for_completion(&mq->thread_complete); ret = PTR_ERR(mq->thread);
init_completion(&mq->thread_complete); goto free_sg;
ret = 0;
goto out;
} }
cleanup: return 0;
free_sg:
kfree(mq->sg); kfree(mq->sg);
mq->sg = NULL; mq->sg = NULL;
cleanup_queue:
blk_cleanup_queue(mq->queue); blk_cleanup_queue(mq->queue);
out:
return ret; return ret;
} }
EXPORT_SYMBOL(mmc_init_queue); EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq) void mmc_cleanup_queue(struct mmc_queue *mq)
{ {
mq->flags |= MMC_QUEUE_EXIT; request_queue_t *q = mq->queue;
wake_up(&mq->thread_wq); unsigned long flags;
wait_for_completion(&mq->thread_complete);
/* 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); kfree(mq->sg);
mq->sg = NULL; mq->sg = NULL;
......
...@@ -6,8 +6,7 @@ struct task_struct; ...@@ -6,8 +6,7 @@ struct task_struct;
struct mmc_queue { struct mmc_queue {
struct mmc_card *card; struct mmc_card *card;
struct completion thread_complete; struct task_struct *thread;
wait_queue_head_t thread_wq;
struct semaphore thread_sem; struct semaphore thread_sem;
unsigned int flags; unsigned int flags;
struct request *req; struct request *req;
......
...@@ -443,7 +443,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -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, .request = mmci_request,
.set_ios = mmci_set_ios, .set_ios = mmci_set_ios,
}; };
......
...@@ -38,7 +38,57 @@ ...@@ -38,7 +38,57 @@
#include <asm/arch/fpga.h> #include <asm/arch/fpga.h>
#include <asm/arch/tps65010.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 DRIVER_NAME "mmci-omap"
#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
...@@ -60,8 +110,9 @@ struct mmc_omap_host { ...@@ -60,8 +110,9 @@ struct mmc_omap_host {
unsigned char id; /* 16xx chips have 2 MMC blocks */ unsigned char id; /* 16xx chips have 2 MMC blocks */
struct clk * iclk; struct clk * iclk;
struct clk * fclk; struct clk * fclk;
struct resource *res; struct resource *mem_res;
void __iomem *base; void __iomem *virt_base;
unsigned int phys_base;
int irq; int irq;
unsigned char bus_mode; unsigned char bus_mode;
unsigned char hw_bus_mode; unsigned char hw_bus_mode;
...@@ -191,16 +242,16 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) ...@@ -191,16 +242,16 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
clk_enable(host->fclk); clk_enable(host->fclk);
OMAP_MMC_WRITE(host->base, CTO, 200); OMAP_MMC_WRITE(host, CTO, 200);
OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16); OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
OMAP_MMC_WRITE(host->base, IE, OMAP_MMC_WRITE(host, IE,
OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL |
OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT |
OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_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_CMD | OMAP_MMC_STAT_CARD_ERR |
OMAP_MMC_STAT_END_OF_DATA); OMAP_MMC_STAT_END_OF_DATA);
OMAP_MMC_WRITE(host->base, CMD, cmdreg); OMAP_MMC_WRITE(host, CMD, cmdreg);
} }
static void static void
...@@ -296,22 +347,22 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) ...@@ -296,22 +347,22 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
if (cmd->flags & MMC_RSP_136) { if (cmd->flags & MMC_RSP_136) {
/* response type 2 */ /* response type 2 */
cmd->resp[3] = cmd->resp[3] =
OMAP_MMC_READ(host->base, RSP0) | OMAP_MMC_READ(host, RSP0) |
(OMAP_MMC_READ(host->base, RSP1) << 16); (OMAP_MMC_READ(host, RSP1) << 16);
cmd->resp[2] = cmd->resp[2] =
OMAP_MMC_READ(host->base, RSP2) | OMAP_MMC_READ(host, RSP2) |
(OMAP_MMC_READ(host->base, RSP3) << 16); (OMAP_MMC_READ(host, RSP3) << 16);
cmd->resp[1] = cmd->resp[1] =
OMAP_MMC_READ(host->base, RSP4) | OMAP_MMC_READ(host, RSP4) |
(OMAP_MMC_READ(host->base, RSP5) << 16); (OMAP_MMC_READ(host, RSP5) << 16);
cmd->resp[0] = cmd->resp[0] =
OMAP_MMC_READ(host->base, RSP6) | OMAP_MMC_READ(host, RSP6) |
(OMAP_MMC_READ(host->base, RSP7) << 16); (OMAP_MMC_READ(host, RSP7) << 16);
} else { } else {
/* response types 1, 1b, 3, 4, 5, 6 */ /* response types 1, 1b, 3, 4, 5, 6 */
cmd->resp[0] = cmd->resp[0] =
OMAP_MMC_READ(host->base, RSP6) | OMAP_MMC_READ(host, RSP6) |
(OMAP_MMC_READ(host->base, RSP7) << 16); (OMAP_MMC_READ(host, RSP7) << 16);
} }
} }
...@@ -354,9 +405,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write) ...@@ -354,9 +405,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
host->data->bytes_xfered += n; host->data->bytes_xfered += n;
if (write) { 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 { } 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) ...@@ -386,11 +437,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
int transfer_error; int transfer_error;
if (host->cmd == NULL && host->data == NULL) { 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); dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
if (status != 0) { if (status != 0) {
OMAP_MMC_WRITE(host->base, STAT, status); OMAP_MMC_WRITE(host, STAT, status);
OMAP_MMC_WRITE(host->base, IE, 0); OMAP_MMC_WRITE(host, IE, 0);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -399,8 +450,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -399,8 +450,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
end_transfer = 0; end_transfer = 0;
transfer_error = 0; transfer_error = 0;
while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) { while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
OMAP_MMC_WRITE(host->base, STAT, status); OMAP_MMC_WRITE(host, STAT, status);
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
status, host->cmd != NULL ? host->cmd->opcode : -1); status, host->cmd != NULL ? host->cmd->opcode : -1);
...@@ -470,8 +521,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -470,8 +521,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
if (status & OMAP_MMC_STAT_CARD_ERR) { if (status & OMAP_MMC_STAT_CARD_ERR) {
if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) { if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
u32 response = OMAP_MMC_READ(host->base, RSP6) u32 response = OMAP_MMC_READ(host, RSP6)
| (OMAP_MMC_READ(host->base, RSP7) << 16); | (OMAP_MMC_READ(host, RSP7) << 16);
/* STOP sometimes sets must-ignore bits */ /* STOP sometimes sets must-ignore bits */
if (!(response & (R1_CC_ERROR if (!(response & (R1_CC_ERROR
| R1_ILLEGAL_COMMAND | R1_ILLEGAL_COMMAND
...@@ -530,12 +581,6 @@ static void mmc_omap_switch_timer(unsigned long arg) ...@@ -530,12 +581,6 @@ static void mmc_omap_switch_timer(unsigned long arg)
schedule_work(&host->switch_work); 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) static void mmc_omap_switch_handler(void *data)
{ {
struct mmc_omap_host *host = (struct mmc_omap_host *) 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) ...@@ -581,7 +626,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
int dst_port = 0; int dst_port = 0;
int sync_dev = 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; frame = data->blksz;
count = sg_dma_len(sg); count = sg_dma_len(sg);
...@@ -642,7 +687,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) ...@@ -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 */ /* Max limit for DMA frame count is 0xffff */
BUG_ON(count > 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, omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
frame, count, OMAP_DMA_SYNC_FRAME, frame, count, OMAP_DMA_SYNC_FRAME,
sync_dev, 0); sync_dev, 0);
...@@ -727,11 +772,11 @@ static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_reques ...@@ -727,11 +772,11 @@ static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_reques
{ {
u16 reg; u16 reg;
reg = OMAP_MMC_READ(host->base, SDIO); reg = OMAP_MMC_READ(host, SDIO);
reg &= ~(1 << 5); reg &= ~(1 << 5);
OMAP_MMC_WRITE(host->base, SDIO, reg); OMAP_MMC_WRITE(host, SDIO, reg);
/* Set maximum timeout */ /* 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) 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 ...@@ -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; timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
/* Check if we need to use timeout multiplier register */ /* 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) { if (timeout > 0xffff) {
reg |= (1 << 5); reg |= (1 << 5);
timeout /= 1024; timeout /= 1024;
} else } else
reg &= ~(1 << 5); reg &= ~(1 << 5);
OMAP_MMC_WRITE(host->base, SDIO, reg); OMAP_MMC_WRITE(host, SDIO, reg);
OMAP_MMC_WRITE(host->base, DTO, timeout); OMAP_MMC_WRITE(host, DTO, timeout);
} }
static void static void
...@@ -764,19 +809,18 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) ...@@ -764,19 +809,18 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
host->data = data; host->data = data;
if (data == NULL) { if (data == NULL) {
OMAP_MMC_WRITE(host->base, BLEN, 0); OMAP_MMC_WRITE(host, BLEN, 0);
OMAP_MMC_WRITE(host->base, NBLK, 0); OMAP_MMC_WRITE(host, NBLK, 0);
OMAP_MMC_WRITE(host->base, BUF, 0); OMAP_MMC_WRITE(host, BUF, 0);
host->dma_in_use = 0; host->dma_in_use = 0;
set_cmd_timeout(host, req); set_cmd_timeout(host, req);
return; return;
} }
block_size = data->blksz; block_size = data->blksz;
OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1); OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
OMAP_MMC_WRITE(host->base, BLEN, block_size - 1); OMAP_MMC_WRITE(host, BLEN, block_size - 1);
set_data_timeout(host, req); set_data_timeout(host, req);
/* cope with calling layer confusion; it issues "single /* 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) ...@@ -818,7 +862,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
/* Revert to PIO? */ /* Revert to PIO? */
if (!use_dma) { 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->total_bytes_left = data->blocks * block_size;
host->sg_len = sg_len; host->sg_len = sg_len;
mmc_omap_sg_to_buf(host); mmc_omap_sg_to_buf(host);
...@@ -844,7 +888,6 @@ static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -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) static void innovator_fpga_socket_power(int on)
{ {
#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX) #if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
if (on) { if (on) {
fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3), fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
OMAP1510_FPGA_POWER); OMAP1510_FPGA_POWER);
...@@ -870,8 +913,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on) ...@@ -870,8 +913,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
/* GPIO 4 of TPS65010 sends SD_EN signal */ /* GPIO 4 of TPS65010 sends SD_EN signal */
tps65010_set_gpio_out_value(GPIO4, HIGH); tps65010_set_gpio_out_value(GPIO4, HIGH);
else if (cpu_is_omap24xx()) { else if (cpu_is_omap24xx()) {
u16 reg = OMAP_MMC_READ(host->base, CON); u16 reg = OMAP_MMC_READ(host, CON);
OMAP_MMC_WRITE(host->base, CON, reg | (1 << 11)); OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
} else } else
if (host->power_pin >= 0) if (host->power_pin >= 0)
omap_set_gpio_dataout(host->power_pin, 1); omap_set_gpio_dataout(host->power_pin, 1);
...@@ -883,8 +926,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on) ...@@ -883,8 +926,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
else if (machine_is_omap_h3()) else if (machine_is_omap_h3())
tps65010_set_gpio_out_value(GPIO4, LOW); tps65010_set_gpio_out_value(GPIO4, LOW);
else if (cpu_is_omap24xx()) { else if (cpu_is_omap24xx()) {
u16 reg = OMAP_MMC_READ(host->base, CON); u16 reg = OMAP_MMC_READ(host, CON);
OMAP_MMC_WRITE(host->base, CON, reg & ~(1 << 11)); OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
} else } else
if (host->power_pin >= 0) if (host->power_pin >= 0)
omap_set_gpio_dataout(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) ...@@ -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_UP:
case MMC_POWER_ON: case MMC_POWER_ON:
mmc_omap_power(host, 1); mmc_omap_power(host, 1);
dsor |= 1<<11; dsor |= 1 << 11;
break; break;
} }
...@@ -940,14 +983,14 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -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. * which results in the while loop below getting stuck.
* Writing to the CON register twice seems to do the trick. */ * Writing to the CON register twice seems to do the trick. */
for (i = 0; i < 2; i++) 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) { if (ios->power_mode == MMC_POWER_UP) {
/* Send clock cycles, poll completion */ /* Send clock cycles, poll completion */
OMAP_MMC_WRITE(host->base, IE, 0); OMAP_MMC_WRITE(host, IE, 0);
OMAP_MMC_WRITE(host->base, STAT, 0xffff); OMAP_MMC_WRITE(host, STAT, 0xffff);
OMAP_MMC_WRITE(host->base, CMD, 1<<7); OMAP_MMC_WRITE(host, CMD, 1 << 7);
while (0 == (OMAP_MMC_READ(host->base, STAT) & 1)); while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
OMAP_MMC_WRITE(host->base, STAT, 1); OMAP_MMC_WRITE(host, STAT, 1);
} }
clk_disable(host->fclk); clk_disable(host->fclk);
} }
...@@ -959,7 +1002,7 @@ static int mmc_omap_get_ro(struct mmc_host *mmc) ...@@ -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); 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, .request = mmc_omap_request,
.set_ios = mmc_omap_set_ios, .set_ios = mmc_omap_set_ios,
.get_ro = mmc_omap_get_ro, .get_ro = mmc_omap_get_ro,
...@@ -970,25 +1013,29 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -970,25 +1013,29 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
struct omap_mmc_conf *minfo = pdev->dev.platform_data; struct omap_mmc_conf *minfo = pdev->dev.platform_data;
struct mmc_host *mmc; struct mmc_host *mmc;
struct mmc_omap_host *host = NULL; struct mmc_omap_host *host = NULL;
struct resource *r; struct resource *res;
int ret = 0; int ret = 0;
int irq; 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); irq = platform_get_irq(pdev, 0);
if (!r || irq < 0) if (res == NULL || irq < 0)
return -ENXIO; return -ENXIO;
r = request_mem_region(pdev->resource[0].start, res = request_mem_region(res->start, res->end - res->start + 1,
pdev->resource[0].end - pdev->resource[0].start + 1, pdev->name);
pdev->name); if (res == NULL)
if (!r)
return -EBUSY; return -EBUSY;
mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev); mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
if (!mmc) { if (mmc == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto err_free_mem_region;
} }
host = mmc_priv(mmc); host = mmc_priv(mmc);
...@@ -1000,13 +1047,13 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1000,13 +1047,13 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
host->dma_timer.data = (unsigned long) host; host->dma_timer.data = (unsigned long) host;
host->id = pdev->id; host->id = pdev->id;
host->res = r; host->mem_res = res;
host->irq = irq; host->irq = irq;
if (cpu_is_omap24xx()) { if (cpu_is_omap24xx()) {
host->iclk = clk_get(&pdev->dev, "mmc_ick"); host->iclk = clk_get(&pdev->dev, "mmc_ick");
if (IS_ERR(host->iclk)) if (IS_ERR(host->iclk))
goto out; goto err_free_mmc_host;
clk_enable(host->iclk); clk_enable(host->iclk);
} }
...@@ -1017,7 +1064,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1017,7 +1064,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
if (IS_ERR(host->fclk)) { if (IS_ERR(host->fclk)) {
ret = PTR_ERR(host->fclk); ret = PTR_ERR(host->fclk);
goto out; goto err_free_iclk;
} }
/* REVISIT: /* REVISIT:
...@@ -1030,14 +1077,15 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1030,14 +1077,15 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
host->use_dma = 1; host->use_dma = 1;
host->dma_ch = -1; host->dma_ch = -1;
host->irq = pdev->resource[1].start; host->irq = irq;
host->base = (void __iomem*)IO_ADDRESS(r->start); host->phys_base = host->mem_res->start;
host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
mmc->ops = &mmc_omap_ops; mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 24000000; mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK; mmc->caps = MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
if (minfo->wire4) if (minfo->wire4)
mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA;
...@@ -1055,20 +1103,18 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1055,20 +1103,18 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
if ((ret = omap_request_gpio(host->power_pin)) != 0) { if ((ret = omap_request_gpio(host->power_pin)) != 0) {
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
"Unable to get GPIO pin for MMC power\n"); "Unable to get GPIO pin for MMC power\n");
goto out; goto err_free_fclk;
} }
omap_set_gpio_direction(host->power_pin, 0); omap_set_gpio_direction(host->power_pin, 0);
} }
ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
if (ret) if (ret)
goto out; goto err_free_power_gpio;
host->dev = &pdev->dev; host->dev = &pdev->dev;
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
mmc_add_host(mmc);
if (host->switch_pin >= 0) { if (host->switch_pin >= 0) {
INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host); INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host);
init_timer(&host->switch_timer); init_timer(&host->switch_timer);
...@@ -1106,10 +1152,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1106,10 +1152,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
schedule_work(&host->switch_work); schedule_work(&host->switch_work);
} }
no_switch: mmc_add_host(mmc);
return 0; return 0;
out: no_switch:
/* FIXME: Free other resources too. */ /* FIXME: Free other resources too. */
if (host) { if (host) {
if (host->iclk && !IS_ERR(host->iclk)) if (host->iclk && !IS_ERR(host->iclk))
...@@ -1118,6 +1165,20 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1118,6 +1165,20 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
clk_put(host->fclk); clk_put(host->fclk);
mmc_free_host(host->mmc); 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; return ret;
} }
...@@ -1127,30 +1188,31 @@ static int mmc_omap_remove(struct platform_device *pdev) ...@@ -1127,30 +1188,31 @@ static int mmc_omap_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
if (host) { BUG_ON(host == NULL);
mmc_remove_host(host->mmc);
free_irq(host->irq, host); mmc_remove_host(host->mmc);
free_irq(host->irq, host);
if (host->power_pin >= 0)
omap_free_gpio(host->power_pin); if (host->power_pin >= 0)
if (host->switch_pin >= 0) { omap_free_gpio(host->power_pin);
device_remove_file(&pdev->dev, &dev_attr_enable_poll); if (host->switch_pin >= 0) {
device_remove_file(&pdev->dev, &dev_attr_cover_switch); device_remove_file(&pdev->dev, &dev_attr_enable_poll);
free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); device_remove_file(&pdev->dev, &dev_attr_cover_switch);
omap_free_gpio(host->switch_pin); free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
host->switch_pin = -1; omap_free_gpio(host->switch_pin);
del_timer_sync(&host->switch_timer); host->switch_pin = -1;
flush_scheduled_work(); 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);
} }
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, 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; return 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
...@@ -393,7 +393,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -393,7 +393,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->clkrt, host->cmdat); host->clkrt, host->cmdat);
} }
static struct mmc_host_ops pxamci_ops = { static const struct mmc_host_ops pxamci_ops = {
.request = pxamci_request, .request = pxamci_request,
.get_ro = pxamci_get_ro, .get_ro = pxamci_get_ro,
.set_ios = pxamci_set_ios, .set_ios = pxamci_set_ios,
......
...@@ -616,6 +616,7 @@ static void sdhci_finish_command(struct sdhci_host *host) ...@@ -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) static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
int div; int div;
u8 ctrl;
u16 clk; u16 clk;
unsigned long timeout; unsigned long timeout;
...@@ -624,6 +625,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -624,6 +625,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); 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) if (clock == 0)
goto out; goto out;
...@@ -784,7 +792,7 @@ static int sdhci_get_ro(struct mmc_host *mmc) ...@@ -784,7 +792,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
return !(present & SDHCI_WRITE_PROTECT); return !(present & SDHCI_WRITE_PROTECT);
} }
static struct mmc_host_ops sdhci_ops = { static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request, .request = sdhci_request,
.set_ios = sdhci_set_ios, .set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro, .get_ro = sdhci_get_ro,
...@@ -1291,6 +1299,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1291,6 +1299,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
else if (caps & SDHCI_CAN_VDD_180) else if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; 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) { if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any " printk(KERN_ERR "%s: Hardware doesn't report any "
"support voltages.\n", host->slot_descr); "support voltages.\n", host->slot_descr);
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#define SDHCI_HOST_CONTROL 0x28 #define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_LED 0x01 #define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02 #define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_HISPD 0x04
#define SDHCI_POWER_CONTROL 0x29 #define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01 #define SDHCI_POWER_ON 0x01
...@@ -138,6 +139,7 @@ ...@@ -138,6 +139,7 @@
#define SDHCI_CLOCK_BASE_SHIFT 8 #define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000 #define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16 #define SDHCI_MAX_BLOCK_SHIFT 16
#define SDHCI_CAN_DO_HISPD 0x00200000
#define SDHCI_CAN_DO_DMA 0x00400000 #define SDHCI_CAN_DO_DMA 0x00400000
#define SDHCI_CAN_VDD_330 0x01000000 #define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000 #define SDHCI_CAN_VDD_300 0x02000000
......
...@@ -1021,7 +1021,7 @@ static int wbsd_get_ro(struct mmc_host *mmc) ...@@ -1021,7 +1021,7 @@ static int wbsd_get_ro(struct mmc_host *mmc)
return csr & WBSD_WRPT; return csr & WBSD_WRPT;
} }
static struct mmc_host_ops wbsd_ops = { static const struct mmc_host_ops wbsd_ops = {
.request = wbsd_request, .request = wbsd_request,
.set_ios = wbsd_set_ios, .set_ios = wbsd_set_ios,
.get_ro = wbsd_get_ro, .get_ro = wbsd_get_ro,
......
...@@ -39,6 +39,10 @@ struct mmc_csd { ...@@ -39,6 +39,10 @@ struct mmc_csd {
write_misalign:1; write_misalign:1;
}; };
struct mmc_ext_csd {
unsigned int hs_max_dtr;
};
struct sd_scr { struct sd_scr {
unsigned char sda_vsn; unsigned char sda_vsn;
unsigned char bus_widths; unsigned char bus_widths;
...@@ -46,6 +50,10 @@ struct sd_scr { ...@@ -46,6 +50,10 @@ struct sd_scr {
#define SD_SCR_BUS_WIDTH_4 (1<<2) #define SD_SCR_BUS_WIDTH_4 (1<<2)
}; };
struct sd_switch_caps {
unsigned int hs_max_dtr;
};
struct mmc_host; struct mmc_host;
/* /*
...@@ -62,12 +70,15 @@ struct mmc_card { ...@@ -62,12 +70,15 @@ struct mmc_card {
#define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_BAD (1<<2) /* unrecognised device */
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */ #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_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */ u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */ u32 raw_scr[2]; /* raw card SCR */
struct mmc_cid cid; /* card identification */ struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */ 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_scr scr; /* extra SD information */
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
}; };
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
...@@ -75,12 +86,14 @@ struct mmc_card { ...@@ -75,12 +86,14 @@ struct mmc_card {
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #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_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #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_bad(c) ((c)->state |= MMC_STATE_BAD)
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #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_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_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id) #define mmc_card_id(c) ((c)->dev.bus_id)
......
...@@ -25,14 +25,16 @@ ...@@ -25,14 +25,16 @@
#ifndef MMC_MMC_PROTOCOL_H #ifndef MMC_MMC_PROTOCOL_H
#define 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 */ /* class 1 */
#define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_GO_IDLE_STATE 0 /* bc */
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */ #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_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_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* 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 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
...@@ -80,6 +82,7 @@ ...@@ -80,6 +82,7 @@
/* class 8 */ /* class 8 */
/* This is basically the same command as for MMC with some quirks. */ /* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* Application commands */ /* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
...@@ -87,6 +90,30 @@ ...@@ -87,6 +90,30 @@
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */ #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 MMC status in R1
Type Type
...@@ -230,13 +257,54 @@ struct _mmc_csd { ...@@ -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_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_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_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #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_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 * SD bus widths
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment