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
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.
......
......@@ -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,
......
......@@ -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,
};
......
......@@ -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,
};
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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,
};
......
......@@ -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 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
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;
}
......
#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)
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,
......
......@@ -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);
......
......@@ -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
......
......@@ -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,
......
......@@ -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)
......
......@@ -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 */
......@@ -87,6 +90,30 @@
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#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
......@@ -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
......
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