r1237 - trunk/src/target/kernel/patches
laforge at sita.openmoko.org
laforge at sita.openmoko.org
Sun Mar 4 15:38:11 CET 2007
Author: laforge
Date: 2007-03-04 15:38:08 +0100 (Sun, 04 Mar 2007)
New Revision: 1237
Added:
trunk/src/target/kernel/patches/sdhc-backport.patch
Modified:
trunk/src/target/kernel/patches/series
Log:
add sdhc patch from 2.6.21-rc1 mainline (See: http://bugzilla.openmoko.org/cgi-bin/bugzilla/show_bug.cgi?id=93)
Added: trunk/src/target/kernel/patches/sdhc-backport.patch
===================================================================
--- trunk/src/target/kernel/patches/sdhc-backport.patch 2007-03-04 13:08:07 UTC (rev 1236)
+++ trunk/src/target/kernel/patches/sdhc-backport.patch 2007-03-04 14:38:08 UTC (rev 1237)
@@ -0,0 +1,323 @@
+From: Philip Langdale <philipl at overt.org>
+Date: Thu, 4 Jan 2007 14:57:32 +0000 (-0800)
+Subject: mmc: Add support for SDHC cards
+X-Git-Tag: v2.6.21-rc1^0~274^2~627^2~26
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fba68bd2dab1ac99af3c5a963ec9581cfa9f1725
+
+mmc: Add support for SDHC cards
+
+Thanks to the generous donation of an SDHC card by John Gilmore, and
+the surprisingly enlightened decision by the SD Card Association to
+publish useful specs, I've been able to bash out support for SDHC. The
+changes are not too profound:
+
+i) Add a card flag indicating the card uses block level addressing and
+check it in the block driver. As we never took advantage of byte-level
+addressing, this simply involves skipping the block -> byte
+translation when sending commands.
+
+ii) The layout of the CSD is changed - a set of fields are discarded
+to make space for a larger C_SIZE. We did not reference any of the
+discarded fields except those related to the C_SIZE.
+
+iii) Read and write timeouts are fixed values and not calculated from
+CSD values.
+
+iv) Before invoking SEND_APP_OP_COND, we must invoke the new
+SEND_IF_COND to inform the card we support SDHC.
+
+Signed-off-by: Philipl Langdale <philipl at overt.org>
+Signed-off-by: Pierre Ossman <drzeus at drzeus.cx>
+---
+
+diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
+index 105f419..b48c277 100644
+--- a/drivers/mmc/mmc.c
++++ b/drivers/mmc/mmc.c
+@@ -289,7 +289,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+ else
+ limit_us = 100000;
+
+- if (timeout_us > limit_us) {
++ /*
++ * SDHC cards always use these fixed values.
++ */
++ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+ data->timeout_ns = limit_us * 1000;
+ data->timeout_clks = 0;
+ }
+@@ -372,7 +375,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
+ mmc_hostname(host), ios->clock, ios->bus_mode,
+ ios->power_mode, ios->chip_select, ios->vdd,
+ ios->bus_width);
+-
++
+ host->ops->set_ios(host, ios);
+ }
+
+@@ -588,34 +591,65 @@ static void mmc_decode_csd(struct mmc_card *card)
+
+ if (mmc_card_sd(card)) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+- if (csd_struct != 0) {
++
++ switch (csd_struct) {
++ case 0:
++ m = UNSTUFF_BITS(resp, 115, 4);
++ e = UNSTUFF_BITS(resp, 112, 3);
++ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
++ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
++
++ m = UNSTUFF_BITS(resp, 99, 4);
++ e = UNSTUFF_BITS(resp, 96, 3);
++ csd->max_dtr = tran_exp[e] * tran_mant[m];
++ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
++
++ e = UNSTUFF_BITS(resp, 47, 3);
++ m = UNSTUFF_BITS(resp, 62, 12);
++ csd->capacity = (1 + m) << (e + 2);
++
++ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
++ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
++ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
++ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
++ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
++ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
++ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
++ break;
++ case 1:
++ /*
++ * This is a block-addressed SDHC card. Most
++ * interesting fields are unused and have fixed
++ * values. To avoid getting tripped by buggy cards,
++ * we assume those fixed values ourselves.
++ */
++ mmc_card_set_blockaddr(card);
++
++ csd->tacc_ns = 0; /* Unused */
++ csd->tacc_clks = 0; /* Unused */
++
++ m = UNSTUFF_BITS(resp, 99, 4);
++ e = UNSTUFF_BITS(resp, 96, 3);
++ csd->max_dtr = tran_exp[e] * tran_mant[m];
++ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
++
++ m = UNSTUFF_BITS(resp, 48, 22);
++ csd->capacity = (1 + m) << 10;
++
++ csd->read_blkbits = 9;
++ csd->read_partial = 0;
++ csd->write_misalign = 0;
++ csd->read_misalign = 0;
++ csd->r2w_factor = 4; /* Unused */
++ csd->write_blkbits = 9;
++ csd->write_partial = 0;
++ break;
++ default:
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+-
+- m = UNSTUFF_BITS(resp, 115, 4);
+- e = UNSTUFF_BITS(resp, 112, 3);
+- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+-
+- m = UNSTUFF_BITS(resp, 99, 4);
+- e = UNSTUFF_BITS(resp, 96, 3);
+- csd->max_dtr = tran_exp[e] * tran_mant[m];
+- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+-
+- e = UNSTUFF_BITS(resp, 47, 3);
+- m = UNSTUFF_BITS(resp, 62, 12);
+- csd->capacity = (1 + m) << (e + 2);
+-
+- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ } else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+@@ -848,6 +882,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+ return err;
+ }
+
++static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
++{
++ struct mmc_command cmd;
++ int err, sd2;
++ static const u8 test_pattern = 0xAA;
++
++ /*
++ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
++ * before SD_APP_OP_COND. This command will harmlessly fail for
++ * SD 1.0 cards.
++ */
++ cmd.opcode = SD_SEND_IF_COND;
++ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
++ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
++
++ err = mmc_wait_for_cmd(host, &cmd, 0);
++ if (err == MMC_ERR_NONE) {
++ if ((cmd.resp[0] & 0xFF) == test_pattern) {
++ sd2 = 1;
++ } else {
++ sd2 = 0;
++ err = MMC_ERR_FAILED;
++ }
++ } else {
++ /*
++ * Treat errors as SD 1.0 card.
++ */
++ sd2 = 0;
++ err = MMC_ERR_NONE;
++ }
++ if (rsd2)
++ *rsd2 = sd2;
++ return err;
++}
++
+ /*
+ * Discover cards by requesting their CID. If this command
+ * times out, it is not an error; there are no further cards
+@@ -1334,6 +1403,10 @@ static void mmc_setup(struct mmc_host *host)
+ mmc_power_up(host);
+ mmc_idle_cards(host);
+
++ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
++ if (err != MMC_ERR_NONE) {
++ return;
++ }
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+
+ /*
+@@ -1386,10 +1459,21 @@ static void mmc_setup(struct mmc_host *host)
+ * all get the idea that they should be ready for CMD2.
+ * (My SanDisk card seems to need this.)
+ */
+- if (host->mode == MMC_MODE_SD)
+- mmc_send_app_op_cond(host, host->ocr, NULL);
+- else
++ if (host->mode == MMC_MODE_SD) {
++ int err, sd2;
++ err = mmc_send_if_cond(host, host->ocr, &sd2);
++ if (err == MMC_ERR_NONE) {
++ /*
++ * If SD_SEND_IF_COND indicates an SD 2.0
++ * compliant card and we should set bit 30
++ * of the ocr to indicate that we can handle
++ * block-addressed SDHC cards.
++ */
++ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
++ }
++ } else {
+ mmc_send_op_cond(host, host->ocr, NULL);
++ }
+
+ mmc_discover_cards(host);
+
+diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
+index 8771357..5a4eaca 100644
+--- a/drivers/mmc/mmc_block.c
++++ b/drivers/mmc/mmc_block.c
+@@ -237,7 +237,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ brq.mrq.cmd = &brq.cmd;
+ brq.mrq.data = &brq.data;
+
+- brq.cmd.arg = req->sector << 9;
++ brq.cmd.arg = req->sector;
++ if (!mmc_card_blockaddr(card))
++ brq.cmd.arg <<= 9;
+ brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq.data.blksz = 1 << md->block_bits;
+ brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+@@ -494,6 +496,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+ struct mmc_command cmd;
+ int err;
+
++ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
++ if (mmc_card_blockaddr(card))
++ return 0;
++
+ mmc_card_claim_host(card);
+ cmd.opcode = MMC_SET_BLOCKLEN;
+ cmd.arg = 1 << md->block_bits;
+diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
+index d0e6a54..e45712a 100644
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -71,6 +71,7 @@ struct mmc_card {
+ #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 */
++#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */
+ u32 raw_cid[4]; /* raw card CID */
+ u32 raw_csd[4]; /* raw card CSD */
+ u32 raw_scr[2]; /* raw card SCR */
+@@ -87,6 +88,7 @@ struct mmc_card {
+ #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_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
+
+ #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
+ #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
+@@ -94,6 +96,7 @@ struct mmc_card {
+ #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_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+
+ #define mmc_card_name(c) ((c)->cid.prod_name)
+ #define mmc_card_id(c) ((c)->dev.bus_id)
+diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
+index bcf2490..cdc54be 100644
+--- a/include/linux/mmc/mmc.h
++++ b/include/linux/mmc/mmc.h
+@@ -43,6 +43,7 @@ struct mmc_command {
+ #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+ #define MMC_RSP_R3 (MMC_RSP_PRESENT)
+ #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
++#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+
+ #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
+index 2dce60c..c90b676 100644
+--- a/include/linux/mmc/protocol.h
++++ b/include/linux/mmc/protocol.h
+@@ -79,9 +79,12 @@
+ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
+
+ /* SD commands type argument response */
+- /* class 8 */
++ /* class 0 */
+ /* This is basically the same command as for MMC with some quirks. */
+ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
++#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
++
++ /* class 10 */
+ #define SD_SWITCH 6 /* adtc [31:0] See below R1 */
+
+ /* Application commands */
+@@ -115,6 +118,14 @@
+ */
+
+ /*
++ * SD_SEND_IF_COND argument format:
++ *
++ * [31:12] Reserved (0)
++ * [11:8] Host Voltage Supply Flags
++ * [7:0] Check Pattern (0xAA)
++ */
++
++/*
+ MMC status in R1
+ Type
+ e : error bit
Modified: trunk/src/target/kernel/patches/series
===================================================================
--- trunk/src/target/kernel/patches/series 2007-03-04 13:08:07 UTC (rev 1236)
+++ trunk/src/target/kernel/patches/series 2007-03-04 14:38:08 UTC (rev 1237)
@@ -33,3 +33,4 @@
ts0710.patch
s3c2410-qt2410-buttons.patch
config-nr-tty-devices.patch
+sdhc-backport.patch
More information about the commitlog
mailing list