[zircon][sdmmc] Multi block I/O should be followed by stop transmission
As per the emmc spec, muti block read/write should be followed by stop
transmission. Some controllers have capibility to send the stop
transmission cmd automatically. This changeset adds a host capability
and sends the cmd if it is not automatically sent.
Change-Id: I80eb9ddd890c5ee92edff53c4ae569a043ca66ff
diff --git a/system/dev/block/sdhci/sdhci.c b/system/dev/block/sdhci/sdhci.c
index efc6880..9d4932e 100644
--- a/system/dev/block/sdhci/sdhci.c
+++ b/system/dev/block/sdhci/sdhci.c
@@ -1080,6 +1080,7 @@
if (caps0 & SDHCI_CORECFG_3P3_VOLT_SUPPORT) {
dev->info.caps |= SDMMC_HOST_CAP_VOLTAGE_330;
}
+ dev->info.caps |= SDMMC_HOST_CAP_AUTO_CMD12;
// initialize the controller
status = sdhci_controller_init(dev);
diff --git a/system/dev/block/sdmmc/sdmmc.c b/system/dev/block/sdmmc/sdmmc.c
index 2e51404..2739120 100644
--- a/system/dev/block/sdmmc/sdmmc.c
+++ b/system/dev/block/sdmmc/sdmmc.c
@@ -344,8 +344,16 @@
zxlogf(TRACE, "sdmmc: do_txn error %d\n", st);
block_complete(&txn->bop, st);
} else {
- zxlogf(TRACE, "sdmmc: do_txn complete\n");
+ if ((req->blockcount > 1) && !(dev->host_info.caps & SDMMC_HOST_CAP_AUTO_CMD12)) {
+ st = sdmmc_stop_transmission(dev);
+ if (st != ZX_OK) {
+ zxlogf(TRACE, "sdmmc: do_txn stop transmission error %d\n", st);
+ block_complete(&txn->bop, st);
+ return;
+ }
+ }
block_complete(&txn->bop, ZX_OK);
+ zxlogf(TRACE, "sdmmc: do_txn complete\n");
}
}
diff --git a/system/ulib/ddk/include/ddk/protocol/sdmmc.h b/system/ulib/ddk/include/ddk/protocol/sdmmc.h
index 24f2765..bb341f4 100644
--- a/system/ulib/ddk/include/ddk/protocol/sdmmc.h
+++ b/system/ulib/ddk/include/ddk/protocol/sdmmc.h
@@ -77,6 +77,7 @@
#define SDMMC_HOST_CAP_ADMA2 (1 << 1)
#define SDMMC_HOST_CAP_64BIT (1 << 2)
#define SDMMC_HOST_CAP_VOLTAGE_330 (1 << 3)
+#define SDMMC_HOST_CAP_AUTO_CMD12 (1 << 4)
// Maximum data request size
uint64_t max_transfer_size;
} sdmmc_host_info_t;