diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-13 13:59:02 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-13 13:59:02 -0500 |
| commit | e861e11c5900d21afe0c3a326d1303d6f92c9f6f (patch) | |
| tree | 4fd8033b6e115389041c0512c818fa34dd0128ac | |
| parent | 52a7dc28a7b01cdd9ec349a943944dc49d20fc26 (diff) | |
| parent | b704441e38f645dcfba1348ca3cc1ba43d1a9f31 (diff) | |
Merge tag 'mmc-v4.20-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull mmc fixes from Ulf Hansson:
"MMC core:
- Fixup RPMB requests to use mrq->sbc when sending CMD23
MMC host:
- omap: Fix broken MMC/SD on OMAP15XX/OMAP5910/OMAP310
- sdhci-omap: Fix DCRC error handling during tuning
- sdhci: Fixup the timeout check window for clock and reset"
* tag 'mmc-v4.20-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
mmc: sdhci: fix the timeout check window for clock and reset
mmc: sdhci-omap: Fix DCRC error handling during tuning
MMC: OMAP: fix broken MMC on OMAP15XX/OMAP5910/OMAP310
mmc: core: use mrq->sbc when sending CMD23 for RPMB
| -rw-r--r-- | drivers/mmc/core/block.c | 15 | ||||
| -rw-r--r-- | drivers/mmc/host/omap.c | 11 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-omap.c | 12 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 18 |
4 files changed, 40 insertions, 16 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index c35b5b08bb33..111934838da2 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c | |||
| @@ -472,7 +472,7 @@ out: | |||
| 472 | static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, | 472 | static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, |
| 473 | struct mmc_blk_ioc_data *idata) | 473 | struct mmc_blk_ioc_data *idata) |
| 474 | { | 474 | { |
| 475 | struct mmc_command cmd = {}; | 475 | struct mmc_command cmd = {}, sbc = {}; |
| 476 | struct mmc_data data = {}; | 476 | struct mmc_data data = {}; |
| 477 | struct mmc_request mrq = {}; | 477 | struct mmc_request mrq = {}; |
| 478 | struct scatterlist sg; | 478 | struct scatterlist sg; |
| @@ -550,10 +550,15 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, | |||
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | if (idata->rpmb) { | 552 | if (idata->rpmb) { |
| 553 | err = mmc_set_blockcount(card, data.blocks, | 553 | sbc.opcode = MMC_SET_BLOCK_COUNT; |
| 554 | idata->ic.write_flag & (1 << 31)); | 554 | /* |
| 555 | if (err) | 555 | * We don't do any blockcount validation because the max size |
| 556 | return err; | 556 | * may be increased by a future standard. We just copy the |
| 557 | * 'Reliable Write' bit here. | ||
| 558 | */ | ||
| 559 | sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31)); | ||
| 560 | sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
| 561 | mrq.sbc = &sbc; | ||
| 557 | } | 562 | } |
| 558 | 563 | ||
| 559 | if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) && | 564 | if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) && |
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index adf32682f27a..c60a7625b1fa 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
| @@ -104,6 +104,7 @@ struct mmc_omap_slot { | |||
| 104 | unsigned int vdd; | 104 | unsigned int vdd; |
| 105 | u16 saved_con; | 105 | u16 saved_con; |
| 106 | u16 bus_mode; | 106 | u16 bus_mode; |
| 107 | u16 power_mode; | ||
| 107 | unsigned int fclk_freq; | 108 | unsigned int fclk_freq; |
| 108 | 109 | ||
| 109 | struct tasklet_struct cover_tasklet; | 110 | struct tasklet_struct cover_tasklet; |
| @@ -1157,7 +1158,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1157 | struct mmc_omap_slot *slot = mmc_priv(mmc); | 1158 | struct mmc_omap_slot *slot = mmc_priv(mmc); |
| 1158 | struct mmc_omap_host *host = slot->host; | 1159 | struct mmc_omap_host *host = slot->host; |
| 1159 | int i, dsor; | 1160 | int i, dsor; |
| 1160 | int clk_enabled; | 1161 | int clk_enabled, init_stream; |
| 1161 | 1162 | ||
| 1162 | mmc_omap_select_slot(slot, 0); | 1163 | mmc_omap_select_slot(slot, 0); |
| 1163 | 1164 | ||
| @@ -1167,6 +1168,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1167 | slot->vdd = ios->vdd; | 1168 | slot->vdd = ios->vdd; |
| 1168 | 1169 | ||
| 1169 | clk_enabled = 0; | 1170 | clk_enabled = 0; |
| 1171 | init_stream = 0; | ||
| 1170 | switch (ios->power_mode) { | 1172 | switch (ios->power_mode) { |
| 1171 | case MMC_POWER_OFF: | 1173 | case MMC_POWER_OFF: |
| 1172 | mmc_omap_set_power(slot, 0, ios->vdd); | 1174 | mmc_omap_set_power(slot, 0, ios->vdd); |
| @@ -1174,13 +1176,17 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1174 | case MMC_POWER_UP: | 1176 | case MMC_POWER_UP: |
| 1175 | /* Cannot touch dsor yet, just power up MMC */ | 1177 | /* Cannot touch dsor yet, just power up MMC */ |
| 1176 | mmc_omap_set_power(slot, 1, ios->vdd); | 1178 | mmc_omap_set_power(slot, 1, ios->vdd); |
| 1179 | slot->power_mode = ios->power_mode; | ||
| 1177 | goto exit; | 1180 | goto exit; |
| 1178 | case MMC_POWER_ON: | 1181 | case MMC_POWER_ON: |
| 1179 | mmc_omap_fclk_enable(host, 1); | 1182 | mmc_omap_fclk_enable(host, 1); |
| 1180 | clk_enabled = 1; | 1183 | clk_enabled = 1; |
| 1181 | dsor |= 1 << 11; | 1184 | dsor |= 1 << 11; |
| 1185 | if (slot->power_mode != MMC_POWER_ON) | ||
| 1186 | init_stream = 1; | ||
| 1182 | break; | 1187 | break; |
| 1183 | } | 1188 | } |
| 1189 | slot->power_mode = ios->power_mode; | ||
| 1184 | 1190 | ||
| 1185 | if (slot->bus_mode != ios->bus_mode) { | 1191 | if (slot->bus_mode != ios->bus_mode) { |
| 1186 | if (slot->pdata->set_bus_mode != NULL) | 1192 | if (slot->pdata->set_bus_mode != NULL) |
| @@ -1196,7 +1202,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1196 | for (i = 0; i < 2; i++) | 1202 | for (i = 0; i < 2; i++) |
| 1197 | OMAP_MMC_WRITE(host, CON, dsor); | 1203 | OMAP_MMC_WRITE(host, CON, dsor); |
| 1198 | slot->saved_con = dsor; | 1204 | slot->saved_con = dsor; |
| 1199 | if (ios->power_mode == MMC_POWER_ON) { | 1205 | if (init_stream) { |
| 1200 | /* worst case at 400kHz, 80 cycles makes 200 microsecs */ | 1206 | /* worst case at 400kHz, 80 cycles makes 200 microsecs */ |
| 1201 | int usecs = 250; | 1207 | int usecs = 250; |
| 1202 | 1208 | ||
| @@ -1234,6 +1240,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) | |||
| 1234 | slot->host = host; | 1240 | slot->host = host; |
| 1235 | slot->mmc = mmc; | 1241 | slot->mmc = mmc; |
| 1236 | slot->id = id; | 1242 | slot->id = id; |
| 1243 | slot->power_mode = MMC_POWER_UNDEFINED; | ||
| 1237 | slot->pdata = &host->pdata->slots[id]; | 1244 | slot->pdata = &host->pdata->slots[id]; |
| 1238 | 1245 | ||
| 1239 | host->slots[id] = slot; | 1246 | host->slots[id] = slot; |
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 88347ce78f23..d264391616f9 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c | |||
| @@ -288,9 +288,9 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) | |||
| 288 | struct device *dev = omap_host->dev; | 288 | struct device *dev = omap_host->dev; |
| 289 | struct mmc_ios *ios = &mmc->ios; | 289 | struct mmc_ios *ios = &mmc->ios; |
| 290 | u32 start_window = 0, max_window = 0; | 290 | u32 start_window = 0, max_window = 0; |
| 291 | bool dcrc_was_enabled = false; | ||
| 291 | u8 cur_match, prev_match = 0; | 292 | u8 cur_match, prev_match = 0; |
| 292 | u32 length = 0, max_len = 0; | 293 | u32 length = 0, max_len = 0; |
| 293 | u32 ier = host->ier; | ||
| 294 | u32 phase_delay = 0; | 294 | u32 phase_delay = 0; |
| 295 | int ret = 0; | 295 | int ret = 0; |
| 296 | u32 reg; | 296 | u32 reg; |
| @@ -317,9 +317,10 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) | |||
| 317 | * during the tuning procedure. So disable it during the | 317 | * during the tuning procedure. So disable it during the |
| 318 | * tuning procedure. | 318 | * tuning procedure. |
| 319 | */ | 319 | */ |
| 320 | ier &= ~SDHCI_INT_DATA_CRC; | 320 | if (host->ier & SDHCI_INT_DATA_CRC) { |
| 321 | sdhci_writel(host, ier, SDHCI_INT_ENABLE); | 321 | host->ier &= ~SDHCI_INT_DATA_CRC; |
| 322 | sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); | 322 | dcrc_was_enabled = true; |
| 323 | } | ||
| 323 | 324 | ||
| 324 | while (phase_delay <= MAX_PHASE_DELAY) { | 325 | while (phase_delay <= MAX_PHASE_DELAY) { |
| 325 | sdhci_omap_set_dll(omap_host, phase_delay); | 326 | sdhci_omap_set_dll(omap_host, phase_delay); |
| @@ -366,6 +367,9 @@ tuning_error: | |||
| 366 | 367 | ||
| 367 | ret: | 368 | ret: |
| 368 | sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); | 369 | sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); |
| 370 | /* Reenable forbidden interrupt */ | ||
| 371 | if (dcrc_was_enabled) | ||
| 372 | host->ier |= SDHCI_INT_DATA_CRC; | ||
| 369 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); | 373 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
| 370 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); | 374 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
| 371 | return ret; | 375 | return ret; |
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 99bdae53fa2e..451b08a818a9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -216,8 +216,12 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) | |||
| 216 | timeout = ktime_add_ms(ktime_get(), 100); | 216 | timeout = ktime_add_ms(ktime_get(), 100); |
| 217 | 217 | ||
| 218 | /* hw clears the bit when it's done */ | 218 | /* hw clears the bit when it's done */ |
| 219 | while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { | 219 | while (1) { |
| 220 | if (ktime_after(ktime_get(), timeout)) { | 220 | bool timedout = ktime_after(ktime_get(), timeout); |
| 221 | |||
| 222 | if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)) | ||
| 223 | break; | ||
| 224 | if (timedout) { | ||
| 221 | pr_err("%s: Reset 0x%x never completed.\n", | 225 | pr_err("%s: Reset 0x%x never completed.\n", |
| 222 | mmc_hostname(host->mmc), (int)mask); | 226 | mmc_hostname(host->mmc), (int)mask); |
| 223 | sdhci_dumpregs(host); | 227 | sdhci_dumpregs(host); |
| @@ -1608,9 +1612,13 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk) | |||
| 1608 | 1612 | ||
| 1609 | /* Wait max 20 ms */ | 1613 | /* Wait max 20 ms */ |
| 1610 | timeout = ktime_add_ms(ktime_get(), 20); | 1614 | timeout = ktime_add_ms(ktime_get(), 20); |
| 1611 | while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) | 1615 | while (1) { |
| 1612 | & SDHCI_CLOCK_INT_STABLE)) { | 1616 | bool timedout = ktime_after(ktime_get(), timeout); |
| 1613 | if (ktime_after(ktime_get(), timeout)) { | 1617 | |
| 1618 | clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); | ||
| 1619 | if (clk & SDHCI_CLOCK_INT_STABLE) | ||
| 1620 | break; | ||
| 1621 | if (timedout) { | ||
| 1614 | pr_err("%s: Internal clock never stabilised.\n", | 1622 | pr_err("%s: Internal clock never stabilised.\n", |
| 1615 | mmc_hostname(host->mmc)); | 1623 | mmc_hostname(host->mmc)); |
| 1616 | sdhci_dumpregs(host); | 1624 | sdhci_dumpregs(host); |
