diff -Naur kernel-source-2.6.16.27.old/arch/arm/mach-omap1/board-nokia770-mmc.c kernel-source-2.6.16.27/arch/arm/mach-omap1/board-nokia770-mmc.c --- kernel-source-2.6.16.27.old/arch/arm/mach-omap1/board-nokia770-mmc.c 2006-09-19 15:07:36.000000000 +0200 +++ kernel-source-2.6.16.27/arch/arm/mach-omap1/board-nokia770-mmc.c 2006-11-11 14:05:44.000000000 +0100 @@ -138,7 +138,7 @@ .enabled = 1, .nr_slots = 1, .wire4 = 0, - .max_freq = 12000000, + .max_freq = 48000000, .init = nokia770_mmc_late_init, .cleanup = nokia770_mmc_cleanup, .slots[0] = { diff -Naur kernel-source-2.6.16.27.old/drivers/mmc/mmc.c kernel-source-2.6.16.27/drivers/mmc/mmc.c --- kernel-source-2.6.16.27.old/drivers/mmc/mmc.c 2006-09-19 15:07:44.000000000 +0200 +++ kernel-source-2.6.16.27/drivers/mmc/mmc.c 2006-11-11 14:02:14.000000000 +0100 @@ -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 @@ -905,6 +906,109 @@ } } +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.timeout_ns = card->csd.tacc_ns * 10; + data.timeout_clks = card->csd.tacc_clks * 10; + + 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; @@ -986,8 +1090,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), @@ -1115,6 +1225,8 @@ if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); + else + mmc_process_ext_csds(host); } diff -Naur kernel-source-2.6.16.27.old/drivers/mmc/mmc_block.c kernel-source-2.6.16.27/drivers/mmc/mmc_block.c --- kernel-source-2.6.16.27.old/drivers/mmc/mmc_block.c 2006-09-19 15:07:44.000000000 +0200 +++ kernel-source-2.6.16.27/drivers/mmc/mmc_block.c 2006-11-12 14:43:13.000000000 +0100 @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -166,6 +167,7 @@ do { struct mmc_blk_request brq; struct mmc_command cmd; + u32 readcmd, writecmd; int loop_count = 0, poll_count = 0; memset(&brq, 0, sizeof(struct mmc_blk_request)); @@ -183,13 +185,31 @@ brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + /* + * If the host doesn't support multiple block writes, force + * block writes to single block. + */ + if (rq_data_dir(req) != READ && + !(card->host->caps & MMC_CAP_MULTI_WRITE)) + brq.data.blocks = 1; + + if (brq.data.blocks > 1) { + brq.data.flags |= MMC_DATA_MULTI; + brq.mrq.stop = &brq.stop; + readcmd = MMC_READ_MULTIPLE_BLOCK; + writecmd = MMC_WRITE_MULTIPLE_BLOCK; + } else { + brq.mrq.stop = NULL; + readcmd = MMC_READ_SINGLE_BLOCK; + writecmd = MMC_WRITE_BLOCK; + } + if (rq_data_dir(req) == READ) { - brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; + brq.cmd.opcode = readcmd; brq.data.flags |= MMC_DATA_READ; } else { - brq.cmd.opcode = MMC_WRITE_BLOCK; + brq.cmd.opcode = writecmd; brq.data.flags |= MMC_DATA_WRITE; - brq.data.blocks = 1; /* * Scale up the timeout by the r2w factor @@ -198,13 +218,6 @@ brq.data.timeout_clks <<= card->csd.r2w_factor; } - if (brq.data.blocks > 1) { - brq.data.flags |= MMC_DATA_MULTI; - brq.mrq.stop = &brq.stop; - } else { - brq.mrq.stop = NULL; - } - brq.data.sg = mq->sg; brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); diff -Naur kernel-source-2.6.16.27.old/drivers/mmc/omap.c kernel-source-2.6.16.27/drivers/mmc/omap.c --- kernel-source-2.6.16.27.old/drivers/mmc/omap.c 2006-09-19 15:07:44.000000000 +0200 +++ kernel-source-2.6.16.27/drivers/mmc/omap.c 2006-11-13 22:07:28.000000000 +0100 @@ -1113,12 +1113,13 @@ if (host->pdata->wire4) mmc->caps |= MMC_CAP_4_BIT_DATA; +// mmc->caps |= MMC_CAP_MULTI_WRITE; mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; - if (cpu_class_is_omap2()) +// if (cpu_class_is_omap2()) mmc->f_max = 48000000; - else - mmc->f_max = 24000000; +// else +// mmc->f_max = 24000000; if (host->pdata->max_freq) mmc->f_max = min(host->pdata->max_freq, mmc->f_max); mmc->ocr_avail = slot->pdata->ocr_mask; diff -Naur kernel-source-2.6.16.27.old/include/linux/mmc/card.h kernel-source-2.6.16.27/include/linux/mmc/card.h --- kernel-source-2.6.16.27.old/include/linux/mmc/card.h 2006-09-19 15:07:52.000000000 +0200 +++ kernel-source-2.6.16.27/include/linux/mmc/card.h 2006-11-11 13:45:54.000000000 +0100 @@ -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 -Naur kernel-source-2.6.16.27.old/include/linux/mmc/host.h kernel-source-2.6.16.27/include/linux/mmc/host.h --- kernel-source-2.6.16.27.old/include/linux/mmc/host.h 2006-09-19 15:07:52.000000000 +0200 +++ kernel-source-2.6.16.27/include/linux/mmc/host.h 2006-11-12 14:44:12.000000000 +0100 @@ -85,6 +85,7 @@ unsigned long caps; /* Host capabilities */ #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ +#define MMC_CAP_MULTI_WRITE (1 << 1) /* Can do multiple block writes */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ diff -Naur kernel-source-2.6.16.27.old/include/linux/mmc/protocol.h kernel-source-2.6.16.27/include/linux/mmc/protocol.h --- kernel-source-2.6.16.27.old/include/linux/mmc/protocol.h 2006-09-19 15:07:52.000000000 +0200 +++ kernel-source-2.6.16.27/include/linux/mmc/protocol.h 2006-11-11 13:45:54.000000000 +0100 @@ -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