diff -aur kernel-source-2.6.16.old/drivers/mmc/mmc.c kernel-source-2.6.16/drivers/mmc/mmc.c --- kernel-source-2.6.16.old/drivers/mmc/mmc.c 2006-06-20 16:01:59.000000000 +0200 +++ kernel-source-2.6.16/drivers/mmc/mmc.c 2006-10-03 10:33:43.000000000 +0200 @@ -369,6 +369,20 @@ } } + /* Activate highspeed MMC v4 support. */ + if (card->csd.mmca_vsn == 4) { + struct mmc_command cmd; + cmd.opcode = SD_APP_SET_BUS_WIDTH; + 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); + } + + host->ops->set_ios(host, &host->ios); return MMC_ERR_NONE; @@ -893,6 +907,88 @@ } } +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 (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)); + + data.timeout_ns = card->csd.tacc_ns * 10; + data.timeout_clks = card->csd.tacc_clks * 10; + data.blksz_bits = 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.cmd_set_rev = ext_csd[EXT_CSD_CMD_SET_REV]; + card->ext_csd.ext_csd_rev = ext_csd[EXT_CSD_EXT_CSD_REV]; + card->ext_csd.csd_structure = ext_csd[EXT_CSD_CSD_STRUCTURE]; + card->ext_csd.card_type = ext_csd[EXT_CSD_CARD_TYPE]; + + card->ext_csd.pwr_cl_52_195 = ext_csd[EXT_CSD_PWR_CL_52_195]; + card->ext_csd.pwr_cl_26_195 = ext_csd[EXT_CSD_PWR_CL_26_195]; + card->ext_csd.pwr_cl_52_360 = ext_csd[EXT_CSD_PWR_CL_52_360]; + card->ext_csd.pwr_cl_26_360 = ext_csd[EXT_CSD_PWR_CL_26_360]; + + card->ext_csd.min_perf_r_4_26 = ext_csd[EXT_CSD_MIN_PERF_R_4_26]; + card->ext_csd.min_perf_w_4_26 = ext_csd[EXT_CSD_MIN_PERF_W_4_26]; + card->ext_csd.min_perf_r_8_26_4_52 = ext_csd[EXT_CSD_MIN_PERF_R_8_26_4_52]; + card->ext_csd.min_perf_w_8_26_4_52 = ext_csd[EXT_CSD_MIN_PERF_W_8_26_4_52]; + card->ext_csd.min_perf_r_8_52 = ext_csd[EXT_CSD_MIN_PERF_R_8_52]; + card->ext_csd.min_perf_w_8_52 = ext_csd[EXT_CSD_MIN_PERF_W_8_52]; + + card->ext_csd.s_cmd_set = ext_csd[EXT_CSD_S_CMD_SET]; + } + + mmc_deselect_cards(host); +} + static void mmc_read_scrs(struct mmc_host *host) { int err; @@ -973,8 +1069,20 @@ 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) ) { + unsigned int card_dtr = card->csd.max_dtr; + if (card->csd.mmca_vsn == 4 && mmc_card_highspeed(card)) { + /* card support it and highspeed mode is enabled */ + if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_26 ){ + card_dtr = 26000000; + } + if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_52 ){ + card_dtr = 52000000; + } + } + if (max_dtr > card_dtr) + max_dtr=card_dtr; + } DBG("MMC: selected %d.%03dMHz transfer rate\n", max_dtr / 1000000, (max_dtr / 1000) % 1000); @@ -1101,6 +1209,8 @@ if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); + else + mmc_read_ext_csds(host); } diff -aur kernel-source-2.6.16.old/drivers/mmc/mmc_block.c kernel-source-2.6.16/drivers/mmc/mmc_block.c --- kernel-source-2.6.16.old/drivers/mmc/mmc_block.c 2006-06-20 16:01:59.000000000 +0200 +++ kernel-source-2.6.16/drivers/mmc/mmc_block.c 2006-10-03 10:20:43.000000000 +0200 @@ -330,6 +330,7 @@ */ md->read_only = mmc_blk_readonly(card); +#if 0 /* * Figure out a workable block size. MMC cards have: * - two block sizes, one for read and one for write. @@ -367,7 +368,15 @@ md->read_only = 1; } } +#endif + md->block_bits = 9; /* hardcode block size to 512, cards >=2GB need this, others don't mind */ + printk(KERN_INFO "card reports rb%u wb%u rp%u wp%u, we set rb,wb to 512\n", + 1 << card->csd.read_blkbits, + 1 << card->csd.write_blkbits, + card->csd.read_partial, + card->csd.write_partial); +#if 0 /* * Refuse to allow block sizes smaller than 512 bytes. */ @@ -377,7 +386,7 @@ ret = -EINVAL; goto err_kfree; } - +#endif md->disk = alloc_disk(1 << MMC_SHIFT); if (md->disk == NULL) { ret = -ENOMEM; diff -aur kernel-source-2.6.16.old/drivers/mmc/omap.c kernel-source-2.6.16/drivers/mmc/omap.c --- kernel-source-2.6.16.old/drivers/mmc/omap.c 2006-06-20 16:01:59.000000000 +0200 +++ kernel-source-2.6.16/drivers/mmc/omap.c 2006-09-30 14:01:34.000000000 +0200 @@ -159,14 +159,14 @@ u32 cmdreg; u32 resptype; u32 cmdtype; - +#if 0 pr_debug("MMC%d: CMD%d, argument 0x%08x%s%s%s%s\n", host->id, cmd->opcode, cmd->arg, (cmd->flags & MMC_RSP_SHORT) ? ", 32-bit response" : "", (cmd->flags & MMC_RSP_LONG) ? ", 128-bit response" : "", (cmd->flags & MMC_RSP_CRC) ? ", CRC" : "", (cmd->flags & MMC_RSP_BUSY) ? ", busy notification" : ""); - +#endif host->cmd = cmd; resptype = 0; @@ -1152,7 +1152,8 @@ if (dsor > 250) dsor = 250; - dsor++; +// why? dsor++; + DBG("MMC%d: set_ios: requested %dHz, divisor %d -> real clock %dHz\n",host->id,realclock,dsor,(func_clk_rate / dsor)); if (ios->bus_width == MMC_BUS_WIDTH_4) dsor |= 1 << 15; @@ -1288,7 +1289,7 @@ mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; - mmc->f_max = 24000000; + mmc->f_max = 48000000; mmc->ocr_avail = MMC_VDD_33_34; /* Use scatterlist DMA to reduce per-transfer costs. diff -aur kernel-source-2.6.16.old/include/linux/mmc/card.h kernel-source-2.6.16/include/linux/mmc/card.h --- kernel-source-2.6.16.old/include/linux/mmc/card.h 2006-06-20 16:02:02.000000000 +0200 +++ kernel-source-2.6.16/include/linux/mmc/card.h 2006-10-02 17:44:09.000000000 +0200 @@ -38,6 +38,48 @@ write_misalign:1; }; +struct mmc_ext_csd { + unsigned char cmd_set_rev; + unsigned char ext_csd_rev; + unsigned char csd_structure; + + unsigned char card_type; + + /* + * Each power class defines MAX RMS Current + * and Max Peak Current in mA. + * Each category is of the form: + * pwr_cl__ + * + * Each category encodes the power class for 4 + * bit transfers in [3:0] and 8 bit transfers + * in [7:4]. Use mmc_get_4bit_pwr_cl() and + * mmc_get_8bit_pwr_cl() to decode these. + */ + unsigned char pwr_cl_52_195; + unsigned char pwr_cl_26_195; + + unsigned char pwr_cl_52_360; + unsigned char pwr_cl_26_360; + + /* + * Performance classes describe the minimum + * transfer speed the card claims to support + * for the given bus widths and speeds. + */ + unsigned char min_perf_r_4_26; + unsigned char min_perf_w_4_26; + unsigned char min_perf_r_8_26_4_52; + unsigned char min_perf_w_8_26_4_52; + unsigned char min_perf_r_8_52; + unsigned char min_perf_w_8_52; + + unsigned char s_cmd_set; +}; + +#define mmc_get_4bit_pwr_cl(p) (p & 0x0F) +#define mmc_get_8bit_pwr_cl(p) (p >> 4) + struct sd_scr { unsigned char sda_vsn; unsigned char bus_widths; @@ -61,11 +103,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 */ }; @@ -74,12 +118,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 -aur kernel-source-2.6.16.old/include/linux/mmc/protocol.h kernel-source-2.6.16/include/linux/mmc/protocol.h --- kernel-source-2.6.16.old/include/linux/mmc/protocol.h 2006-06-20 16:02:02.000000000 +0200 +++ kernel-source-2.6.16/include/linux/mmc/protocol.h 2006-10-02 17:48:32.000000000 +0200 @@ -33,6 +33,7 @@ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ #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 */ @@ -235,6 +236,99 @@ #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_4 4 /* Implements system specification 4.0 - 4.1 */ +/* + * EXT_CSD fields + */ +#define EXT_CSD_BUS_WIDTH 183 /* WO */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_CMD_SET_REV 189 /* RO */ +#define EXT_CSD_CMD_SET 191 /* R/W */ +#define EXT_CSD_EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_MIN_PERF_R_4_26 205 /* RO */ +#define EXT_CSD_MIN_PERF_W_4_26 206 /* RO */ +#define EXT_CSD_MIN_PERF_R_8_26_4_52 207 /* RO */ +#define EXT_CSD_MIN_PERF_W_8_26_4_52 208 /* RO */ +#define EXT_CSD_MIN_PERF_R_8_52 209 /* RO */ +#define EXT_CSD_MIN_PERF_W_8_52 210 /* RO */ +#define EXT_CSD_S_CMD_SET 504 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_BUS_WIDTH_1 0 +#define EXT_CSD_BUS_WIDTH_4 1 +#define EXT_CSD_BUS_WIDTH_8 2 + +#define EXT_CSD_HS_TIMING_LEGACY 0 /* <= 20MHz */ +#define EXT_CSD_HS_TIMING_FAST 1 /* > 20Mhz */ + +#define EXT_CSD_CMD_SET_REV_4 0 + +#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_EXT_CSD_REV_1_0 0 +#define EXT_CSD_EXT_CSD_REV_1_1 1 + +#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 */ + +/* + * Power classes + * + * Each class is of the form: + * __ + * + */ +#define EXT_CSD_PWR_CL_195_065_130 0 +#define EXT_CSD_PWR_CL_195_070_140 1 +#define EXT_CSD_PWR_CL_195_080_160 2 +#define EXT_CSD_PWR_CL_195_090_180 3 +#define EXT_CSD_PWR_CL_195_100_200 4 +#define EXT_CSD_PWR_CL_195_120_220 5 +#define EXT_CSD_PWR_CL_195_140_240 6 +#define EXT_CSD_PWR_CL_195_160_260 7 +#define EXT_CSD_PWR_CL_195_180_280 8 +#define EXT_CSD_PWR_CL_195_200_300 9 +#define EXT_CSD_PWR_CL_195_250_350 10 + +#define EXT_CSD_PWR_CL_360_100_200 0 +#define EXT_CSD_PWR_CL_360_120_220 1 +#define EXT_CSD_PWR_CL_360_150_250 2 +#define EXT_CSD_PWR_CL_360_180_280 3 +#define EXT_CSD_PWR_CL_360_200_300 4 +#define EXT_CSD_PWR_CL_360_220_320 5 +#define EXT_CSD_PWR_CL_360_250_350 6 +#define EXT_CSD_PWR_CL_360_300_400 7 +#define EXT_CSD_PWR_CL_360_350_450 8 +#define EXT_CSD_PWR_CL_360_400_500 9 +#define EXT_CSD_PWR_CL_360_450_550 10 + +#define EXT_CSD_MIN_PERF_CLASS_LEGACY 0x00 /* < 2.4 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_A 0x08 /* 2.4 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_B 0x0A /* 3 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_C 0x0F /* 4.5 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_D 0x14 /* 6 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_E 0x1E /* 9 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_F 0x28 /* 12 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_G 0x32 /* 15 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_H 0x3C /* 18 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_J 0x46 /* 21 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_K 0x50 /* 24 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_M 0x64 /* 30 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_O 0x78 /* 36 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_R 0x8C /* 42 MB/s */ +#define EXT_CSD_MIN_PERF_CLASS_T 0xA0 /* 48 MB/s */ /*