Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: core: implement enhanced strobe support

Controllers use data strobe line to latch data from devices
under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
introduces enhanced strobe mode for latching cmd response from
emmc devices to host controllers. This new feature is optional,
so it depends both on device's cap and host's cap to decide
whether to use it or not.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>

Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
Tested-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Shawn Lin and committed by
Ulf Hansson
81ac2af6 ef29c0e2

+108 -3
+2 -1
drivers/mmc/core/bus.c
··· 332 332 mmc_card_ddr52(card) ? "DDR " : "", 333 333 type); 334 334 } else { 335 - pr_info("%s: new %s%s%s%s%s card at address %04x\n", 335 + pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", 336 336 mmc_hostname(card->host), 337 337 mmc_card_uhs(card) ? "ultra high speed " : 338 338 (mmc_card_hs(card) ? "high speed " : ""), 339 339 mmc_card_hs400(card) ? "HS400 " : 340 340 (mmc_card_hs200(card) ? "HS200 " : ""), 341 + mmc_card_hs400es(card) ? "Enhanced strobe " : "", 341 342 mmc_card_ddr52(card) ? "DDR " : "", 342 343 uhs_bus_speed_mode, type, card->rca); 343 344 }
+9
drivers/mmc/core/core.c
··· 1127 1127 host->ios.bus_width = MMC_BUS_WIDTH_1; 1128 1128 host->ios.timing = MMC_TIMING_LEGACY; 1129 1129 host->ios.drv_type = 0; 1130 + host->ios.enhanced_strobe = false; 1131 + 1132 + /* 1133 + * Make sure we are in non-enhanced strobe mode before we 1134 + * actually enable it in ext_csd. 1135 + */ 1136 + if ((host->caps2 & MMC_CAP2_HS400_ES) && 1137 + host->ops->hs400_enhanced_strobe) 1138 + host->ops->hs400_enhanced_strobe(host, &host->ios); 1130 1139 1131 1140 mmc_set_ios(host); 1132 1141 }
+82 -2
drivers/mmc/core/mmc.c
··· 235 235 avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V; 236 236 } 237 237 238 + if ((caps2 & MMC_CAP2_HS400_ES) && 239 + card->ext_csd.strobe_support && 240 + (avail_type & EXT_CSD_CARD_TYPE_HS400)) 241 + avail_type |= EXT_CSD_CARD_TYPE_HS400ES; 242 + 238 243 card->ext_csd.hs_max_dtr = hs_max_dtr; 239 244 card->ext_csd.hs200_max_dtr = hs200_max_dtr; 240 245 card->mmc_avail_type = avail_type; ··· 391 386 mmc_card_set_blockaddr(card); 392 387 } 393 388 389 + card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT]; 394 390 card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; 395 391 mmc_select_card_type(card); 396 392 ··· 1229 1223 return err; 1230 1224 } 1231 1225 1226 + static int mmc_select_hs400es(struct mmc_card *card) 1227 + { 1228 + struct mmc_host *host = card->host; 1229 + int err = 0; 1230 + u8 val; 1231 + 1232 + if (!(host->caps & MMC_CAP_8_BIT_DATA)) { 1233 + err = -ENOTSUPP; 1234 + goto out_err; 1235 + } 1236 + 1237 + err = mmc_select_bus_width(card); 1238 + if (err < 0) 1239 + goto out_err; 1240 + 1241 + /* Switch card to HS mode */ 1242 + err = mmc_select_hs(card); 1243 + if (err) { 1244 + pr_err("%s: switch to high-speed failed, err:%d\n", 1245 + mmc_hostname(host), err); 1246 + goto out_err; 1247 + } 1248 + 1249 + err = mmc_switch_status(card); 1250 + if (err) 1251 + goto out_err; 1252 + 1253 + /* Switch card to DDR with strobe bit */ 1254 + val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE; 1255 + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1256 + EXT_CSD_BUS_WIDTH, 1257 + val, 1258 + card->ext_csd.generic_cmd6_time); 1259 + if (err) { 1260 + pr_err("%s: switch to bus width for hs400es failed, err:%d\n", 1261 + mmc_hostname(host), err); 1262 + goto out_err; 1263 + } 1264 + 1265 + /* Switch card to HS400 */ 1266 + val = EXT_CSD_TIMING_HS400 | 1267 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1268 + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1269 + EXT_CSD_HS_TIMING, val, 1270 + card->ext_csd.generic_cmd6_time, 1271 + true, false, true); 1272 + if (err) { 1273 + pr_err("%s: switch to hs400es failed, err:%d\n", 1274 + mmc_hostname(host), err); 1275 + goto out_err; 1276 + } 1277 + 1278 + /* Set host controller to HS400 timing and frequency */ 1279 + mmc_set_timing(host, MMC_TIMING_MMC_HS400); 1280 + 1281 + /* Controller enable enhanced strobe function */ 1282 + host->ios.enhanced_strobe = true; 1283 + if (host->ops->hs400_enhanced_strobe) 1284 + host->ops->hs400_enhanced_strobe(host, &host->ios); 1285 + 1286 + err = mmc_switch_status(card); 1287 + if (err) 1288 + goto out_err; 1289 + 1290 + return 0; 1291 + 1292 + out_err: 1293 + pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), 1294 + __func__, err); 1295 + return err; 1296 + } 1297 + 1232 1298 static void mmc_select_driver_type(struct mmc_card *card) 1233 1299 { 1234 1300 int card_drv_type, drive_strength, drv_type; ··· 1388 1310 } 1389 1311 1390 1312 /* 1391 - * Activate High Speed or HS200 mode if supported. 1313 + * Activate High Speed, HS200 or HS400ES mode if supported. 1392 1314 */ 1393 1315 static int mmc_select_timing(struct mmc_card *card) 1394 1316 { ··· 1397 1319 if (!mmc_can_ext_csd(card)) 1398 1320 goto bus_speed; 1399 1321 1400 - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) 1322 + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) 1323 + err = mmc_select_hs400es(card); 1324 + else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) 1401 1325 err = mmc_select_hs200(card); 1402 1326 else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) 1403 1327 err = mmc_select_hs(card);
+1
include/linux/mmc/card.h
··· 95 95 u8 raw_partition_support; /* 160 */ 96 96 u8 raw_rpmb_size_mult; /* 168 */ 97 97 u8 raw_erased_mem_count; /* 181 */ 98 + u8 strobe_support; /* 184 */ 98 99 u8 raw_ext_csd_structure; /* 194 */ 99 100 u8 raw_card_type; /* 196 */ 100 101 u8 raw_driver_strength; /* 197 */
+11
include/linux/mmc/host.h
··· 19 19 20 20 #include <linux/mmc/core.h> 21 21 #include <linux/mmc/card.h> 22 + #include <linux/mmc/mmc.h> 22 23 #include <linux/mmc/pm.h> 23 24 24 25 struct mmc_ios { ··· 78 77 #define MMC_SET_DRIVER_TYPE_A 1 79 78 #define MMC_SET_DRIVER_TYPE_C 2 80 79 #define MMC_SET_DRIVER_TYPE_D 3 80 + 81 + bool enhanced_strobe; /* hs400es selection */ 81 82 }; 82 83 83 84 struct mmc_host_ops { ··· 146 143 147 144 /* Prepare HS400 target operating frequency depending host driver */ 148 145 int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios); 146 + /* Prepare enhanced strobe depending host driver */ 147 + void (*hs400_enhanced_strobe)(struct mmc_host *host, 148 + struct mmc_ios *ios); 149 149 int (*select_drive_strength)(struct mmc_card *card, 150 150 unsigned int max_dtr, int host_drv, 151 151 int card_drv, int *drv_type); ··· 518 512 static inline bool mmc_card_hs400(struct mmc_card *card) 519 513 { 520 514 return card->host->ios.timing == MMC_TIMING_MMC_HS400; 515 + } 516 + 517 + static inline bool mmc_card_hs400es(struct mmc_card *card) 518 + { 519 + return card->host->ios.enhanced_strobe; 521 520 } 522 521 523 522 void mmc_retune_timer_stop(struct mmc_host *host);
+3
include/linux/mmc/mmc.h
··· 297 297 #define EXT_CSD_PART_CONFIG 179 /* R/W */ 298 298 #define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ 299 299 #define EXT_CSD_BUS_WIDTH 183 /* R/W */ 300 + #define EXT_CSD_STROBE_SUPPORT 184 /* RO */ 300 301 #define EXT_CSD_HS_TIMING 185 /* R/W */ 301 302 #define EXT_CSD_POWER_CLASS 187 /* R/W */ 302 303 #define EXT_CSD_REV 192 /* RO */ ··· 381 380 #define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */ 382 381 #define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \ 383 382 EXT_CSD_CARD_TYPE_HS400_1_2V) 383 + #define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */ 384 384 385 385 #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ 386 386 #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ 387 387 #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ 388 388 #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ 389 389 #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ 390 + #define EXT_CSD_BUS_WIDTH_STROBE BIT(7) /* Enhanced strobe mode */ 390 391 391 392 #define EXT_CSD_TIMING_BC 0 /* Backwards compatility */ 392 393 #define EXT_CSD_TIMING_HS 1 /* High speed */