2006-10-04 05:52:08

by Philip Langdale

[permalink] [raw]
Subject: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

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 <[email protected]>
---

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[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
+ struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
struct sd_scr scr; /* extra SD information */
};

@@ -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



2006-10-07 05:58:52

by Pierre Ossman

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

[email protected] wrote:
> Hi Pierre,
>
> I couldn't wait to do this, so here's the updated diff :-)
>

Nice. I'll try to review it this weekend.

Rgds
Pierre

2006-10-10 06:17:27

by Pierre Ossman

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

[email protected] wrote:
> 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 patch is small and self contained, so it will do just fine.

> 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 <[email protected]>
> ---
>
> 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;
>

I'd prefer some defines and shifts here. Also, this should be done at
init, not at select. The reason SD does it is that the spec says it
drops out of wide mode when it gets unselected.

> @@ -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),
>

A "max_dtr" int the mmc_ext_csd structure would be nicer here. And you
cannot do a kernel BUG because the card is broken. You should mark it as
dead.

Rgds
Pierre

2006-10-11 05:39:30

by Philip Langdale

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

> Pierre Ossman wrote:
>> + cmd.arg = 0x03B90100;
>>
>
> I'd prefer some defines and shifts here. Also, this should be done at
> init, not at select. The reason SD does it is that the spec says it
> drops out of wide mode when it gets unselected.

I have done this, but your suggestion somewhat contradicts your original
suggestion to remove the defines. Essentially, my updated change restores
the relevant definitions from my very first diff. I hope this is what you
wanted. I prefer to have the #defines, so I'm not complaining.

I also moved the explaination of the MMC_SWITCH argument to protocol.h I
think it's worth documenting somewhere.

I have moved this work into the read_ext_csd function and renamed it
process_ext_csd.

> A "max_dtr" int the mmc_ext_csd structure would be nicer here. And you
> cannot do a kernel BUG because the card is broken. You should mark it as
> dead.

I have replaced storing the CARD_TYPE value with storing a dtr based on
the CARD_TYPE which should achieve what you wanted. I've replaced the
BUG with marking the card as bad.

Finally, as pointed out by Jarkko, I added the missing MMC_CMD flags to
the calls to MMC_SWITCH and MMC_SEND_EXT_CSD;

Thanks,

--phil

Signed-off-by: Philip Langdale <[email protected]>
---

drivers/mmc/mmc.c | 114 ++++++++++++++++++++++++++++++++++++++++++-
include/linux/mmc/card.h | 8 +++
include/linux/mmc/protocol.h | 47 ++++++++++++++++-
3 files changed, 164 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-10 22:31:15.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
@@ -953,6 +954,107 @@
}
}

+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[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 | MMC_CMD_ADTC;
+
+ 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;
+ }
+
+ 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);
+ /* printk a warning */
+ 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);
+ }
+
+ mmc_deselect_cards(host);
+}
+
static void mmc_read_scrs(struct mmc_host *host)
{
int err;
@@ -1032,8 +1134,14 @@
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 (max_dtr > card->ext_csd.hs_max_dtr)
+ max_dtr = card->ext_csd.hs_max_dtr;
+ } else if (max_dtr > card->csd.max_dtr) {
+ max_dtr = card->csd.max_dtr;
+ }
+ }

pr_debug("%s: selected %d.%03dMHz transfer rate\n",
mmc_hostname(host),
@@ -1153,6 +1261,8 @@

if (host->mode == MMC_MODE_SD)
mmc_read_scrs(host);
+ else
+ mmc_process_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-10 21:47:52.000000000 -0700
@@ -39,6 +39,10 @@
write_misalign:1;
};

+struct mmc_ext_csd {
+ unsigned int hs_max_dtr;
+};
+
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[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
+ struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
struct sd_scr scr; /* extra SD information */
};

@@ -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-10 21:48:52.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] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
@@ -87,6 +89,17 @@
#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
+ */
+
+/*
MMC status in R1
Type
e : error bit
@@ -229,13 +242,41 @@

#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
-#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */

#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
-#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
+
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_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 */
+
+/*
+ * 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 */

/*
* SD bus widths


2006-10-11 05:58:29

by Pierre Ossman

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

[email protected] wrote:
>> Pierre Ossman wrote:
>>
>>> + cmd.arg = 0x03B90100;
>>>
>>>
>> I'd prefer some defines and shifts here. Also, this should be done at
>> init, not at select. The reason SD does it is that the spec says it
>> drops out of wide mode when it gets unselected.
>>
>
> I have done this, but your suggestion somewhat contradicts your original
> suggestion to remove the defines. Essentially, my updated change restores
> the relevant definitions from my very first diff. I hope this is what you
> wanted. I prefer to have the #defines, so I'm not complaining.
>

I know I can be a bit unclear some times, so feel free to be utterly
confused. :)

What I don't like is defines used for structure offsets where those
fields will be transformed into a normal C structure. I.e. the defines
will only be used once.

In this case, it's protocol opcodes, which are far more vital to have
readable. Currently we only use this in one place, but this will
probably grow. If I understand things correctly, switching to 4-bit and
8-bit bus also uses the SWITCH command?

> I also moved the explaination of the MMC_SWITCH argument to protocol.h I
> think it's worth documenting somewhere.
>

A variant of this would be to do a macro. But this is fine as well.

> I have moved this work into the read_ext_csd function and renamed it
> process_ext_csd.
>
>

Looks good.

>> A "max_dtr" int the mmc_ext_csd structure would be nicer here. And you
>> cannot do a kernel BUG because the card is broken. You should mark it as
>> dead.
>>
>
> I have replaced storing the CARD_TYPE value with storing a dtr based on
> the CARD_TYPE which should achieve what you wanted. I've replaced the
> BUG with marking the card as bad.
>
>

Very nice. This is a lot less confusing when someone else will be
mucking about with the clock selection routines (e.g. adding SDIO support).

> Finally, as pointed out by Jarkko, I added the missing MMC_CMD flags to
> the calls to MMC_SWITCH and MMC_SEND_EXT_CSD;
>

Rgds
Pierre

2006-10-11 07:00:21

by Philip Langdale

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

Pierre Ossman wrote:
>
> In this case, it's protocol opcodes, which are far more vital to have
> readable. Currently we only use this in one place, but this will
> probably grow. If I understand things correctly, switching to 4-bit and
> 8-bit bus also uses the SWITCH command?

Correct. SWITCH is used to change the bus width. Now I have to stop
avoiding the issue and confront those crazy test commands so we can turn
on the wide-bus stuff properly. (You are happy with this diff now right? :-)

--phil

2006-10-15 19:49:15

by Pierre Ossman

[permalink] [raw]
Subject: Re: [PATCH 2.6.18 1/1] mmc: Add support for mmc v4 high speed mode

Philip Langdale wrote:
> Correct. SWITCH is used to change the bus width. Now I have to stop
> avoiding the issue and confront those crazy test commands so we can turn
> on the wide-bus stuff properly. (You are happy with this diff now right? :-)
>

That I am. It will be queued up for 2.6.20 once I get my new maintainer
role in order.

--
-- Pierre Ossman

Linux kernel, MMC maintainer http://www.kernel.org
PulseAudio, core developer http://pulseaudio.org
rdesktop, core developer http://www.rdesktop.org
OLPC, developer http://www.laptop.org