diff options
Diffstat (limited to 'drivers/mmc/mmc.c')
-rw-r--r-- | drivers/mmc/mmc.c | 121 |
1 files changed, 119 insertions, 2 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc54406e5..2d5b93000dee 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 2003-2004 Russell King, All Rights Reserved. | 4 | * Copyright (C) 2003-2004 Russell King, All Rights Reserved. |
5 | * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. | 5 | * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. |
6 | * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. | 6 | * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. |
7 | * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -953,6 +954,114 @@ static void mmc_read_csds(struct mmc_host *host) | |||
953 | } | 954 | } |
954 | } | 955 | } |
955 | 956 | ||
957 | static void mmc_process_ext_csds(struct mmc_host *host) | ||
958 | { | ||
959 | int err; | ||
960 | struct mmc_card *card; | ||
961 | |||
962 | struct mmc_request mrq; | ||
963 | struct mmc_command cmd; | ||
964 | struct mmc_data data; | ||
965 | |||
966 | struct scatterlist sg; | ||
967 | |||
968 | /* | ||
969 | * As the ext_csd is so large and mostly unused, we don't store the | ||
970 | * raw block in mmc_card. | ||
971 | */ | ||
972 | u8 *ext_csd; | ||
973 | ext_csd = kmalloc(512, GFP_KERNEL); | ||
974 | if (!ext_csd) { | ||
975 | printk("%s: could not allocate a buffer to receive the ext_csd." | ||
976 | "mmc v4 cards will be treated as v3.\n", | ||
977 | mmc_hostname(host)); | ||
978 | return; | ||
979 | } | ||
980 | |||
981 | list_for_each_entry(card, &host->cards, node) { | ||
982 | if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) | ||
983 | continue; | ||
984 | if (mmc_card_sd(card)) | ||
985 | continue; | ||
986 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) | ||
987 | continue; | ||
988 | |||
989 | err = mmc_select_card(host, card); | ||
990 | if (err != MMC_ERR_NONE) { | ||
991 | mmc_card_set_dead(card); | ||
992 | continue; | ||
993 | } | ||
994 | |||
995 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
996 | |||
997 | cmd.opcode = MMC_SEND_EXT_CSD; | ||
998 | cmd.arg = 0; | ||
999 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1000 | |||
1001 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1002 | |||
1003 | mmc_set_data_timeout(&data, card, 0); | ||
1004 | |||
1005 | data.blksz = 512; | ||
1006 | data.blocks = 1; | ||
1007 | data.flags = MMC_DATA_READ; | ||
1008 | data.sg = &sg; | ||
1009 | data.sg_len = 1; | ||
1010 | |||
1011 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1012 | |||
1013 | mrq.cmd = &cmd; | ||
1014 | mrq.data = &data; | ||
1015 | |||
1016 | sg_init_one(&sg, ext_csd, 512); | ||
1017 | |||
1018 | mmc_wait_for_req(host, &mrq); | ||
1019 | |||
1020 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1021 | mmc_card_set_dead(card); | ||
1022 | continue; | ||
1023 | } | ||
1024 | |||
1025 | switch (ext_csd[EXT_CSD_CARD_TYPE]) { | ||
1026 | case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: | ||
1027 | card->ext_csd.hs_max_dtr = 52000000; | ||
1028 | break; | ||
1029 | case EXT_CSD_CARD_TYPE_26: | ||
1030 | card->ext_csd.hs_max_dtr = 26000000; | ||
1031 | break; | ||
1032 | default: | ||
1033 | /* MMC v4 spec says this cannot happen */ | ||
1034 | printk("%s: card is mmc v4 but doesn't support " | ||
1035 | "any high-speed modes.\n", | ||
1036 | mmc_hostname(card->host)); | ||
1037 | mmc_card_set_bad(card); | ||
1038 | continue; | ||
1039 | } | ||
1040 | |||
1041 | /* Activate highspeed support. */ | ||
1042 | cmd.opcode = MMC_SWITCH; | ||
1043 | cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | ||
1044 | (EXT_CSD_HS_TIMING << 16) | | ||
1045 | (1 << 8) | | ||
1046 | EXT_CSD_CMD_SET_NORMAL; | ||
1047 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | ||
1048 | |||
1049 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
1050 | if (err != MMC_ERR_NONE) { | ||
1051 | printk("%s: failed to switch card to mmc v4 " | ||
1052 | "high-speed mode.\n", | ||
1053 | mmc_hostname(card->host)); | ||
1054 | continue; | ||
1055 | } | ||
1056 | |||
1057 | mmc_card_set_highspeed(card); | ||
1058 | } | ||
1059 | |||
1060 | kfree(ext_csd); | ||
1061 | |||
1062 | mmc_deselect_cards(host); | ||
1063 | } | ||
1064 | |||
956 | static void mmc_read_scrs(struct mmc_host *host) | 1065 | static void mmc_read_scrs(struct mmc_host *host) |
957 | { | 1066 | { |
958 | int err; | 1067 | int err; |
@@ -1031,8 +1140,14 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) | |||
1031 | unsigned int max_dtr = host->f_max; | 1140 | unsigned int max_dtr = host->f_max; |
1032 | 1141 | ||
1033 | list_for_each_entry(card, &host->cards, node) | 1142 | list_for_each_entry(card, &host->cards, node) |
1034 | if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) | 1143 | if (!mmc_card_dead(card)) { |
1035 | max_dtr = card->csd.max_dtr; | 1144 | if (mmc_card_highspeed(card)) { |
1145 | if (max_dtr > card->ext_csd.hs_max_dtr) | ||
1146 | max_dtr = card->ext_csd.hs_max_dtr; | ||
1147 | } else if (max_dtr > card->csd.max_dtr) { | ||
1148 | max_dtr = card->csd.max_dtr; | ||
1149 | } | ||
1150 | } | ||
1036 | 1151 | ||
1037 | pr_debug("%s: selected %d.%03dMHz transfer rate\n", | 1152 | pr_debug("%s: selected %d.%03dMHz transfer rate\n", |
1038 | mmc_hostname(host), | 1153 | mmc_hostname(host), |
@@ -1152,6 +1267,8 @@ static void mmc_setup(struct mmc_host *host) | |||
1152 | 1267 | ||
1153 | if (host->mode == MMC_MODE_SD) | 1268 | if (host->mode == MMC_MODE_SD) |
1154 | mmc_read_scrs(host); | 1269 | mmc_read_scrs(host); |
1270 | else | ||
1271 | mmc_process_ext_csds(host); | ||
1155 | } | 1272 | } |
1156 | 1273 | ||
1157 | 1274 | ||