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

mmc: mmc: Add driver strength selection

Add the ability to set eMMC driver strength
for HS200 and HS400.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Adrian Hunter and committed by
Ulf Hansson
cc4f414c b097e07f

+41 -7
+38 -7
drivers/mmc/core/mmc.c
··· 1044 1044 { 1045 1045 struct mmc_host *host = card->host; 1046 1046 int err = 0; 1047 + u8 val; 1047 1048 1048 1049 /* 1049 1050 * HS400 mode requires 8-bit bus width ··· 1060 1059 mmc_set_timing(card->host, MMC_TIMING_MMC_HS); 1061 1060 mmc_set_bus_speed(card); 1062 1061 1062 + val = EXT_CSD_TIMING_HS | 1063 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1063 1064 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1064 - EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, 1065 + EXT_CSD_HS_TIMING, val, 1065 1066 card->ext_csd.generic_cmd6_time, 1066 1067 true, true, true); 1067 1068 if (err) { ··· 1082 1079 return err; 1083 1080 } 1084 1081 1082 + val = EXT_CSD_TIMING_HS400 | 1083 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1085 1084 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1086 - EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, 1085 + EXT_CSD_HS_TIMING, val, 1087 1086 card->ext_csd.generic_cmd6_time, 1088 1087 true, true, true); 1089 1088 if (err) { ··· 1124 1119 bool send_status = true; 1125 1120 unsigned int max_dtr; 1126 1121 int err; 1122 + u8 val; 1127 1123 1128 1124 if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) 1129 1125 send_status = false; ··· 1134 1128 mmc_set_clock(host, max_dtr); 1135 1129 1136 1130 /* Switch HS400 to HS DDR */ 1131 + val = EXT_CSD_TIMING_HS | 1132 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1137 1133 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1138 - EXT_CSD_TIMING_HS, card->ext_csd.generic_cmd6_time, 1134 + val, card->ext_csd.generic_cmd6_time, 1139 1135 true, send_status, true); 1140 1136 if (err) 1141 1137 goto out_err; ··· 1166 1158 } 1167 1159 1168 1160 /* Switch HS to HS200 */ 1161 + val = EXT_CSD_TIMING_HS200 | 1162 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1169 1163 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1170 - EXT_CSD_TIMING_HS200, 1171 - card->ext_csd.generic_cmd6_time, true, send_status, 1172 - true); 1164 + val, card->ext_csd.generic_cmd6_time, true, 1165 + send_status, true); 1173 1166 if (err) 1174 1167 goto out_err; 1175 1168 ··· 1192 1183 return err; 1193 1184 } 1194 1185 1186 + static void mmc_select_driver_type(struct mmc_card *card) 1187 + { 1188 + int card_drv_type, drive_strength, drv_type; 1189 + 1190 + card_drv_type = card->ext_csd.raw_driver_strength | 1191 + mmc_driver_type_mask(0); 1192 + 1193 + drive_strength = mmc_select_drive_strength(card, 1194 + card->ext_csd.hs200_max_dtr, 1195 + card_drv_type, &drv_type); 1196 + 1197 + card->drive_strength = drive_strength; 1198 + 1199 + if (drv_type) 1200 + mmc_set_driver_type(card->host, drv_type); 1201 + } 1202 + 1195 1203 /* 1196 1204 * For device supporting HS200 mode, the following sequence 1197 1205 * should be done before executing the tuning process. ··· 1220 1194 { 1221 1195 struct mmc_host *host = card->host; 1222 1196 int err = -EINVAL; 1197 + u8 val; 1223 1198 1224 1199 if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V) 1225 1200 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); ··· 1232 1205 if (err) 1233 1206 goto err; 1234 1207 1208 + mmc_select_driver_type(card); 1209 + 1235 1210 /* 1236 1211 * Set the bus width(4 or 8) with host's support and 1237 1212 * switch to HS200 mode if bus width is set successfully. 1238 1213 */ 1239 1214 err = mmc_select_bus_width(card); 1240 1215 if (!IS_ERR_VALUE(err)) { 1216 + val = EXT_CSD_TIMING_HS200 | 1217 + card->drive_strength << EXT_CSD_DRV_STR_SHIFT; 1241 1218 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1242 - EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200, 1219 + EXT_CSD_HS_TIMING, val, 1243 1220 card->ext_csd.generic_cmd6_time, 1244 1221 true, true, true); 1245 1222 if (!err)
+3
include/linux/mmc/mmc.h
··· 391 391 #define EXT_CSD_TIMING_HS 1 /* High speed */ 392 392 #define EXT_CSD_TIMING_HS200 2 /* HS200 */ 393 393 #define EXT_CSD_TIMING_HS400 3 /* HS400 */ 394 + #define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */ 394 395 395 396 #define EXT_CSD_SEC_ER_EN BIT(0) 396 397 #define EXT_CSD_SEC_BD_BLK_EN BIT(2) ··· 442 441 #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ 443 442 #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ 444 443 #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ 444 + 445 + #define mmc_driver_type_mask(n) (1 << (n)) 445 446 446 447 #endif /* LINUX_MMC_MMC_H */