mmc: Add support for SDHC cards

user name
2006-12-22 18:24:00
Hi all,

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.

I've done some basic read and write tests and everything
seems to work fine but one
should obviously use caution in case it eats your data.

Addendum: Similar spec changes were introduced by the MMC
Association in version 4.2
to switch to block addressing. We do not have access to the
4.2 spec or even a change
summary as we did for 3 -> 4. My guess as to what's
changed looks something like the
following:

i) A new field is added to the ext_csd to store the capacity
that cannot be described
using existing csd fields.

ii) A new field is added to the ext_csd to indicate the need
for block addressing.

iii) A new write-only field is added to the ext_csd which
has to be toggled to tell the
card that the host supports block-addressing. But perhaps
compatibility requires that
a new command be used like for SDHC...

If someone has access to the spec and can shed some light on
the subject in a legal way,
please let us know. Of course, I don't think there are any
MMC HC cards on the market
yet, but one was announced last month.

--phil

Signed-off-by: Philipl Langdale <philiplovert.org>
---

drivers/mmc/mmc.c | 40
+++++++++++++++++++++++++++++++++++-----
drivers/mmc/mmc_block.c | 4 +++-
include/linux/mmc/card.h | 3 +++
include/linux/mmc/mmc.h | 1 +
include/linux/mmc/protocol.h | 13 ++++++++++++-
5 files changed, 54 insertions(+), 7 deletions(-)

diff -urN linux-2.6.19/drivers/mmc/mmc_block.c
linux-2.6.19-sdhc/drivers/mmc/mmc_block.c
--- linux-2.6.19/drivers/mmc/mmc_block.c 2006-12-21
20:29:49.000000000 -0800
+++ linux-2.6.19-sdhc/drivers/mmc/mmc_block.c 2006-12-22
08:42:56.000000000 -0800
-237,7
+237,9
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);
diff -urN linux-2.6.19/drivers/mmc/mmc.c
linux-2.6.19-sdhc/drivers/mmc/mmc.c
--- linux-2.6.19/drivers/mmc/mmc.c 2006-12-21
20:29:49.000000000 -0800
+++ linux-2.6.19-sdhc/drivers/mmc/mmc.c 2006-12-22
09:57:41.000000000 -0800
-289,7
+289,10
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;
}
-588,12
+591,15

if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 0) {
+ if (csd_struct != 0 && csd_struct != 1) {
printk("%s: unrecognised CSD structure version
%dn",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
return;
}
+ if (csd_struct == 1) {
+ mmc_card_set_blockaddr(card);
+ }

m = UNSTUFF_BITS(resp, 115, 4);
e = UNSTUFF_BITS(resp, 112, 3);
-605,9
+611,14
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);
+ if (csd_struct == 0) {
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+ } else if (csd_struct == 1) {
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+ }

csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
-824,6
+835,25
{
struct mmc_command cmd;
int i, err = 0;
+ 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 and MMC cards (fortunately including MMC 4
cards).
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((host->ocr_avail & 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) {
+ return MMC_ERR_FAILED;
+ } else if (ocr != 0) {
+ ocr |= 1 << 30;
+ }
+ }

cmd.opcode = SD_APP_OP_COND;
cmd.arg = ocr;
diff -urN linux-2.6.19/include/linux/mmc/card.h
linux-2.6.19-sdhc/include/linux/mmc/card.h
--- linux-2.6.19/include/linux/mmc/card.h 2006-12-21
20:29:49.000000000 -0800
+++ linux-2.6.19-sdhc/include/linux/mmc/card.h 2006-12-22
08:42:56.000000000 -0800
-71,6
+71,7
#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
#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
#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 -urN linux-2.6.19/include/linux/mmc/mmc.h
linux-2.6.19-sdhc/include/linux/mmc/mmc.h
--- linux-2.6.19/include/linux/mmc/mmc.h 2006-11-29
13:57:37.000000000 -0800
+++ linux-2.6.19-sdhc/include/linux/mmc/mmc.h 2006-12-22
08:42:56.000000000 -0800
-43,6
+43,7
#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)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC)

#define mmc_resp_type(cmd) ((cmd)->flags &
(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RS
P_OPCODE))

diff -urN linux-2.6.19/include/linux/mmc/protocol.h
linux-2.6.19-sdhc/include/linux/mmc/protocol.h
--- linux-2.6.19/include/linux/mmc/protocol.h 2006-12-21
20:29:49.000000000 -0800
+++
linux-2.6.19-sdhc/include/linux/mmc/protocol.h 2006-12-22
08:42:56.000000000 -0800
-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
-
To unsubscribe from this list: send the line
"unsubscribe linux-kernel" in
the body of a message to majordomovger.kernel.org
More majordomo info at http://vge
r.kernel.org/majordomo-info.html

Please read the FAQ at http://www.tux.org/lkml/

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!"mmc0: Skipping voltage switch" 是内核启动过程中的一条信息,它表示内核在初始化MMC(多媒体卡)设备时跳过了电压切换操作。 MMC是一种用于存储数据的可移动存储介质,如SD卡或eMMC(嵌入式多媒体卡)。电压切换是指在MMC设备的不同操作模式之间切换电压级别,以满足设备的要求。 跳过电压切换通常是由于以下原因之一: 1. 设备不需要进行电压切换:某些MMC设备在初始化过程中不需要进行电压切换,因为它们已经处于所需的电压级别下。因此,内核会跳过这一步骤并打印这个信息。 2. 内核配置不正确:确保您的内核配置中已经启用了MMC设备和相应的电压切换支持。您可以通过 `make menuconfig` 命令或者编辑 `.config` 文件来进行配置。确保以下选项被选中: - `CONFIG_MMC`:启用MMC子系统支持 - `CONFIG_MMC_BLOCK`:启用MMC块设备支持 - `CONFIG_MMC_SDHCI` 或 `CONFIG_MMC_SDHCI_PLTFM`:启用SDHCI控制器支持(具体选项名称可能会有所不同,取决于内核版本和配置) 如果您的设备确实需要电压切换,但是内核跳过了这一步骤,您可以尝试以下方法解决问题: 1. 检查设备的硬件电路:确保设备的硬件电路正确连接,并且支持所需的电压切换。如果电压切换电路未正确连接或者不支持所需的电压级别,那么内核就无法执行电压切换操作。 2. 检查设备树配置:如果您使用的是设备树,确认设备树中的MMC节点是否正确配置了电压切换相关的属性。例如,您可以检查设备树中的 `vmmc-supply` 属性是否正确设置。 请注意,"mmc0: Skipping voltage switch" 信息本身并不一定代表错误,只是表示内核在初始化MMC设备时跳过了电压切换操作。如果您的系统能够正常工作且没有其他错误提示,那么这条信息可能是正常现象。如果您遇到其他问题或错误,请提供更多详细信息,以便我能够更好地帮助您解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值