diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2006-11-08 17:03:10 -0500 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2006-12-01 12:53:37 -0500 |
commit | 7ccd266e676a3f0c6f8f897f58b684cac3dd1650 (patch) | |
tree | aba8632fc523c5c663a56876ce67c580ce8d38eb | |
parent | 73778120c4088a0a7b59c4c378904f7a230b4820 (diff) |
mmc: Support for high speed SD cards
Modern SD cards support a clock speed of 50 MHz. Make sure we test for
this capability and do the song and dance required to activate it.
Activating high speed support actually modifies the TRAN_SPEED field
of the CSD. But as the spec says that the cards must report 50 MHz,
we might as well skip re-reading the CSD.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r-- | drivers/mmc/mmc.c | 122 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 7 | ||||
-rw-r--r-- | include/linux/mmc/protocol.h | 22 |
3 files changed, 146 insertions, 5 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 82b7643c1654..9d190022a490 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c | |||
@@ -1157,6 +1157,116 @@ static void mmc_read_scrs(struct mmc_host *host) | |||
1157 | mmc_deselect_cards(host); | 1157 | mmc_deselect_cards(host); |
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | static void mmc_read_switch_caps(struct mmc_host *host) | ||
1161 | { | ||
1162 | int err; | ||
1163 | struct mmc_card *card; | ||
1164 | struct mmc_request mrq; | ||
1165 | struct mmc_command cmd; | ||
1166 | struct mmc_data data; | ||
1167 | unsigned char *status; | ||
1168 | struct scatterlist sg; | ||
1169 | |||
1170 | status = kmalloc(64, GFP_KERNEL); | ||
1171 | if (!status) { | ||
1172 | printk(KERN_WARNING "%s: Unable to allocate buffer for " | ||
1173 | "reading switch capabilities.\n", | ||
1174 | mmc_hostname(host)); | ||
1175 | return; | ||
1176 | } | ||
1177 | |||
1178 | list_for_each_entry(card, &host->cards, node) { | ||
1179 | if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) | ||
1180 | continue; | ||
1181 | if (!mmc_card_sd(card)) | ||
1182 | continue; | ||
1183 | if (card->scr.sda_vsn < SCR_SPEC_VER_1) | ||
1184 | continue; | ||
1185 | |||
1186 | err = mmc_select_card(host, card); | ||
1187 | if (err != MMC_ERR_NONE) { | ||
1188 | mmc_card_set_dead(card); | ||
1189 | continue; | ||
1190 | } | ||
1191 | |||
1192 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
1193 | |||
1194 | cmd.opcode = SD_SWITCH; | ||
1195 | cmd.arg = 0x00FFFFF1; | ||
1196 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1197 | |||
1198 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1199 | |||
1200 | mmc_set_data_timeout(&data, card, 0); | ||
1201 | |||
1202 | data.blksz = 64; | ||
1203 | data.blocks = 1; | ||
1204 | data.flags = MMC_DATA_READ; | ||
1205 | data.sg = &sg; | ||
1206 | data.sg_len = 1; | ||
1207 | |||
1208 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1209 | |||
1210 | mrq.cmd = &cmd; | ||
1211 | mrq.data = &data; | ||
1212 | |||
1213 | sg_init_one(&sg, status, 64); | ||
1214 | |||
1215 | mmc_wait_for_req(host, &mrq); | ||
1216 | |||
1217 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1218 | mmc_card_set_dead(card); | ||
1219 | continue; | ||
1220 | } | ||
1221 | |||
1222 | if (status[13] & 0x02) | ||
1223 | card->sw_caps.hs_max_dtr = 50000000; | ||
1224 | |||
1225 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
1226 | |||
1227 | cmd.opcode = SD_SWITCH; | ||
1228 | cmd.arg = 0x80FFFFF1; | ||
1229 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1230 | |||
1231 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1232 | |||
1233 | mmc_set_data_timeout(&data, card, 0); | ||
1234 | |||
1235 | data.blksz = 64; | ||
1236 | data.blocks = 1; | ||
1237 | data.flags = MMC_DATA_READ; | ||
1238 | data.sg = &sg; | ||
1239 | data.sg_len = 1; | ||
1240 | |||
1241 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1242 | |||
1243 | mrq.cmd = &cmd; | ||
1244 | mrq.data = &data; | ||
1245 | |||
1246 | sg_init_one(&sg, status, 64); | ||
1247 | |||
1248 | mmc_wait_for_req(host, &mrq); | ||
1249 | |||
1250 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1251 | mmc_card_set_dead(card); | ||
1252 | continue; | ||
1253 | } | ||
1254 | |||
1255 | if ((status[16] & 0xF) != 1) { | ||
1256 | printk(KERN_WARNING "%s: Problem switching card " | ||
1257 | "into high-speed mode!\n", | ||
1258 | mmc_hostname(host)); | ||
1259 | continue; | ||
1260 | } | ||
1261 | |||
1262 | mmc_card_set_highspeed(card); | ||
1263 | } | ||
1264 | |||
1265 | kfree(status); | ||
1266 | |||
1267 | mmc_deselect_cards(host); | ||
1268 | } | ||
1269 | |||
1160 | static unsigned int mmc_calculate_clock(struct mmc_host *host) | 1270 | static unsigned int mmc_calculate_clock(struct mmc_host *host) |
1161 | { | 1271 | { |
1162 | struct mmc_card *card; | 1272 | struct mmc_card *card; |
@@ -1164,9 +1274,12 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) | |||
1164 | 1274 | ||
1165 | list_for_each_entry(card, &host->cards, node) | 1275 | list_for_each_entry(card, &host->cards, node) |
1166 | if (!mmc_card_dead(card)) { | 1276 | if (!mmc_card_dead(card)) { |
1167 | if (mmc_card_highspeed(card)) { | 1277 | if (mmc_card_highspeed(card) && mmc_card_sd(card)) { |
1278 | if (max_dtr > card->sw_caps.hs_max_dtr) | ||
1279 | max_dtr = card->sw_caps.hs_max_dtr; | ||
1280 | } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { | ||
1168 | if (max_dtr > card->ext_csd.hs_max_dtr) | 1281 | if (max_dtr > card->ext_csd.hs_max_dtr) |
1169 | max_dtr = card->ext_csd.hs_max_dtr; | 1282 | max_dtr = card->ext_csd.hs_max_dtr; |
1170 | } else if (max_dtr > card->csd.max_dtr) { | 1283 | } else if (max_dtr > card->csd.max_dtr) { |
1171 | max_dtr = card->csd.max_dtr; | 1284 | max_dtr = card->csd.max_dtr; |
1172 | } | 1285 | } |
@@ -1288,9 +1401,10 @@ static void mmc_setup(struct mmc_host *host) | |||
1288 | 1401 | ||
1289 | mmc_read_csds(host); | 1402 | mmc_read_csds(host); |
1290 | 1403 | ||
1291 | if (host->mode == MMC_MODE_SD) | 1404 | if (host->mode == MMC_MODE_SD) { |
1292 | mmc_read_scrs(host); | 1405 | mmc_read_scrs(host); |
1293 | else | 1406 | mmc_read_switch_caps(host); |
1407 | } else | ||
1294 | mmc_process_ext_csds(host); | 1408 | mmc_process_ext_csds(host); |
1295 | } | 1409 | } |
1296 | 1410 | ||
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index ce25256f80d5..d0e6a5497614 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -50,6 +50,10 @@ struct sd_scr { | |||
50 | #define SD_SCR_BUS_WIDTH_4 (1<<2) | 50 | #define SD_SCR_BUS_WIDTH_4 (1<<2) |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct sd_switch_caps { | ||
54 | unsigned int hs_max_dtr; | ||
55 | }; | ||
56 | |||
53 | struct mmc_host; | 57 | struct mmc_host; |
54 | 58 | ||
55 | /* | 59 | /* |
@@ -66,7 +70,7 @@ struct mmc_card { | |||
66 | #define MMC_STATE_BAD (1<<2) /* unrecognised device */ | 70 | #define MMC_STATE_BAD (1<<2) /* unrecognised device */ |
67 | #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ | 71 | #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ |
68 | #define MMC_STATE_READONLY (1<<4) /* card is read-only */ | 72 | #define MMC_STATE_READONLY (1<<4) /* card is read-only */ |
69 | #define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ | 73 | #define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ |
70 | u32 raw_cid[4]; /* raw card CID */ | 74 | u32 raw_cid[4]; /* raw card CID */ |
71 | u32 raw_csd[4]; /* raw card CSD */ | 75 | u32 raw_csd[4]; /* raw card CSD */ |
72 | u32 raw_scr[2]; /* raw card SCR */ | 76 | u32 raw_scr[2]; /* raw card SCR */ |
@@ -74,6 +78,7 @@ struct mmc_card { | |||
74 | struct mmc_csd csd; /* card specific */ | 78 | struct mmc_csd csd; /* card specific */ |
75 | struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ | 79 | struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ |
76 | struct sd_scr scr; /* extra SD information */ | 80 | struct sd_scr scr; /* extra SD information */ |
81 | struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ | ||
77 | }; | 82 | }; |
78 | 83 | ||
79 | #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) | 84 | #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) |
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 45c51fd85786..2dce60c43f4b 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h | |||
@@ -82,6 +82,7 @@ | |||
82 | /* class 8 */ | 82 | /* class 8 */ |
83 | /* This is basically the same command as for MMC with some quirks. */ | 83 | /* This is basically the same command as for MMC with some quirks. */ |
84 | #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ | 84 | #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ |
85 | #define SD_SWITCH 6 /* adtc [31:0] See below R1 */ | ||
85 | 86 | ||
86 | /* Application commands */ | 87 | /* Application commands */ |
87 | #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ | 88 | #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ |
@@ -101,6 +102,19 @@ | |||
101 | */ | 102 | */ |
102 | 103 | ||
103 | /* | 104 | /* |
105 | * SD_SWITCH argument format: | ||
106 | * | ||
107 | * [31] Check (0) or switch (1) | ||
108 | * [30:24] Reserved (0) | ||
109 | * [23:20] Function group 6 | ||
110 | * [19:16] Function group 5 | ||
111 | * [15:12] Function group 4 | ||
112 | * [11:8] Function group 3 | ||
113 | * [7:4] Function group 2 | ||
114 | * [3:0] Function group 1 | ||
115 | */ | ||
116 | |||
117 | /* | ||
104 | MMC status in R1 | 118 | MMC status in R1 |
105 | Type | 119 | Type |
106 | e : error bit | 120 | e : error bit |
@@ -285,6 +299,14 @@ struct _mmc_csd { | |||
285 | #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ | 299 | #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ |
286 | 300 | ||
287 | /* | 301 | /* |
302 | * SCR field definitions | ||
303 | */ | ||
304 | |||
305 | #define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ | ||
306 | #define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ | ||
307 | #define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ | ||
308 | |||
309 | /* | ||
288 | * SD bus widths | 310 | * SD bus widths |
289 | */ | 311 | */ |
290 | #define SD_BUS_WIDTH_1 0 | 312 | #define SD_BUS_WIDTH_1 0 |