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()
This commit is contained in:
commit
cdb54fac35
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
* 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)
|
|||||||
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.
|
||||||
*/
|
*
|
||||||
if (host->caps & MMC_CAP_4_BIT_DATA) {
|
|
||||||
/*
|
|
||||||
* The card is in 1 bit mode by default so
|
* The card is in 1 bit mode by default so
|
||||||
* we only need to change if it supports the
|
* we only need to change if it supports the
|
||||||
* wider version.
|
* wider version.
|
||||||
*/
|
*/
|
||||||
if (mmc_card_sd(card) &&
|
if (mmc_card_sd(card) &&
|
||||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
(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;
|
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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)) {
|
||||||
|
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;
|
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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
|
|||||||
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;
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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
|
|||||||
{
|
{
|
||||||
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
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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);
|
||||||
@ -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)
|
|||||||
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)
|
|||||||
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 (!r)
|
if (res == NULL)
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ out:
|
|||||||
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,7 +1188,8 @@ 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);
|
mmc_remove_host(host->mmc);
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
|
|
||||||
@ -1146,12 +1208,12 @@ static int mmc_omap_remove(struct platform_device *pdev)
|
|||||||
clk_put(host->iclk);
|
clk_put(host->iclk);
|
||||||
if (host->fclk && !IS_ERR(host->fclk))
|
if (host->fclk && !IS_ERR(host->fclk))
|
||||||
clk_put(host->fclk);
|
clk_put(host->fclk);
|
||||||
mmc_free_host(host->mmc);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
#ifndef DRIVERS_MEDIA_MMC_OMAP_H
|
|
||||||
#define DRIVERS_MEDIA_MMC_OMAP_H
|
|
||||||
|
|
||||||
#define OMAP_MMC_REG_CMD 0x00
|
|
||||||
#define OMAP_MMC_REG_ARGL 0x04
|
|
||||||
#define OMAP_MMC_REG_ARGH 0x08
|
|
||||||
#define OMAP_MMC_REG_CON 0x0c
|
|
||||||
#define OMAP_MMC_REG_STAT 0x10
|
|
||||||
#define OMAP_MMC_REG_IE 0x14
|
|
||||||
#define OMAP_MMC_REG_CTO 0x18
|
|
||||||
#define OMAP_MMC_REG_DTO 0x1c
|
|
||||||
#define OMAP_MMC_REG_DATA 0x20
|
|
||||||
#define OMAP_MMC_REG_BLEN 0x24
|
|
||||||
#define OMAP_MMC_REG_NBLK 0x28
|
|
||||||
#define OMAP_MMC_REG_BUF 0x2c
|
|
||||||
#define OMAP_MMC_REG_SDIO 0x34
|
|
||||||
#define OMAP_MMC_REG_REV 0x3c
|
|
||||||
#define OMAP_MMC_REG_RSP0 0x40
|
|
||||||
#define OMAP_MMC_REG_RSP1 0x44
|
|
||||||
#define OMAP_MMC_REG_RSP2 0x48
|
|
||||||
#define OMAP_MMC_REG_RSP3 0x4c
|
|
||||||
#define OMAP_MMC_REG_RSP4 0x50
|
|
||||||
#define OMAP_MMC_REG_RSP5 0x54
|
|
||||||
#define OMAP_MMC_REG_RSP6 0x58
|
|
||||||
#define OMAP_MMC_REG_RSP7 0x5c
|
|
||||||
#define OMAP_MMC_REG_IOSR 0x60
|
|
||||||
#define OMAP_MMC_REG_SYSC 0x64
|
|
||||||
#define OMAP_MMC_REG_SYSS 0x68
|
|
||||||
|
|
||||||
#define OMAP_MMC_STAT_CARD_ERR (1 << 14)
|
|
||||||
#define OMAP_MMC_STAT_CARD_IRQ (1 << 13)
|
|
||||||
#define OMAP_MMC_STAT_OCR_BUSY (1 << 12)
|
|
||||||
#define OMAP_MMC_STAT_A_EMPTY (1 << 11)
|
|
||||||
#define OMAP_MMC_STAT_A_FULL (1 << 10)
|
|
||||||
#define OMAP_MMC_STAT_CMD_CRC (1 << 8)
|
|
||||||
#define OMAP_MMC_STAT_CMD_TOUT (1 << 7)
|
|
||||||
#define OMAP_MMC_STAT_DATA_CRC (1 << 6)
|
|
||||||
#define OMAP_MMC_STAT_DATA_TOUT (1 << 5)
|
|
||||||
#define OMAP_MMC_STAT_END_BUSY (1 << 4)
|
|
||||||
#define OMAP_MMC_STAT_END_OF_DATA (1 << 3)
|
|
||||||
#define OMAP_MMC_STAT_CARD_BUSY (1 << 2)
|
|
||||||
#define OMAP_MMC_STAT_END_OF_CMD (1 << 0)
|
|
||||||
|
|
||||||
#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg)
|
|
||||||
#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command types
|
|
||||||
*/
|
|
||||||
#define OMAP_MMC_CMDTYPE_BC 0
|
|
||||||
#define OMAP_MMC_CMDTYPE_BCR 1
|
|
||||||
#define OMAP_MMC_CMDTYPE_AC 2
|
|
||||||
#define OMAP_MMC_CMDTYPE_ADTC 3
|
|
||||||
|
|
||||||
#endif
|
|
@ -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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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 @@
|
|||||||
#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)
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
#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 {
|
|||||||
#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 {
|
|||||||
#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 @@
|
|||||||
#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 @@
|
|||||||
/* 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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
#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
|
||||||
|
Loading…
Reference in New Issue
Block a user