分类:
2015-05-10 01:01:14
原文地址:Linux mmc+sd 2G驱动 作者:study-linux
[] [] [prev in thread] []
List:
Subject:
From:
Date:
Message-ID:
[]
Hi Pierre,
I couldn't wait to do this, so here's the updated diff :-)
I've taken your previous comments to heart and I believe that
this can probably just be a single diff, but if you want me to
split it out, just ask.
This adds support for the high-speed modes defined by mmc v4
(assuming the host controller is up to it). On a TI sdhci controller,
it improves read speed from 1.3MBps to 2.3MBps. The TI controller can
only go up to 24MHz, but everything helps. Another person has taken
this basic patch and used it on a Nokia 770 to get a bigger boost
because that controller can run at 48MHZ.
Thanks,
--phil
Signed-off-by: Philip Langdale
---
drivers/mmc/mmc.c | 110 ++++++++++++++++++++++++++++++++++++++++++-
include/linux/mmc/card.h | 8 +++
include/linux/mmc/protocol.h | 16 +++++-
3 files changed, 129 insertions(+), 5 deletions(-)
diff -urN /usr/src/linux-2.6.18/drivers/mmc/mmc.c linux-2.6.18-mmc4/drivers/mmc/mmc.c
--- /usr/src/linux-2.6.18/drivers/mmc/mmc.c 2006-09-19 20:42:06.000000000 -0700
+++ linux-2.6.18-mmc4/drivers/mmc/mmc.c 2006-10-03 22:14:05.000000000 -0700
@@ -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
@@ -427,6 +428,30 @@
}
}
+ /* Activate highspeed MMC v4 support. */
+ if (card->csd.mmca_vsn == CSD_SPEC_VER_4) {
+ struct mmc_command cmd;
+
+ /*
+ * Arg breakdown:
+ * [31:26] Set to 0
+ * [25:24] Access: Write Byte (0x03)
+ * [23:16] Index: HS_TIMING (0xB9)
+ * [15:08] Value: True (0x01)
+ * [07:03] Set to 0
+ * [02:00] Cmd Set: Standard (0x00)
+ */
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = 0x03B90100;
+ cmd.flags = MMC_RSP_R1B;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ mmc_card_set_highspeed(card);
+ }
+
mmc_set_ios(host);
return MMC_ERR_NONE;
@@ -953,6 +978,74 @@
}
}
+static void mmc_read_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[512];
+
+ 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;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ data.blksz_bits = 9;
+ data.blksz = 1 << 9;
+ 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;
+ }
+
+ card->ext_csd.card_type = ext_csd[196];
+ }
+
+ mmc_deselect_cards(host);
+}
+
static void mmc_read_scrs(struct mmc_host *host)
{
int err;
@@ -1032,8 +1125,19 @@
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))
+ if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_52) &&
+ max_dtr > 52000000)
+ max_dtr = 52000000;
+ else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_26) &&
+ max_dtr > 26000000)
+ max_dtr = 26000000;
+ else /* mmc v4 spec says this cannot happen */
+ BUG_ON(card->ext_csd.card_type == 0);
+ 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),
@@ -1153,6 +1257,8 @@
if (host->mode == MMC_MODE_SD)
mmc_read_scrs(host);
+ else
+ mmc_read_ext_csds(host);
}
diff -urN /usr/src/linux-2.6.18/include/linux/mmc/card.h \
linux-2.6.18-mmc4/include/linux/mmc/card.h
--- /usr/src/linux-2.6.18/include/linux/mmc/card.h 2006-09-19 20:42:06.000000000 \
-0700
+++ linux-2.6.18-mmc4/include/linux/mmc/card.h 2006-10-03 22:13:58.000000000 -0700
@@ -39,6 +39,10 @@
write_misalign:1;
};
+struct mmc_ext_csd {
+ unsigned char card_type;
+};
+
struct sd_scr {
unsigned char sda_vsn;
unsigned char bus_widths;
@@ -62,11 +66,13 @@
#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 mmc4 highspeed mode */
u32 raw_cid; /* raw card CID */
u32 raw_csd; /* raw card CSD */
u32 raw_scr; /* 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 */
};
@@ -75,12 +81,14 @@
#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)
diff -urN /usr/src/linux-2.6.18/include/linux/mmc/protocol.h \
linux-2.6.18-mmc4/include/linux/mmc/protocol.h
--- /usr/src/linux-2.6.18/include/linux/mmc/protocol.h 2006-09-19 20:42:06.000000000 \
-0700
+++ linux-2.6.18-mmc4/include/linux/mmc/protocol.h 2006-10-03 22:14:08.000000000 \
-0700 @@ -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] Complex 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 */
@@ -229,13 +231,21 @@
#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 field definitions
+ */
+
+#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 */
/*
* SD bus widths
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at
Please read the FAQ at
On 2/24/06, Dmitry Artamonow
> On Thu, Feb 23, 2006 at 09:43:45PM -0800, Matt Reimer wrote:
> >
> > Did you try partitioning and formatting the card on your iPAQ, or with
> > the card reader? I wonder if it's the card reader that's messing up.
> > Or are you saying that fdisk is breaking things by assuming 512 byte
> > blocks?
> >
> > Matt
> >
>
> I partitioned and formatted card with card reader on my linux PC. Fdisk
> partitioned it with 512-byte sectors. I think fdisk gets sector size
> from block device. When i insert this card into iPAQ
> and run fdisk here (i booted from CF with help of Stanson's patches), it
> gives me a warning about sector size:
>
> / # fdisk /dev/mmcblk0
> Note: sector size is 1024 (not 512)
>
> Command (m for help):
>
>
> So, i don't know what's messing up - maybe it's MMC code, maybe it's
> faulty reader or even usb-storage code. As i said I tried with two USB
> readers - with both of them fdisk thinks that sector size is 512 (but with
> one of them linux sees only half of card's capacity - that's strange too).
> Here's the facts - what fdisk tells about card's geometry:
>
> Linux PC + cardreader 1 (my):
>
> Disk /dev/sda: 2045 MB, 2045771776 bytes
> 63 heads, 62 sectors/track, 1022 cylinders
> Units = cylinders of 3906 * 512 = 1999872 bytes
>
> Linux PC + cardreader 2 (my friend's):
>
> Disk /dev/sda: 1022 MB, 1022885888 bytes
> 63 heads, 62 sectors/track, 511 cylinders
> Units = cylinders of 3906 * 512 = 1999872 bytes
>
> Linux iPAQ without dirty hack:
>
> Disk /dev/mmcblk0: 2045 MB, 2045771776 bytes
> 63 heads, 62 sectors/track, 511 cylinders
> Units = cylinders of 3906 * 1024 = 3999744 bytes
>
>
> I didn't try with any other readers and Windows PCs, since i don't have
> access to them. By the way, Windows CE on iPAQ doesn't detect this card at
> all (that's funny, isn't it?).
Maybe your card reader is broken for large block sizes too. Can you
try using the MMC v4 patch but not the 9 bit/512-byte block patch, and
do the partitioning on your iPAQ instead of using the card reader?
Maybe linux is right and the card reader is wrong. The card reader
won't hit the drivers/mmc code path, so even though you may have linux
on both your iPAQ and your desktop, the behavior could be different.
Matt
Received on Fri Feb 24 2006 - 17:01:44 EST